Blender V4.3
text_ops.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <algorithm>
10#include <cerrno>
11#include <cstring>
12#include <sstream>
13
14#include "MEM_guardedalloc.h"
15
16#include "DNA_text_types.h"
17
18#include "BLI_blenlib.h"
19#include "BLI_math_base.h"
20#include "BLI_math_vector.h"
22#include "BLI_string_utf8.h"
23#include "BLI_time.h"
24
25#include "BLT_translation.hh"
26
27#include "BKE_context.hh"
28#include "BKE_lib_id.hh"
29#include "BKE_main.hh"
30#include "BKE_report.hh"
31#include "BKE_text.h"
32
33#include "WM_api.hh"
34#include "WM_types.hh"
35
36#include "ED_curve.hh"
37#include "ED_screen.hh"
38#include "ED_text.hh"
39#include "UI_interface.hh"
40#include "UI_resources.hh"
41
42#include "RNA_access.hh"
43#include "RNA_define.hh"
44
45#ifdef WITH_PYTHON
46# include "BPY_extern.hh"
47# include "BPY_extern_run.hh"
48#endif
49
50#include "text_format.hh"
51#include "text_intern.hh"
52
53static void space_text_screen_clamp(SpaceText *st, const ARegion *region);
54
55/* -------------------------------------------------------------------- */
66static void test_line_start(char c, bool *r_last_state)
67{
68 if (c == '\n') {
69 *r_last_state = true;
70 }
71 else if (!ELEM(c, '\t', ' ')) {
72 *r_last_state = false;
73 }
74}
75
81static char text_closing_character_pair_get(const char character)
82{
83
84 switch (character) {
85 case '(':
86 return ')';
87 case '[':
88 return ']';
89 case '{':
90 return '}';
91 case '"':
92 return '"';
93 case '\'':
94 return '\'';
95 default:
96 return 0;
97 }
98}
99
108static bool text_span_is_blank(TextLine *line1,
109 const int line1_char,
110 TextLine *line2,
111 const int line2_char)
112{
113 const TextLine *start_line;
114 const TextLine *end_line;
115 int start_char;
116 int end_char;
117
118 /* Get the start and end lines. */
119 if (txt_get_span(line1, line2) > 0 || (line1 == line2 && line1_char <= line2_char)) {
120 start_line = line1;
121 end_line = line2;
122 start_char = line1_char;
123 end_char = line2_char;
124 }
125 else {
126 start_line = line2;
127 end_line = line1;
128 start_char = line2_char;
129 end_char = line1_char;
130 }
131
132 for (const TextLine *line = start_line; line != end_line->next; line = line->next) {
133 const int start = (line == start_line) ? start_char : 0;
134 const int end = (line == end_line) ? end_char : line->len;
135
136 for (int i = start; i < end; i++) {
137 if (!ELEM(line->line[i], ' ', '\t', '\n')) {
138 return false;
139 }
140 }
141 }
142
143 return true;
144}
145
152static char *buf_tabs_to_spaces(const char *in_buf, const int tab_size, int *r_out_buf_len)
153{
154 /* Get the number of tab characters in buffer. */
155 bool line_start = true;
156 int num_tabs = 0;
157
158 for (int in_offset = 0; in_buf[in_offset]; in_offset++) {
159 /* Verify if is an indentation whitespace character. */
160 test_line_start(in_buf[in_offset], &line_start);
161
162 if (in_buf[in_offset] == '\t' && line_start) {
163 num_tabs++;
164 }
165 }
166
167 /* Allocate output before with extra space for expanded tabs. */
168 const int out_size = strlen(in_buf) + num_tabs * (tab_size - 1) + 1;
169 char *out_buf = static_cast<char *>(MEM_mallocN(out_size * sizeof(char), __func__));
170
171 /* Fill output buffer. */
172 int spaces_until_tab = 0;
173 int out_offset = 0;
174 line_start = true;
175
176 for (int in_offset = 0; in_buf[in_offset]; in_offset++) {
177 /* Verify if is an indentation whitespace character. */
178 test_line_start(in_buf[in_offset], &line_start);
179
180 if (in_buf[in_offset] == '\t' && line_start) {
181 /* Calculate tab size so it fills until next indentation. */
182 int num_spaces = tab_size - (spaces_until_tab % tab_size);
183 spaces_until_tab = 0;
184
185 /* Write to buffer. */
186 memset(&out_buf[out_offset], ' ', num_spaces);
187 out_offset += num_spaces;
188 }
189 else {
190 if (in_buf[in_offset] == ' ') {
191 spaces_until_tab++;
192 }
193 else if (in_buf[in_offset] == '\n') {
194 spaces_until_tab = 0;
195 }
196
197 out_buf[out_offset++] = in_buf[in_offset];
198 }
199 }
200
201 out_buf[out_offset] = '\0';
202 *r_out_buf_len = out_offset;
203 return out_buf;
204}
205
207{
208 /* Add half the char width so mouse cursor selection is in between letters. */
209 return (x + (st->runtime->cwidth_px / 2)) / st->runtime->cwidth_px;
210}
211
213{
215 return;
216 }
217 if (!txt_has_sel(text)) {
218 return;
219 }
220 char *buf = txt_sel_to_buf(text, nullptr);
221 if (buf == nullptr) {
222 return;
223 }
224 WM_clipboard_text_set(buf, true);
225 MEM_freeN(buf);
226}
227
230/* -------------------------------------------------------------------- */
234static bool text_new_poll(bContext * /*C*/)
235{
236 return true;
237}
238
240{
241 Text *text = CTX_data_edit_text(C);
242 if (!text) {
243 return false;
244 }
245 return true;
246}
247
249{
250 Text *text = CTX_data_edit_text(C);
251
252 if (!text) {
253 return false;
254 }
255
256 if (!BKE_id_is_editable(CTX_data_main(C), &text->id)) {
257 // BKE_report(op->reports, RPT_ERROR, "Cannot edit external library data");
258 return false;
259 }
260
261 return true;
262}
263
265{
267 Text *text = CTX_data_edit_text(C);
268
269 if (!st || !text) {
270 return false;
271 }
272
273 if (!BKE_id_is_editable(CTX_data_main(C), &text->id)) {
274 // BKE_report(op->reports, RPT_ERROR, "Cannot edit external library data");
275 return false;
276 }
277
278 return true;
279}
280
282{
284 Text *text = CTX_data_edit_text(C);
285 ARegion *region = CTX_wm_region(C);
286
287 if (!st || !text) {
288 return false;
289 }
290
291 if (!region || region->regiontype != RGN_TYPE_WINDOW) {
292 return false;
293 }
294
295 if (!BKE_id_is_editable(CTX_data_main(C), &text->id)) {
296 // BKE_report(op->reports, RPT_ERROR, "Cannot edit external library data");
297 return false;
298 }
299
300 return true;
301}
302
305/* -------------------------------------------------------------------- */
310{
311 if (!line) {
312 return;
313 }
314
315 /* we just free format here, and let it rebuild during draw */
316 MEM_SAFE_FREE(line->format);
317}
318
320{
321 LISTBASE_FOREACH (TextLine *, line, &text->lines) {
323 }
324}
325
328/* -------------------------------------------------------------------- */
332static int text_new_exec(bContext *C, wmOperator * /*op*/)
333{
335 Main *bmain = CTX_data_main(C);
336 Text *text;
338 PropertyRNA *prop;
339
340 text = BKE_text_add(bmain, DATA_("Text"));
341
342 /* hook into UI */
344
345 if (prop) {
346 PointerRNA idptr = RNA_id_pointer_create(&text->id);
347 RNA_property_pointer_set(&ptr, prop, idptr, nullptr);
348 RNA_property_update(C, &ptr, prop);
349 }
350 else if (st) {
351 st->text = text;
352 st->left = 0;
353 st->top = 0;
354 st->runtime->scroll_ofs_px[0] = 0;
355 st->runtime->scroll_ofs_px[1] = 0;
357 }
358
360
361 return OPERATOR_FINISHED;
362}
363
365{
366 /* identifiers */
367 ot->name = "New Text";
368 ot->idname = "TEXT_OT_new";
369 ot->description = "Create a new text data-block";
370
371 /* api callbacks */
374
375 /* flags */
377}
378
381/* -------------------------------------------------------------------- */
386{
387 PropertyPointerRNA *pprop = static_cast<PropertyPointerRNA *>(
388 MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA"));
389
390 op->customdata = pprop;
392}
393
394static void text_open_cancel(bContext * /*C*/, wmOperator *op)
395{
397}
398
400{
402 Main *bmain = CTX_data_main(C);
403 Text *text;
404 PropertyPointerRNA *pprop;
405 char filepath[FILE_MAX];
406 const bool internal = RNA_boolean_get(op->ptr, "internal");
407
408 RNA_string_get(op->ptr, "filepath", filepath);
409
410 text = BKE_text_load_ex(bmain, filepath, BKE_main_blendfile_path(bmain), internal);
411
412 if (!text) {
413 if (op->customdata) {
415 }
416 return OPERATOR_CANCELLED;
417 }
418
419 if (!op->customdata) {
420 text_open_init(C, op);
421 }
422
423 /* hook into UI */
424 pprop = static_cast<PropertyPointerRNA *>(op->customdata);
425
426 if (pprop->prop) {
427 PointerRNA idptr = RNA_id_pointer_create(&text->id);
428 RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, nullptr);
429 RNA_property_update(C, &pprop->ptr, pprop->prop);
430 }
431 else if (st) {
432 st->text = text;
433 st->left = 0;
434 st->top = 0;
435 st->runtime->scroll_ofs_px[0] = 0;
436 st->runtime->scroll_ofs_px[1] = 0;
437 }
438
441
443
444 return OPERATOR_FINISHED;
445}
446
447static int text_open_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
448{
449 Main *bmain = CTX_data_main(C);
450 Text *text = CTX_data_edit_text(C);
451 const char *path = (text && text->filepath) ? text->filepath : BKE_main_blendfile_path(bmain);
452
453 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
454 return text_open_exec(C, op);
455 }
456
457 text_open_init(C, op);
458 RNA_string_set(op->ptr, "filepath", path);
460
462}
463
465{
466 /* identifiers */
467 ot->name = "Open Text";
468 ot->idname = "TEXT_OT_open";
469 ot->description = "Open a new text data-block";
470
471 /* api callbacks */
476
477 /* flags */
479
480 /* properties */
487 FILE_SORT_DEFAULT); /* TODO: relative_path. */
489 ot->srna, "internal", false, "Make Internal", "Make text file internal after loading");
490}
491
494/* -------------------------------------------------------------------- */
499{
501 Text *text = CTX_data_edit_text(C);
502 ARegion *region = CTX_wm_region(C);
503
504 /* store view & cursor state */
505 const int orig_top = st->top;
506 const int orig_curl = BLI_findindex(&text->lines, text->curl);
507 const int orig_curc = text->curc;
508
509 /* Don't make this part of 'poll', since 'Alt-R' will type 'R',
510 * if poll checks for the filename. */
511 if (text->filepath == nullptr) {
512 BKE_report(op->reports, RPT_ERROR, "This text has not been saved");
513 return OPERATOR_CANCELLED;
514 }
515
516 if (!BKE_text_reload(text)) {
517 BKE_report(op->reports, RPT_ERROR, "Could not reopen file");
518 return OPERATOR_CANCELLED;
519 }
520
521#ifdef WITH_PYTHON
522 if (text->compiled) {
523 BPY_text_free_code(text);
524 }
525#endif
526
527 text_update_edited(text);
531
532 text->flags &= ~TXT_ISDIRTY;
533
534 /* return to scroll position */
535 st->top = orig_top;
536 space_text_screen_clamp(st, region);
537 /* return cursor */
538 txt_move_to(text, orig_curl, orig_curc, false);
539
540 return OPERATOR_FINISHED;
541}
542
543static int text_reload_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
544{
545 return WM_operator_confirm_ex(C,
546 op,
547 IFACE_("Reload active text file?"),
548 nullptr,
549 IFACE_("Reload"),
551 false);
552}
553
555{
556 /* identifiers */
557 ot->name = "Reload";
558 ot->idname = "TEXT_OT_reload";
559 ot->description = "Reload active text data-block from its file";
560
561 /* api callbacks */
565}
566
569/* -------------------------------------------------------------------- */
574{
575 /* it should be possible to unlink texts if they're lib-linked in... */
576 return CTX_data_edit_text(C) != nullptr;
577}
578
579static int text_unlink_exec(bContext *C, wmOperator * /*op*/)
580{
581 Main *bmain = CTX_data_main(C);
583 Text *text = CTX_data_edit_text(C);
584
585 /* make the previous text active, if its not there make the next text active */
586 if (st) {
587 if (text->id.prev) {
588 st->text = static_cast<Text *>(text->id.prev);
590 }
591 else if (text->id.next) {
592 st->text = static_cast<Text *>(text->id.next);
594 }
595 }
596
597 BKE_id_delete(bmain, text);
598
601
602 return OPERATOR_FINISHED;
603}
604
605static int text_unlink_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
606{
607 return WM_operator_confirm_ex(C,
608 op,
609 IFACE_("Delete active text file?"),
610 nullptr,
611 IFACE_("Delete"),
613 false);
614}
615
617{
618 /* identifiers */
619 ot->name = "Unlink";
620 ot->idname = "TEXT_OT_unlink";
621 ot->description = "Unlink active text data-block";
622
623 /* api callbacks */
627
628 /* flags */
630}
631
634/* -------------------------------------------------------------------- */
639{
640 Text *text = CTX_data_edit_text(C);
641
642 text->flags |= TXT_ISMEM | TXT_ISDIRTY;
643
644 MEM_SAFE_FREE(text->filepath);
645
648
649 return OPERATOR_FINISHED;
650}
651
653{
654 /* identifiers */
655 ot->name = "Make Internal";
656 ot->idname = "TEXT_OT_make_internal";
657 ot->description = "Make active text file internal";
658
659 /* api callbacks */
662
663 /* flags */
665}
666
669/* -------------------------------------------------------------------- */
673static void txt_write_file(Main *bmain, Text *text, ReportList *reports)
674{
675 FILE *fp;
676 BLI_stat_t st;
677 char filepath[FILE_MAX];
678
679 if (text->filepath == nullptr) {
680 BKE_reportf(reports, RPT_ERROR, "No file path for \"%s\"", text->id.name + 2);
681 return;
682 }
683
684 STRNCPY(filepath, text->filepath);
685 BLI_path_abs(filepath, BKE_main_blendfile_path(bmain));
686
687 /* Check if file write permission is ok. */
688 if (BLI_exists(filepath) && !BLI_file_is_writable(filepath)) {
690 reports, RPT_ERROR, "Cannot save text file, path \"%s\" is not writable", filepath);
691 return;
692 }
693
694 fp = BLI_fopen(filepath, "w");
695 if (fp == nullptr) {
696 BKE_reportf(reports,
697 RPT_ERROR,
698 "Unable to save '%s': %s",
699 filepath,
700 errno ? strerror(errno) : RPT_("unknown error writing file"));
701 return;
702 }
703
704 LISTBASE_FOREACH (TextLine *, tmp, &text->lines) {
705 fputs(tmp->line, fp);
706 if (tmp->next) {
707 fputc('\n', fp);
708 }
709 }
710
711 fclose(fp);
712
713 if (BLI_stat(filepath, &st) == 0) {
714 text->mtime = st.st_mtime;
715
716 /* Report since this can be called from key shortcuts. */
717 BKE_reportf(reports, RPT_INFO, "Saved text \"%s\"", filepath);
718 }
719 else {
720 text->mtime = 0;
721 BKE_reportf(reports,
723 "Unable to stat '%s': %s",
724 filepath,
725 errno ? strerror(errno) : RPT_("unknown error statting file"));
726 }
727
728 text->flags &= ~TXT_ISDIRTY;
729}
730
732{
733 Main *bmain = CTX_data_main(C);
734 Text *text = CTX_data_edit_text(C);
735
736 txt_write_file(bmain, text, op->reports);
737
740
741 return OPERATOR_FINISHED;
742}
743
744static int text_save_invoke(bContext *C, wmOperator *op, const wmEvent *event)
745{
746 Text *text = CTX_data_edit_text(C);
747
748 /* Internal and texts without a filepath will go to "Save As". */
749 if (text->filepath == nullptr || (text->flags & TXT_ISMEM)) {
750 WM_operator_name_call(C, "TEXT_OT_save_as", WM_OP_INVOKE_DEFAULT, nullptr, event);
751 return OPERATOR_CANCELLED;
752 }
753 return text_save_exec(C, op);
754}
755
757{
758 /* identifiers */
759 ot->name = "Save";
760 ot->idname = "TEXT_OT_save";
761 ot->description = "Save active text data-block";
762
763 /* api callbacks */
767}
768
771/* -------------------------------------------------------------------- */
776{
777 Main *bmain = CTX_data_main(C);
778 Text *text = CTX_data_edit_text(C);
779 char filepath[FILE_MAX];
780
781 if (!text) {
782 return OPERATOR_CANCELLED;
783 }
784
785 RNA_string_get(op->ptr, "filepath", filepath);
786
787 if (text->filepath) {
788 MEM_freeN(text->filepath);
789 }
790 text->filepath = BLI_strdup(filepath);
791 text->flags &= ~TXT_ISMEM;
792
793 txt_write_file(bmain, text, op->reports);
794
797
798 return OPERATOR_FINISHED;
799}
800
801static int text_save_as_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
802{
803 Main *bmain = CTX_data_main(C);
804 Text *text = CTX_data_edit_text(C);
805
806 if (RNA_struct_property_is_set(op->ptr, "filepath")) {
807 return text_save_as_exec(C, op);
808 }
809
810 const char *filepath;
811 if (text->filepath) {
812 filepath = text->filepath;
813 }
814 else if (text->flags & TXT_ISMEM) {
815 filepath = text->id.name + 2;
816 }
817 else {
818 filepath = BKE_main_blendfile_path(bmain);
819 }
820
821 RNA_string_set(op->ptr, "filepath", filepath);
823
825}
826
828{
829 /* identifiers */
830 ot->name = "Save As";
831 ot->idname = "TEXT_OT_save_as";
832 ot->description = "Save active text file with options";
833
834 /* api callbacks */
838
839 /* properties */
843 FILE_SAVE,
846 FILE_SORT_DEFAULT); /* XXX TODO: relative_path. */
847}
848
851/* -------------------------------------------------------------------- */
855static int text_run_script(bContext *C, ReportList *reports)
856{
857#ifdef WITH_PYTHON
858 Text *text = CTX_data_edit_text(C);
859 const bool is_live = (reports == nullptr);
860
861 /* only for comparison */
862 void *curl_prev = text->curl;
863 int curc_prev = text->curc;
864 int selc_prev = text->selc;
865
866 if (BPY_run_text(C, text, reports, !is_live)) {
867 if (is_live) {
868 /* for nice live updates */
870 }
871 return OPERATOR_FINISHED;
872 }
873
874 /* Don't report error messages while live editing */
875 if (!is_live) {
876 /* text may have freed itself */
877 if (CTX_data_edit_text(C) == text) {
878 if (text->curl != curl_prev || curc_prev != text->curc || selc_prev != text->selc) {
881 }
882 }
883
884 /* No need to report the error, this has already been handled by #BPY_run_text. */
885 return OPERATOR_FINISHED;
886 }
887#else
888 (void)C;
889 (void)reports;
890#endif /* !WITH_PYTHON */
891 return OPERATOR_CANCELLED;
892}
893
895{
896#ifndef WITH_PYTHON
897 (void)C; /* unused */
898
899 BKE_report(op->reports, RPT_ERROR, "Python disabled in this build");
900
901 return OPERATOR_CANCELLED;
902#else
903 return text_run_script(C, op->reports);
904#endif /* WITH_PYTHON */
905}
906
908{
909 /* identifiers */
910 ot->name = "Run Script";
911 ot->idname = "TEXT_OT_run_script";
912 ot->description = "Run active script";
913
914 /* api callbacks */
917
918 /* flags */
920}
921
924/* -------------------------------------------------------------------- */
929{
930#ifdef WITH_PYTHON
931# if 0
932 Main *bmain = CTX_data_main(C);
933 Text *text = CTX_data_edit_text(C);
934 Object *ob;
935 bConstraint *con;
936 bool update;
937
938 /* check all pyconstraints */
939 for (ob = bmain->objects.first; ob; ob = ob->id.next) {
940 update = false;
941 if (ob->type == OB_ARMATURE && ob->pose) {
942 bPoseChannel *pchan;
943 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
944 for (con = pchan->constraints.first; con; con = con->next) {
945 if (con->type == CONSTRAINT_TYPE_PYTHON) {
946 bPythonConstraint *data = con->data;
947 if (data->text == text) {
949 }
950 update = true;
951 }
952 }
953 }
954 }
955 for (con = ob->constraints.first; con; con = con->next) {
956 if (con->type == CONSTRAINT_TYPE_PYTHON) {
957 bPythonConstraint *data = con->data;
958 if (data->text == text) {
960 }
961 update = true;
962 }
963 }
964
965 if (update) {
967 }
968 }
969# endif
970#endif
971
972 return OPERATOR_FINISHED;
973}
974
976{
977 /* identifiers */
978 ot->name = "Refresh PyConstraints";
979 ot->idname = "TEXT_OT_refresh_pyconstraints";
980 ot->description = "Refresh all pyconstraints";
981
982 /* api callbacks */
985}
986
989/* -------------------------------------------------------------------- */
994{
996 Text *text = CTX_data_edit_text(C);
997
998 const bool selection = RNA_boolean_get(op->ptr, "selection");
999
1000 char *buf;
1001 int buf_len;
1002
1003 /* No need for UTF8 validation as the conversion handles invalid sequences gracefully. */
1004 buf = WM_clipboard_text_get(selection, false, &buf_len);
1005
1006 if (!buf) {
1007 return OPERATOR_CANCELLED;
1008 }
1009
1011
1013
1014 /* Convert clipboard content indentation to spaces if specified */
1015 if (text->flags & TXT_TABSTOSPACES) {
1016 char *new_buf = buf_tabs_to_spaces(buf, TXT_TABSIZE, &buf_len);
1017 MEM_freeN(buf);
1018 buf = new_buf;
1019 }
1020
1021 txt_insert_buf(text, buf, buf_len);
1022 text_update_edited(text);
1023
1024 MEM_freeN(buf);
1025
1028
1029 /* run the script while editing, evil but useful */
1030 if (st->live_edit) {
1031 text_run_script(C, nullptr);
1032 }
1033
1034 return OPERATOR_FINISHED;
1035}
1036
1038{
1039 /* identifiers */
1040 ot->name = "Paste";
1041 ot->idname = "TEXT_OT_paste";
1042 ot->description = "Paste text from clipboard";
1043
1044 /* api callbacks */
1047
1048 /* flags */
1049 ot->flag = OPTYPE_UNDO;
1050
1051 /* properties */
1052 PropertyRNA *prop;
1053 prop = RNA_def_boolean(ot->srna,
1054 "selection",
1055 false,
1056 "Selection",
1057 "Paste text selected elsewhere rather than copied (X11/Wayland only)");
1059}
1060
1063/* -------------------------------------------------------------------- */
1068{
1069 Text *text = CTX_data_edit_text(C);
1070
1072
1073 txt_duplicate_line(text);
1074
1076
1077 /* run the script while editing, evil but useful */
1078 if (CTX_wm_space_text(C)->live_edit) {
1079 text_run_script(C, nullptr);
1080 }
1081
1082 return OPERATOR_FINISHED;
1083}
1084
1086{
1087 /* identifiers */
1088 ot->name = "Duplicate Line";
1089 ot->idname = "TEXT_OT_duplicate_line";
1090 ot->description = "Duplicate the current line";
1091
1092 /* api callbacks */
1095
1096 /* flags */
1097 ot->flag = OPTYPE_UNDO;
1098}
1099
1102/* -------------------------------------------------------------------- */
1106static void txt_copy_clipboard(const Text *text)
1107{
1108 char *buf;
1109
1110 if (!txt_has_sel(text)) {
1111 return;
1112 }
1113
1114 buf = txt_sel_to_buf(text, nullptr);
1115
1116 if (buf) {
1117 WM_clipboard_text_set(buf, false);
1118 MEM_freeN(buf);
1119 }
1120}
1121
1122static int text_copy_exec(bContext *C, wmOperator * /*op*/)
1123{
1124 const Text *text = CTX_data_edit_text(C);
1125
1126 txt_copy_clipboard(text);
1127
1128 return OPERATOR_FINISHED;
1129}
1130
1132{
1133 /* identifiers */
1134 ot->name = "Copy";
1135 ot->idname = "TEXT_OT_copy";
1136 ot->description = "Copy selected text to clipboard";
1137
1138 /* api callbacks */
1141}
1142
1145/* -------------------------------------------------------------------- */
1149static int text_cut_exec(bContext *C, wmOperator * /*op*/)
1150{
1152 Text *text = CTX_data_edit_text(C);
1153
1155
1156 txt_copy_clipboard(text);
1157
1159 txt_delete_selected(text);
1160
1163
1164 /* run the script while editing, evil but useful */
1165 if (st->live_edit) {
1166 text_run_script(C, nullptr);
1167 }
1168
1169 return OPERATOR_FINISHED;
1170}
1171
1173{
1174 /* identifiers */
1175 ot->name = "Cut";
1176 ot->idname = "TEXT_OT_cut";
1177 ot->description = "Cut selected text to clipboard";
1178
1179 /* api callbacks */
1182
1183 /* flags */
1184 ot->flag = OPTYPE_UNDO;
1185}
1186
1189/* -------------------------------------------------------------------- */
1194{
1195 Text *text = CTX_data_edit_text(C);
1196 TextLine *line = text->curl;
1197 bool text_before_cursor = text->curc != 0 && !ELEM(line->line[text->curc - 1], ' ', '\t');
1198 if (text_before_cursor && (txt_has_sel(text) == false)) {
1199 WM_operator_name_call(C, "TEXT_OT_autocomplete", WM_OP_INVOKE_DEFAULT, nullptr, nullptr);
1200 }
1201 else {
1202 WM_operator_name_call(C, "TEXT_OT_indent", WM_OP_EXEC_DEFAULT, nullptr, nullptr);
1203 }
1204 return OPERATOR_FINISHED;
1205}
1206
1208{
1209 /* identifiers */
1210 ot->name = "Indent or Autocomplete";
1211 ot->idname = "TEXT_OT_indent_or_autocomplete";
1212 ot->description = "Indent selected text or autocomplete";
1213
1214 /* api callbacks */
1217
1218 /* flags */
1219 ot->flag = 0;
1220}
1221
1224/* -------------------------------------------------------------------- */
1228static int text_indent_exec(bContext *C, wmOperator * /*op*/)
1229{
1231 Text *text = CTX_data_edit_text(C);
1232
1234
1236
1237 if (txt_has_sel(text)) {
1238 txt_order_cursors(text, false);
1239 txt_indent(text);
1240 }
1241 else {
1242 txt_add_char(text, '\t');
1243 }
1244
1245 text_update_edited(text);
1246
1249
1250 return OPERATOR_FINISHED;
1251}
1252
1254{
1255 /* identifiers */
1256 ot->name = "Indent";
1257 ot->idname = "TEXT_OT_indent";
1258 ot->description = "Indent selected text";
1259
1260 /* api callbacks */
1263
1264 /* flags */
1265 ot->flag = OPTYPE_UNDO;
1266}
1267
1270/* -------------------------------------------------------------------- */
1275{
1277 Text *text = CTX_data_edit_text(C);
1278
1280
1282
1283 txt_order_cursors(text, false);
1284 txt_unindent(text);
1285
1286 text_update_edited(text);
1287
1290
1291 return OPERATOR_FINISHED;
1292}
1293
1295{
1296 /* identifiers */
1297 ot->name = "Unindent";
1298 ot->idname = "TEXT_OT_unindent";
1299 ot->description = "Unindent selected text";
1300
1301 /* api callbacks */
1304
1305 /* flags */
1306 ot->flag = OPTYPE_UNDO;
1307}
1308
1311/* -------------------------------------------------------------------- */
1316{
1318 Text *text = CTX_data_edit_text(C);
1319 int a, curts;
1320 int space = (text->flags & TXT_TABSTOSPACES) ? st->tabnumber : 1;
1321
1323
1324 /* Double check tabs/spaces before splitting the line. */
1325 curts = txt_setcurr_tab_spaces(text, space);
1327 txt_split_curline(text);
1328
1329 for (a = 0; a < curts; a++) {
1330 if (text->flags & TXT_TABSTOSPACES) {
1331 txt_add_char(text, ' ');
1332 }
1333 else {
1334 txt_add_char(text, '\t');
1335 }
1336 }
1337
1338 if (text->curl) {
1339 if (text->curl->prev) {
1340 text_update_line_edited(text->curl->prev);
1341 }
1342 text_update_line_edited(text->curl);
1343 }
1344
1347
1348 return OPERATOR_FINISHED;
1349}
1350
1352{
1353 /* identifiers */
1354 ot->name = "Line Break";
1355 ot->idname = "TEXT_OT_line_break";
1356 ot->description = "Insert line break at cursor position";
1357
1358 /* api callbacks */
1361
1362 /* flags */
1363 ot->flag = OPTYPE_UNDO;
1364}
1365
1368/* -------------------------------------------------------------------- */
1373{
1375 Text *text = CTX_data_edit_text(C);
1376 int type = RNA_enum_get(op->ptr, "type");
1377 const char *prefix = ED_text_format_comment_line_prefix(text);
1378
1380
1382
1383 if (txt_has_sel(text)) {
1384 txt_order_cursors(text, false);
1385 }
1386
1387 switch (type) {
1388 case 1:
1389 txt_comment(text, prefix);
1390 break;
1391 case -1:
1392 txt_uncomment(text, prefix);
1393 break;
1394 default:
1395 if (txt_uncomment(text, prefix) == false) {
1396 txt_comment(text, prefix);
1397 }
1398 break;
1399 }
1400
1401 text_update_edited(text);
1402
1405
1406 return OPERATOR_FINISHED;
1407}
1408
1410{
1411 static const EnumPropertyItem comment_items[] = {
1412 {0, "TOGGLE", 0, "Toggle Comments", nullptr},
1413 {1, "COMMENT", 0, "Comment", nullptr},
1414 {-1, "UNCOMMENT", 0, "Un-Comment", nullptr},
1415 {0, nullptr, 0, nullptr, nullptr},
1416 };
1417
1418 /* identifiers */
1419 ot->name = "Toggle Comments";
1420 ot->idname = "TEXT_OT_comment_toggle";
1421
1422 /* api callbacks */
1425
1426 /* flags */
1427 ot->flag = OPTYPE_UNDO;
1428
1429 /* properties */
1430 PropertyRNA *prop;
1431 prop = RNA_def_enum(ot->srna, "type", comment_items, 0, "Type", "Add or remove comments");
1433}
1434
1437/* -------------------------------------------------------------------- */
1443 {TO_SPACES, "SPACES", 0, "To Spaces", nullptr},
1444 {TO_TABS, "TABS", 0, "To Tabs", nullptr},
1445 {0, nullptr, 0, nullptr, nullptr},
1446};
1447
1449{
1451 Text *text = CTX_data_edit_text(C);
1452 FlattenString fs;
1453 size_t a, j, max_len = 0;
1454 int type = RNA_enum_get(op->ptr, "type");
1455
1456 const int curc_column = text->curl ?
1458 text->curl->line, text->curl->len, text->curc, TXT_TABSIZE) :
1459 -1;
1460 const int selc_column = text->sell ?
1462 text->sell->line, text->sell->len, text->selc, TXT_TABSIZE) :
1463 -1;
1464
1465 /* first convert to all space, this make it a lot easier to convert to tabs
1466 * because there is no mixtures of ' ' && '\t' */
1467 LISTBASE_FOREACH (TextLine *, tmp, &text->lines) {
1468 char *new_line;
1469
1470 BLI_assert(tmp->line);
1471
1472 flatten_string(st, &fs, tmp->line);
1473 new_line = BLI_strdup(fs.buf);
1475
1476 MEM_freeN(tmp->line);
1477 if (tmp->format) {
1478 MEM_freeN(tmp->format);
1479 }
1480
1481 /* Put new_line in the tmp->line spot still need to try and set the curc correctly. */
1482 tmp->line = new_line;
1483 tmp->len = strlen(new_line);
1484 tmp->format = nullptr;
1485 if (tmp->len > max_len) {
1486 max_len = tmp->len;
1487 }
1488 }
1489
1490 if (type == TO_TABS) {
1491 char *tmp_line = static_cast<char *>(MEM_mallocN(sizeof(*tmp_line) * (max_len + 1), __func__));
1492
1493 LISTBASE_FOREACH (TextLine *, tmp, &text->lines) {
1494 const char *text_check_line = tmp->line;
1495 const int text_check_line_len = tmp->len;
1496 char *tmp_line_cur = tmp_line;
1497 const size_t tab_len = st->tabnumber;
1498
1499 BLI_assert(text_check_line);
1500
1501 for (a = 0; a < text_check_line_len;) {
1502 /* A tab can only start at a position multiple of tab_len... */
1503 if (!(a % tab_len) && (text_check_line[a] == ' ')) {
1504 /* a + 0 we already know to be ' ' char... */
1505 for (j = 1;
1506 (j < tab_len) && (a + j < text_check_line_len) && (text_check_line[a + j] == ' ');
1507 j++)
1508 {
1509 /* pass */
1510 }
1511
1512 if (j == tab_len) {
1513 /* We found a set of spaces that can be replaced by a tab... */
1514 if ((tmp_line_cur == tmp_line) && a != 0) {
1515 /* Copy all 'valid' string already 'parsed'... */
1516 memcpy(tmp_line_cur, text_check_line, a);
1517 tmp_line_cur += a;
1518 }
1519 *tmp_line_cur = '\t';
1520 tmp_line_cur++;
1521 a += j;
1522 }
1523 else {
1524 if (tmp_line_cur != tmp_line) {
1525 memcpy(tmp_line_cur, &text_check_line[a], j);
1526 tmp_line_cur += j;
1527 }
1528 a += j;
1529 }
1530 }
1531 else {
1532 size_t len = BLI_str_utf8_size_safe(&text_check_line[a]);
1533 if (tmp_line_cur != tmp_line) {
1534 memcpy(tmp_line_cur, &text_check_line[a], len);
1535 tmp_line_cur += len;
1536 }
1537 a += len;
1538 }
1539 }
1540
1541 if (tmp_line_cur != tmp_line) {
1542 *tmp_line_cur = '\0';
1543
1544#ifndef NDEBUG
1545 BLI_assert(tmp_line_cur - tmp_line <= max_len);
1546
1547 flatten_string(st, &fs, tmp_line);
1548 BLI_assert(STREQ(fs.buf, tmp->line));
1550#endif
1551
1552 MEM_freeN(tmp->line);
1553 if (tmp->format) {
1554 MEM_freeN(tmp->format);
1555 }
1556
1557 /* Put new_line in the `tmp->line` spot. */
1558 tmp->len = strlen(tmp_line);
1559 tmp->line = BLI_strdupn(tmp_line, tmp->len);
1560 tmp->format = nullptr;
1561 }
1562 }
1563
1564 MEM_freeN(tmp_line);
1565 }
1566
1567 if (curc_column != -1) {
1569 text->curl->line, text->curl->len, curc_column, TXT_TABSIZE);
1570 }
1571 if (selc_column != -1) {
1573 text->sell->line, text->sell->len, selc_column, TXT_TABSIZE);
1574 }
1575
1576 text_update_edited(text);
1580
1581 return OPERATOR_FINISHED;
1582}
1583
1585{
1586 /* identifiers */
1587 ot->name = "Convert Whitespace";
1588 ot->idname = "TEXT_OT_convert_whitespace";
1589 ot->description = "Convert whitespaces by type";
1590
1591 /* api callbacks */
1594
1595 /* flags */
1596 ot->flag = OPTYPE_UNDO;
1597
1598 /* properties */
1600 "type",
1602 TO_SPACES,
1603 "Type",
1604 "Type of whitespace to convert to");
1605}
1606
1609/* -------------------------------------------------------------------- */
1614{
1615 Text *text = CTX_data_edit_text(C);
1616
1617 txt_sel_all(text);
1618
1621
1623
1624 return OPERATOR_FINISHED;
1625}
1626
1628{
1629 /* identifiers */
1630 ot->name = "Select All";
1631 ot->idname = "TEXT_OT_select_all";
1632 ot->description = "Select all text";
1633
1634 /* api callbacks */
1637}
1638
1641/* -------------------------------------------------------------------- */
1646{
1647 Text *text = CTX_data_edit_text(C);
1648
1649 txt_sel_line(text);
1650
1653
1655
1656 return OPERATOR_FINISHED;
1657}
1658
1660{
1661 /* identifiers */
1662 ot->name = "Select Line";
1663 ot->idname = "TEXT_OT_select_line";
1664 ot->description = "Select text by line";
1665
1666 /* api callbacks */
1669}
1670
1673/* -------------------------------------------------------------------- */
1678{
1679 Text *text = CTX_data_edit_text(C);
1680
1682 text->curl->line, text->curl->len, text->selc, &text->curc, &text->selc);
1683
1686
1688
1689 return OPERATOR_FINISHED;
1690}
1691
1693{
1694 /* identifiers */
1695 ot->name = "Select Word";
1696 ot->idname = "TEXT_OT_select_word";
1697 ot->description = "Select word under cursor";
1698
1699 /* api callbacks */
1702}
1703
1706/* -------------------------------------------------------------------- */
1711{
1712 Text *text = CTX_data_edit_text(C);
1713 const int direction = RNA_enum_get(op->ptr, "direction");
1714
1716
1717 txt_move_lines(text, direction);
1718
1721
1722 /* run the script while editing, evil but useful */
1723 if (CTX_wm_space_text(C)->live_edit) {
1724 text_run_script(C, nullptr);
1725 }
1726
1727 return OPERATOR_FINISHED;
1728}
1729
1731{
1732 static const EnumPropertyItem direction_items[] = {
1733 {TXT_MOVE_LINE_UP, "UP", 0, "Up", ""},
1734 {TXT_MOVE_LINE_DOWN, "DOWN", 0, "Down", ""},
1735 {0, nullptr, 0, nullptr, nullptr},
1736 };
1737
1738 /* identifiers */
1739 ot->name = "Move Lines";
1740 ot->idname = "TEXT_OT_move_lines";
1741 ot->description = "Move the currently selected line(s) up/down";
1742
1743 /* api callbacks */
1746
1747 /* flags */
1748 ot->flag = OPTYPE_UNDO;
1749
1750 /* properties */
1751 RNA_def_enum(ot->srna, "direction", direction_items, 1, "Direction", "");
1752}
1753
1756/* -------------------------------------------------------------------- */
1761 {LINE_BEGIN, "LINE_BEGIN", 0, "Line Begin", ""},
1762 {LINE_END, "LINE_END", 0, "Line End", ""},
1763 {FILE_TOP, "FILE_TOP", 0, "File Top", ""},
1764 {FILE_BOTTOM, "FILE_BOTTOM", 0, "File Bottom", ""},
1765 {PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
1766 {NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
1767 {PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""},
1768 {NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""},
1769 {PREV_LINE, "PREVIOUS_LINE", 0, "Previous Line", ""},
1770 {NEXT_LINE, "NEXT_LINE", 0, "Next Line", ""},
1771 {PREV_PAGE, "PREVIOUS_PAGE", 0, "Previous Page", ""},
1772 {NEXT_PAGE, "NEXT_PAGE", 0, "Next Page", ""},
1773 {0, nullptr, 0, nullptr, nullptr},
1774};
1775
1780 const SpaceText *st, const ARegion *region, TextLine *linein, int rell, int relc)
1781{
1782 int i, j, start, end, max, curs, endj, selc;
1783 bool chop, loop, found;
1784 char ch;
1785
1786 max = space_text_wrap_width(st, region);
1787
1788 selc = start = endj = curs = found = false;
1789 end = max;
1790 chop = loop = true;
1791
1792 for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe(linein->line + j)) {
1793 int chars;
1794 const int columns = BLI_str_utf8_char_width_safe(linein->line + j); /* = 1 for tab */
1795
1796 /* Mimic replacement of tabs */
1797 ch = linein->line[j];
1798 if (ch == '\t') {
1799 chars = st->tabnumber - i % st->tabnumber;
1800 ch = ' ';
1801 }
1802 else {
1803 chars = 1;
1804 }
1805
1806 while (chars--) {
1807 if (rell == 0 && i - start <= relc && i + columns - start > relc) {
1808 /* current position could be wrapped to next line */
1809 /* this should be checked when end of current line would be reached */
1810 selc = j;
1811 found = true;
1812 }
1813 else if (i - end <= relc && i + columns - end > relc) {
1814 curs = j;
1815 }
1816 if (i + columns - start > max) {
1817 end = std::min(end, i);
1818
1819 if (found) {
1820 /* exact cursor position was found, check if it's */
1821 /* still on needed line (hasn't been wrapped) */
1822 if (selc > endj && !chop) {
1823 selc = endj;
1824 }
1825 loop = false;
1826 break;
1827 }
1828
1829 if (chop) {
1830 endj = j;
1831 }
1832
1833 start = end;
1834 end += max;
1835 chop = true;
1836 rell--;
1837
1838 if (rell == 0 && i + columns - start > relc) {
1839 selc = curs;
1840 loop = false;
1841 break;
1842 }
1843 }
1844 else if (ch == '\0') {
1845 if (!found) {
1846 selc = linein->len;
1847 }
1848 loop = false;
1849 break;
1850 }
1851 else if (ELEM(ch, ' ', '-')) {
1852 if (found) {
1853 loop = false;
1854 break;
1855 }
1856
1857 if (rell == 0 && i + columns - start > relc) {
1858 selc = curs;
1859 loop = false;
1860 break;
1861 }
1862 end = i + 1;
1863 endj = j;
1864 chop = false;
1865 }
1866 i += columns;
1867 }
1868 }
1869
1870 return selc;
1871}
1872
1874 const ARegion *region,
1875 int lines,
1876 TextLine **linep,
1877 int *charp,
1878 int *rell,
1879 int *relc)
1880{
1881 int offl, offc, visible_lines;
1882
1883 space_text_wrap_offset_in_line(st, region, *linep, *charp, &offl, &offc);
1884 *relc = space_text_get_char_pos(st, (*linep)->line, *charp) + offc;
1885 *rell = lines;
1886
1887 /* handle current line */
1888 if (lines > 0) {
1889 visible_lines = space_text_get_visible_lines(st, region, (*linep)->line);
1890
1891 if (*rell - visible_lines + offl >= 0) {
1892 if (!(*linep)->next) {
1893 if (offl < visible_lines - 1) {
1894 *rell = visible_lines - 1;
1895 return 1;
1896 }
1897
1898 *charp = (*linep)->len;
1899 return 0;
1900 }
1901
1902 *rell -= visible_lines - offl;
1903 *linep = (*linep)->next;
1904 }
1905 else {
1906 *rell += offl;
1907 return 1;
1908 }
1909 }
1910 else {
1911 if (*rell + offl <= 0) {
1912 if (!(*linep)->prev) {
1913 if (offl) {
1914 *rell = 0;
1915 return 1;
1916 }
1917
1918 *charp = 0;
1919 return 0;
1920 }
1921
1922 *rell += offl;
1923 *linep = (*linep)->prev;
1924 }
1925 else {
1926 *rell += offl;
1927 return 1;
1928 }
1929 }
1930
1931 /* skip lines and find destination line and offsets */
1932 while (*linep) {
1933 visible_lines = space_text_get_visible_lines(st, region, (*linep)->line);
1934
1935 if (lines < 0) { /* moving top */
1936 if (*rell + visible_lines >= 0) {
1937 *rell += visible_lines;
1938 break;
1939 }
1940
1941 if (!(*linep)->prev) {
1942 *rell = 0;
1943 break;
1944 }
1945
1946 *rell += visible_lines;
1947 *linep = (*linep)->prev;
1948 }
1949 else { /* moving bottom */
1950 if (*rell - visible_lines < 0) {
1951 break;
1952 }
1953
1954 if (!(*linep)->next) {
1955 *rell = visible_lines - 1;
1956 break;
1957 }
1958
1959 *rell -= visible_lines;
1960 *linep = (*linep)->next;
1961 }
1962 }
1963
1964 return 1;
1965}
1966
1967static void txt_wrap_move_bol(SpaceText *st, ARegion *region, const bool sel)
1968{
1969 Text *text = st->text;
1970 TextLine **linep;
1971 int *charp;
1972 int oldc, i, j, max, start, end, endj;
1973 bool chop, loop;
1974 char ch;
1975
1977
1978 if (sel) {
1979 linep = &text->sell;
1980 charp = &text->selc;
1981 }
1982 else {
1983 linep = &text->curl;
1984 charp = &text->curc;
1985 }
1986
1987 oldc = *charp;
1988
1989 max = space_text_wrap_width(st, region);
1990
1991 start = endj = 0;
1992 end = max;
1993 chop = loop = true;
1994 *charp = 0;
1995
1996 for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe((*linep)->line + j)) {
1997 int chars;
1998 const int columns = BLI_str_utf8_char_width_safe((*linep)->line + j); /* = 1 for tab */
1999
2000 /* Mimic replacement of tabs */
2001 ch = (*linep)->line[j];
2002 if (ch == '\t') {
2003 chars = st->tabnumber - i % st->tabnumber;
2004 ch = ' ';
2005 }
2006 else {
2007 chars = 1;
2008 }
2009
2010 while (chars--) {
2011 if (i + columns - start > max) {
2012 end = std::min(end, i);
2013
2014 *charp = endj;
2015
2016 if (j >= oldc) {
2017 if (ch == '\0') {
2019 (*linep)->line, (*linep)->len, start, TXT_TABSIZE);
2020 }
2021 loop = false;
2022 break;
2023 }
2024
2025 if (chop) {
2026 endj = j;
2027 }
2028
2029 start = end;
2030 end += max;
2031 chop = true;
2032 }
2033 else if (ELEM(ch, ' ', '-', '\0')) {
2034 if (j >= oldc) {
2036 (*linep)->line, (*linep)->len, start, TXT_TABSIZE);
2037 loop = false;
2038 break;
2039 }
2040
2041 end = i + 1;
2042 endj = j + 1;
2043 chop = false;
2044 }
2045 i += columns;
2046 }
2047 }
2048
2049 if (!sel) {
2050 txt_pop_sel(text);
2051 }
2052}
2053
2054static void txt_wrap_move_eol(SpaceText *st, ARegion *region, const bool sel)
2055{
2056 Text *text = st->text;
2057 TextLine **linep;
2058 int *charp;
2059 int oldc, i, j, max, start, end, endj;
2060 bool chop, loop;
2061 char ch;
2062
2064
2065 if (sel) {
2066 linep = &text->sell;
2067 charp = &text->selc;
2068 }
2069 else {
2070 linep = &text->curl;
2071 charp = &text->curc;
2072 }
2073
2074 oldc = *charp;
2075
2076 max = space_text_wrap_width(st, region);
2077
2078 start = endj = 0;
2079 end = max;
2080 chop = loop = true;
2081 *charp = 0;
2082
2083 for (i = 0, j = 0; loop; j += BLI_str_utf8_size_safe((*linep)->line + j)) {
2084 int chars;
2085 const int columns = BLI_str_utf8_char_width_safe((*linep)->line + j); /* = 1 for tab */
2086
2087 /* Mimic replacement of tabs */
2088 ch = (*linep)->line[j];
2089 if (ch == '\t') {
2090 chars = st->tabnumber - i % st->tabnumber;
2091 ch = ' ';
2092 }
2093 else {
2094 chars = 1;
2095 }
2096
2097 while (chars--) {
2098 if (i + columns - start > max) {
2099 end = std::min(end, i);
2100
2101 if (chop) {
2102 endj = BLI_str_find_prev_char_utf8((*linep)->line + j, (*linep)->line) - (*linep)->line;
2103 }
2104
2105 if (endj >= oldc) {
2106 if (ch == '\0') {
2107 *charp = (*linep)->len;
2108 }
2109 else {
2110 *charp = endj;
2111 }
2112 loop = false;
2113 break;
2114 }
2115
2116 start = end;
2117 end += max;
2118 chop = true;
2119 }
2120 else if (ch == '\0') {
2121 *charp = (*linep)->len;
2122 loop = false;
2123 break;
2124 }
2125 else if (ELEM(ch, ' ', '-')) {
2126 end = i + 1;
2127 endj = j;
2128 chop = false;
2129 }
2130 i += columns;
2131 }
2132 }
2133
2134 if (!sel) {
2135 txt_pop_sel(text);
2136 }
2137}
2138
2139static void txt_wrap_move_up(SpaceText *st, ARegion *region, const bool sel)
2140{
2141 Text *text = st->text;
2142 TextLine **linep;
2143 int *charp;
2144 int offl, offc, col;
2145
2147
2148 if (sel) {
2149 linep = &text->sell;
2150 charp = &text->selc;
2151 }
2152 else {
2153 linep = &text->curl;
2154 charp = &text->curc;
2155 }
2156
2157 space_text_wrap_offset_in_line(st, region, *linep, *charp, &offl, &offc);
2158 col = space_text_get_char_pos(st, (*linep)->line, *charp) + offc;
2159 if (offl) {
2160 *charp = space_text_get_cursor_rel(st, region, *linep, offl - 1, col);
2161 }
2162 else {
2163 if ((*linep)->prev) {
2164 int visible_lines;
2165
2166 *linep = (*linep)->prev;
2167 visible_lines = space_text_get_visible_lines(st, region, (*linep)->line);
2168 *charp = space_text_get_cursor_rel(st, region, *linep, visible_lines - 1, col);
2169 }
2170 else {
2171 *charp = 0;
2172 }
2173 }
2174
2175 if (!sel) {
2176 txt_pop_sel(text);
2177 }
2178}
2179
2180static void txt_wrap_move_down(SpaceText *st, ARegion *region, const bool sel)
2181{
2182 Text *text = st->text;
2183 TextLine **linep;
2184 int *charp;
2185 int offl, offc, col, visible_lines;
2186
2188
2189 if (sel) {
2190 linep = &text->sell;
2191 charp = &text->selc;
2192 }
2193 else {
2194 linep = &text->curl;
2195 charp = &text->curc;
2196 }
2197
2198 space_text_wrap_offset_in_line(st, region, *linep, *charp, &offl, &offc);
2199 col = space_text_get_char_pos(st, (*linep)->line, *charp) + offc;
2200 visible_lines = space_text_get_visible_lines(st, region, (*linep)->line);
2201 if (offl < visible_lines - 1) {
2202 *charp = space_text_get_cursor_rel(st, region, *linep, offl + 1, col);
2203 }
2204 else {
2205 if ((*linep)->next) {
2206 *linep = (*linep)->next;
2207 *charp = space_text_get_cursor_rel(st, region, *linep, 0, col);
2208 }
2209 else {
2210 *charp = (*linep)->len;
2211 }
2212 }
2213
2214 if (!sel) {
2215 txt_pop_sel(text);
2216 }
2217}
2218
2227 const SpaceText *st, const ARegion *region, Text *text, int lines, const bool sel)
2228{
2229 TextLine **linep;
2230 int *charp;
2231
2232 if (sel) {
2233 linep = &text->sell;
2234 charp = &text->selc;
2235 }
2236 else {
2237 linep = &text->curl;
2238 charp = &text->curc;
2239 }
2240
2241 if (st && region && st->wordwrap) {
2242 int rell, relc;
2243
2244 /* find line and offsets inside it needed to set cursor position */
2245 if (cursor_skip_find_line(st, region, lines, linep, charp, &rell, &relc)) {
2246 *charp = space_text_get_cursor_rel(st, region, *linep, rell, relc);
2247 }
2248 }
2249 else {
2250 while (lines > 0 && (*linep)->next) {
2251 *linep = (*linep)->next;
2252 lines--;
2253 }
2254 while (lines < 0 && (*linep)->prev) {
2255 *linep = (*linep)->prev;
2256 lines++;
2257 }
2258 }
2259
2260 if (*charp > (*linep)->len) {
2261 *charp = (*linep)->len;
2262 }
2263
2264 if (!sel) {
2265 txt_pop_sel(text);
2266 }
2267}
2268
2269static int text_move_cursor(bContext *C, int type, bool select)
2270{
2272 Text *text = CTX_data_edit_text(C);
2273 ARegion *region = CTX_wm_region(C);
2274
2275 /* ensure we have the right region, it's optional */
2276 if (region && region->regiontype != RGN_TYPE_WINDOW) {
2277 region = nullptr;
2278 }
2279
2280 switch (type) {
2281 case LINE_BEGIN:
2282 if (!select) {
2283 txt_sel_clear(text);
2284 }
2285 if (st && st->wordwrap && region) {
2286 txt_wrap_move_bol(st, region, select);
2287 }
2288 else {
2289 txt_move_bol(text, select);
2290 }
2291 break;
2292
2293 case LINE_END:
2294 if (!select) {
2295 txt_sel_clear(text);
2296 }
2297 if (st && st->wordwrap && region) {
2298 txt_wrap_move_eol(st, region, select);
2299 }
2300 else {
2301 txt_move_eol(text, select);
2302 }
2303 break;
2304
2305 case FILE_TOP:
2306 txt_move_bof(text, select);
2307 break;
2308
2309 case FILE_BOTTOM:
2310 txt_move_eof(text, select);
2311 break;
2312
2313 case PREV_WORD:
2314 if (txt_cursor_is_line_start(text)) {
2315 txt_move_left(text, select);
2316 }
2317 txt_jump_left(text, select, true);
2318 break;
2319
2320 case NEXT_WORD:
2321 if (txt_cursor_is_line_end(text)) {
2322 txt_move_right(text, select);
2323 }
2324 txt_jump_right(text, select, true);
2325 break;
2326
2327 case PREV_CHAR:
2328 if (txt_has_sel(text) && !select) {
2329 txt_order_cursors(text, false);
2330 txt_pop_sel(text);
2331 }
2332 else {
2333 txt_move_left(text, select);
2334 }
2335 break;
2336
2337 case NEXT_CHAR:
2338 if (txt_has_sel(text) && !select) {
2339 txt_order_cursors(text, true);
2340 txt_pop_sel(text);
2341 }
2342 else {
2343 txt_move_right(text, select);
2344 }
2345 break;
2346
2347 case PREV_LINE:
2348 if (st && st->wordwrap && region) {
2349 txt_wrap_move_up(st, region, select);
2350 }
2351 else {
2352 txt_move_up(text, select);
2353 }
2354 break;
2355
2356 case NEXT_LINE:
2357 if (st && st->wordwrap && region) {
2358 txt_wrap_move_down(st, region, select);
2359 }
2360 else {
2361 txt_move_down(text, select);
2362 }
2363 break;
2364
2365 case PREV_PAGE:
2366 if (st) {
2367 space_text_cursor_skip(st, region, st->text, -st->runtime->viewlines, select);
2368 }
2369 else {
2370 space_text_cursor_skip(nullptr, nullptr, text, -10, select);
2371 }
2372 break;
2373
2374 case NEXT_PAGE:
2375 if (st) {
2376 space_text_cursor_skip(st, region, st->text, st->runtime->viewlines, select);
2377 }
2378 else {
2379 space_text_cursor_skip(nullptr, nullptr, text, 10, select);
2380 }
2381 break;
2382 }
2383
2385 if (select) {
2387 }
2388
2390
2391 return OPERATOR_FINISHED;
2392}
2393
2395{
2396 int type = RNA_enum_get(op->ptr, "type");
2397
2398 return text_move_cursor(C, type, false);
2399}
2400
2402{
2403 /* identifiers */
2404 ot->name = "Move Cursor";
2405 ot->idname = "TEXT_OT_move";
2406 ot->description = "Move cursor to position type";
2407
2408 /* api callbacks */
2411
2412 /* properties */
2413 RNA_def_enum(ot->srna, "type", move_type_items, LINE_BEGIN, "Type", "Where to move cursor to");
2414}
2415
2418/* -------------------------------------------------------------------- */
2423{
2424 int type = RNA_enum_get(op->ptr, "type");
2425
2426 return text_move_cursor(C, type, true);
2427}
2428
2430{
2431 /* identifiers */
2432 ot->name = "Move Select";
2433 ot->idname = "TEXT_OT_move_select";
2434 ot->description = "Move the cursor while selecting";
2435
2436 /* api callbacks */
2439
2440 /* properties */
2442 "type",
2444 LINE_BEGIN,
2445 "Type",
2446 "Where to move cursor to, to make a selection");
2447}
2448
2451/* -------------------------------------------------------------------- */
2456{
2457 Text *text = CTX_data_edit_text(C);
2458 int line = RNA_int_get(op->ptr, "line");
2459 short nlines = txt_get_span(static_cast<TextLine *>(text->lines.first),
2460 static_cast<TextLine *>(text->lines.last)) +
2461 1;
2462
2463 if (line < 1) {
2464 txt_move_toline(text, 1, false);
2465 }
2466 else if (line > nlines) {
2467 txt_move_toline(text, nlines - 1, false);
2468 }
2469 else {
2470 txt_move_toline(text, line - 1, false);
2471 }
2472
2475
2476 return OPERATOR_FINISHED;
2477}
2478
2479static int text_jump_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
2480{
2481 return WM_operator_props_dialog_popup(C, op, 200, IFACE_("Jump to Line Number"));
2482}
2483
2485{
2486 /* identifiers */
2487 ot->name = "Jump";
2488 ot->idname = "TEXT_OT_jump";
2489 ot->description = "Jump cursor to line";
2490
2491 /* api callbacks */
2495
2496 /* properties */
2497 ot->prop = RNA_def_int(
2498 ot->srna, "line", 1, 1, INT_MAX, "Line", "Line number to jump to", 1, 10000);
2500}
2501
2504/* -------------------------------------------------------------------- */
2509 {DEL_NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
2510 {DEL_PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
2511 {DEL_NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""},
2512 {DEL_PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""},
2513 {0, nullptr, 0, nullptr, nullptr},
2514};
2515
2517{
2519 Text *text = CTX_data_edit_text(C);
2520 int type = RNA_enum_get(op->ptr, "type");
2521
2523
2524 /* behavior could be changed here,
2525 * but for now just don't jump words when we have a selection */
2526 if (txt_has_sel(text)) {
2527 if (type == DEL_PREV_WORD) {
2528 type = DEL_PREV_CHAR;
2529 }
2530 else if (type == DEL_NEXT_WORD) {
2531 type = DEL_NEXT_CHAR;
2532 }
2533 }
2534
2536
2537 if (type == DEL_PREV_WORD) {
2538 if (txt_cursor_is_line_start(text)) {
2539 txt_backspace_char(text);
2540 }
2541 txt_backspace_word(text);
2542 }
2543 else if (type == DEL_PREV_CHAR) {
2544
2545 if (text->flags & TXT_TABSTOSPACES) {
2546 if (!txt_has_sel(text) && !txt_cursor_is_line_start(text)) {
2547 int tabsize = 0;
2548 tabsize = txt_calc_tab_left(text->curl, text->curc);
2549 if (tabsize) {
2550 text->sell = text->curl;
2551 text->selc = text->curc - tabsize;
2552 txt_order_cursors(text, false);
2553 }
2554 }
2555 }
2556 if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) {
2557 const char *curr = text->curl->line + text->curc;
2558 if (*curr != '\0') {
2559 const char *prev = BLI_str_find_prev_char_utf8(curr, text->curl->line);
2560 if ((curr != prev) && /* When back-spacing from the start of the line. */
2561 (*curr == text_closing_character_pair_get(*prev)))
2562 {
2563 txt_move_right(text, false);
2564 txt_backspace_char(text);
2565 }
2566 }
2567 }
2568 txt_backspace_char(text);
2569 }
2570 else if (type == DEL_NEXT_WORD) {
2571 if (txt_cursor_is_line_end(text)) {
2572 txt_delete_char(text);
2573 }
2574 txt_delete_word(text);
2575 }
2576 else if (type == DEL_NEXT_CHAR) {
2577
2578 if (text->flags & TXT_TABSTOSPACES) {
2579 if (!txt_has_sel(text) && !txt_cursor_is_line_end(text)) {
2580 int tabsize = 0;
2581 tabsize = txt_calc_tab_right(text->curl, text->curc);
2582 if (tabsize) {
2583 text->sell = text->curl;
2584 text->selc = text->curc + tabsize;
2585 txt_order_cursors(text, true);
2586 }
2587 }
2588 }
2589
2590 txt_delete_char(text);
2591 }
2592
2593 text_update_line_edited(text->curl);
2594
2597
2598 /* run the script while editing, evil but useful */
2599 if (st->live_edit) {
2600 text_run_script(C, nullptr);
2601 }
2602
2603 return OPERATOR_FINISHED;
2604}
2605
2607{
2608 /* identifiers */
2609 ot->name = "Delete";
2610 ot->idname = "TEXT_OT_delete";
2611 ot->description = "Delete text by cursor position";
2612
2613 /* api callbacks */
2616
2617 /* flags */
2618 ot->flag = OPTYPE_UNDO;
2619
2620 /* properties */
2621 PropertyRNA *prop;
2622 prop = RNA_def_enum(ot->srna,
2623 "type",
2626 "Type",
2627 "Which part of the text to delete");
2629}
2630
2633/* -------------------------------------------------------------------- */
2638{
2640
2641 st->overwrite = !st->overwrite;
2642
2644
2645 return OPERATOR_FINISHED;
2646}
2647
2649{
2650 /* identifiers */
2651 ot->name = "Toggle Overwrite";
2652 ot->idname = "TEXT_OT_overwrite_toggle";
2653 ot->description = "Toggle overwrite while typing";
2654
2655 /* api callbacks */
2658}
2659
2662/* -------------------------------------------------------------------- */
2666static void space_text_screen_clamp(SpaceText *st, const ARegion *region)
2667{
2668 if (st->top <= 0) {
2669 st->top = 0;
2670 }
2671 else {
2672 int last;
2673 last = space_text_get_total_lines(st, region);
2674 last = last - (st->runtime->viewlines / 2);
2675 if (last > 0 && st->top > last) {
2676 st->top = last;
2677 }
2678 }
2679}
2680
2681/* Moves the view vertically by the specified number of lines */
2682static void space_text_screen_skip(SpaceText *st, ARegion *region, int lines)
2683{
2684 st->top += lines;
2685 space_text_screen_clamp(st, region);
2686}
2687
2688/* quick enum for tsc->zone (scroller handles) */
2695
2699
2702
2704
2705 /* Store the state of the display, cache some constant vars. */
2706 struct {
2707 int ofs_init[2];
2708 int ofs_max[2];
2709 int size_px[2];
2713};
2714
2716{
2717 tsc->state.ofs_init[0] = st->left;
2718 tsc->state.ofs_init[1] = st->top;
2719
2720 tsc->state.ofs_max[0] = INT_MAX;
2721 tsc->state.ofs_max[1] = max_ii(
2722 0, space_text_get_total_lines(st, region) - (st->runtime->viewlines / 2));
2723
2724 tsc->state.size_px[0] = st->runtime->cwidth_px;
2725 tsc->state.size_px[1] = TXT_LINE_HEIGHT(st);
2726}
2727
2729{
2730 /* it should be possible to still scroll linked texts to read them,
2731 * even if they can't be edited... */
2732 return CTX_data_edit_text(C) != nullptr;
2733}
2734
2736{
2738 ARegion *region = CTX_wm_region(C);
2739
2740 int lines = RNA_int_get(op->ptr, "lines");
2741
2742 if (lines == 0) {
2743 return OPERATOR_CANCELLED;
2744 }
2745
2746 space_text_screen_skip(st, region, lines * 3);
2747
2749
2750 return OPERATOR_FINISHED;
2751}
2752
2753static void text_scroll_apply(bContext *C, wmOperator *op, const wmEvent *event)
2754{
2756 TextScroll *tsc = static_cast<TextScroll *>(op->customdata);
2757 const int mval[2] = {event->xy[0], event->xy[1]};
2758
2760
2761 /* compute mouse move distance */
2762 if (tsc->is_first) {
2763 copy_v2_v2_int(tsc->mval_prev, mval);
2764 tsc->is_first = false;
2765 }
2766
2767 if (event->type != MOUSEPAN) {
2768 sub_v2_v2v2_int(tsc->mval_delta, mval, tsc->mval_prev);
2769 }
2770
2771 /* accumulate scroll, in float values for events that give less than one
2772 * line offset but taken together should still scroll */
2773 if (!tsc->is_scrollbar) {
2774 tsc->ofs_delta_px[0] -= tsc->mval_delta[0];
2775 tsc->ofs_delta_px[1] += tsc->mval_delta[1];
2776 }
2777 else {
2778 tsc->ofs_delta_px[1] -= (tsc->mval_delta[1] * st->runtime->scroll_px_per_line) *
2779 tsc->state.size_px[1];
2780 }
2781
2782 for (int i = 0; i < 2; i += 1) {
2783 int lines_from_pixels = tsc->ofs_delta_px[i] / tsc->state.size_px[i];
2784 tsc->ofs_delta[i] += lines_from_pixels;
2785 tsc->ofs_delta_px[i] -= lines_from_pixels * tsc->state.size_px[i];
2786 }
2787
2788 /* The final values need to be calculated from the inputs,
2789 * so clamping and ensuring an unsigned pixel offset doesn't conflict with
2790 * updating the cursor mval_delta. */
2791 int scroll_ofs_new[2] = {
2792 tsc->state.ofs_init[0] + tsc->ofs_delta[0],
2793 tsc->state.ofs_init[1] + tsc->ofs_delta[1],
2794 };
2795 int scroll_ofs_px_new[2] = {
2796 tsc->ofs_delta_px[0],
2797 tsc->ofs_delta_px[1],
2798 };
2799
2800 for (int i = 0; i < 2; i += 1) {
2801 /* Ensure always unsigned (adjusting line/column accordingly). */
2802 while (scroll_ofs_px_new[i] < 0) {
2803 scroll_ofs_px_new[i] += tsc->state.size_px[i];
2804 scroll_ofs_new[i] -= 1;
2805 }
2806
2807 /* Clamp within usable region. */
2808 if (scroll_ofs_new[i] < 0) {
2809 scroll_ofs_new[i] = 0;
2810 scroll_ofs_px_new[i] = 0;
2811 }
2812 else if (scroll_ofs_new[i] >= tsc->state.ofs_max[i]) {
2813 scroll_ofs_new[i] = tsc->state.ofs_max[i];
2814 scroll_ofs_px_new[i] = 0;
2815 }
2816 }
2817
2818 /* Override for word-wrap. */
2819 if (st->wordwrap) {
2820 scroll_ofs_new[0] = 0;
2821 scroll_ofs_px_new[0] = 0;
2822 }
2823
2824 /* Apply to the screen. */
2825 if (scroll_ofs_new[0] != st->left || scroll_ofs_new[1] != st->top ||
2826 /* Horizontal sub-pixel offset currently isn't used. */
2827 /* scroll_ofs_px_new[0] != st->scroll_ofs_px[0] || */
2828 scroll_ofs_px_new[1] != st->runtime->scroll_ofs_px[1])
2829 {
2830
2831 st->left = scroll_ofs_new[0];
2832 st->top = scroll_ofs_new[1];
2833 st->runtime->scroll_ofs_px[0] = scroll_ofs_px_new[0];
2834 st->runtime->scroll_ofs_px[1] = scroll_ofs_px_new[1];
2836 }
2837
2838 tsc->mval_prev[0] = mval[0];
2839 tsc->mval_prev[1] = mval[1];
2840}
2841
2842static void scroll_exit(bContext *C, wmOperator *op)
2843{
2845 TextScroll *tsc = static_cast<TextScroll *>(op->customdata);
2846
2847 st->flags &= ~ST_SCROLL_SELECT;
2848
2849 if (st->runtime->scroll_ofs_px[1] > tsc->state.size_px[1] / 2) {
2850 st->top += 1;
2851 }
2852
2853 st->runtime->scroll_ofs_px[0] = 0;
2854 st->runtime->scroll_ofs_px[1] = 0;
2856
2857 MEM_freeN(op->customdata);
2858}
2859
2860static int text_scroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
2861{
2862 TextScroll *tsc = static_cast<TextScroll *>(op->customdata);
2864 ARegion *region = CTX_wm_region(C);
2865
2866 switch (event->type) {
2867 case MOUSEMOVE:
2868 if (tsc->zone == SCROLLHANDLE_BAR) {
2869 text_scroll_apply(C, op, event);
2870 }
2871 break;
2872 case LEFTMOUSE:
2873 case RIGHTMOUSE:
2874 case MIDDLEMOUSE:
2875 if (event->val == KM_RELEASE) {
2878 region,
2879 st->runtime->viewlines *
2880 (tsc->zone == SCROLLHANDLE_MIN_OUTSIDE ? 1 : -1));
2881
2883 }
2884 scroll_exit(C, op);
2885 return OPERATOR_FINISHED;
2886 }
2887 }
2888
2890}
2891
2893{
2894 scroll_exit(C, op);
2895}
2896
2897static int text_scroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2898{
2900 ARegion *region = CTX_wm_region(C);
2901
2902 TextScroll *tsc;
2903
2904 if (RNA_struct_property_is_set(op->ptr, "lines")) {
2905 return text_scroll_exec(C, op);
2906 }
2907
2908 tsc = static_cast<TextScroll *>(MEM_callocN(sizeof(TextScroll), "TextScroll"));
2909 tsc->is_first = true;
2910 tsc->zone = SCROLLHANDLE_BAR;
2911
2912 text_scroll_state_init(tsc, st, region);
2913
2914 op->customdata = tsc;
2915
2916 st->flags |= ST_SCROLL_SELECT;
2917
2918 if (event->type == MOUSEPAN) {
2920
2921 copy_v2_v2_int(tsc->mval_prev, event->xy);
2922 /* Sensitivity of scroll set to 4pix per line/char */
2923 tsc->mval_delta[0] = (event->xy[0] - event->prev_xy[0]) * st->runtime->cwidth_px / 4;
2924 tsc->mval_delta[1] = (event->xy[1] - event->prev_xy[1]) * st->runtime->lheight_px / 4;
2925 tsc->is_first = false;
2926 tsc->is_scrollbar = false;
2927 text_scroll_apply(C, op, event);
2928 scroll_exit(C, op);
2929 return OPERATOR_FINISHED;
2930 }
2931
2933
2935}
2936
2938{
2939 /* identifiers */
2940 ot->name = "Scroll";
2941 /* don't really see the difference between this and
2942 * scroll_bar. Both do basically the same thing (aside from key-maps). */
2943 ot->idname = "TEXT_OT_scroll";
2944
2945 /* api callbacks */
2951
2952 /* flags */
2954
2955 /* properties */
2956 PropertyRNA *prop;
2957 prop = RNA_def_int(
2958 ot->srna, "lines", 1, INT_MIN, INT_MAX, "Lines", "Number of lines to scroll", -100, 100);
2960}
2961
2964/* -------------------------------------------------------------------- */
2969{
2970 /* same as text_region_edit_poll except it works on libdata too */
2972 Text *text = CTX_data_edit_text(C);
2973 ARegion *region = CTX_wm_region(C);
2974
2975 if (!st || !text) {
2976 return false;
2977 }
2978
2979 if (!region || region->regiontype != RGN_TYPE_WINDOW) {
2980 return false;
2981 }
2982
2983 return true;
2984}
2985
2986static int text_scroll_bar_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2987{
2989 ARegion *region = CTX_wm_region(C);
2990 TextScroll *tsc;
2991 const int *mval = event->mval;
2993
2994 if (RNA_struct_property_is_set(op->ptr, "lines")) {
2995 return text_scroll_exec(C, op);
2996 }
2997
2998 /* verify we are in the right zone */
2999 if (mval[0] > st->runtime->scroll_region_handle.xmin &&
3000 mval[0] < st->runtime->scroll_region_handle.xmax)
3001 {
3002 if (mval[1] >= st->runtime->scroll_region_handle.ymin &&
3003 mval[1] <= st->runtime->scroll_region_handle.ymax)
3004 {
3005 /* mouse inside scroll handle */
3006 zone = SCROLLHANDLE_BAR;
3007 }
3008 else if (mval[1] > TXT_SCROLL_SPACE && mval[1] < region->winy - TXT_SCROLL_SPACE) {
3009 if (mval[1] < st->runtime->scroll_region_handle.ymin) {
3011 }
3012 else {
3014 }
3015 }
3016 }
3017
3018 if (zone == SCROLLHANDLE_INVALID_OUTSIDE) {
3019 /* we are outside slider - nothing to do */
3020 return OPERATOR_PASS_THROUGH;
3021 }
3022
3023 tsc = static_cast<TextScroll *>(MEM_callocN(sizeof(TextScroll), "TextScroll"));
3024 tsc->is_first = true;
3025 tsc->is_scrollbar = true;
3026 tsc->zone = zone;
3027 op->customdata = tsc;
3028 st->flags |= ST_SCROLL_SELECT;
3029
3030 text_scroll_state_init(tsc, st, region);
3031
3032 /* jump scroll, works in v2d but needs to be added here too :S */
3033 if (event->type == MIDDLEMOUSE) {
3034 tsc->mval_prev[0] = region->winrct.xmin + BLI_rcti_cent_x(&st->runtime->scroll_region_handle);
3035 tsc->mval_prev[1] = region->winrct.ymin + BLI_rcti_cent_y(&st->runtime->scroll_region_handle);
3036
3037 tsc->is_first = false;
3038 tsc->zone = SCROLLHANDLE_BAR;
3039 text_scroll_apply(C, op, event);
3040 }
3041
3043
3045}
3046
3048{
3049 /* identifiers */
3050 ot->name = "Scrollbar";
3051 /* don't really see the difference between this and
3052 * scroll. Both do basically the same thing (aside from key-maps). */
3053 ot->idname = "TEXT_OT_scroll_bar";
3054
3055 /* api callbacks */
3060
3061 /* flags */
3063
3064 /* properties */
3065 PropertyRNA *prop;
3066 prop = RNA_def_int(
3067 ot->srna, "lines", 1, INT_MIN, INT_MAX, "Lines", "Number of lines to scroll", -100, 100);
3069}
3070
3073/* -------------------------------------------------------------------- */
3079 short mval_prev[2];
3080 wmTimer *timer; /* needed for scrolling when mouse at region bounds */
3081};
3082
3083static int flatten_width(SpaceText *st, const char *str)
3084{
3085 int total = 0;
3086
3087 for (int i = 0; str[i]; i += BLI_str_utf8_size_safe(str + i)) {
3088 const int columns = (str[i] == '\t') ? (st->tabnumber - total % st->tabnumber) :
3090 total += columns;
3091 }
3092
3093 return total;
3094}
3095
3096static int flatten_column_to_offset(SpaceText *st, const char *str, int index)
3097{
3098 int i = 0, j = 0;
3099
3100 while (*(str + j)) {
3101 const int col = (str[j] == '\t') ? (st->tabnumber - i % st->tabnumber) :
3103 if (i + col > index) {
3104 break;
3105 }
3106
3107 i += col;
3108 j += BLI_str_utf8_size_safe(str + j);
3109 }
3110
3111 return j;
3112}
3113
3115 const ARegion *region,
3116 int *y)
3117{
3118 TextLine *linep = static_cast<TextLine *>(st->text->lines.first);
3119 int i, lines;
3120
3121 if (*y < -st->top) {
3122 return nullptr; /* We are beyond the first line... */
3123 }
3124
3125 for (i = -st->top; i <= *y && linep; linep = linep->next, i += lines) {
3126 lines = space_text_get_visible_lines(st, region, linep->line);
3127
3128 if (i + lines > *y) {
3129 /* We found the line matching given vertical 'coordinate',
3130 * now set y relative to this line's start. */
3131 *y -= i;
3132 break;
3133 }
3134 }
3135 return linep;
3136}
3137
3139 const SpaceText *st, const ARegion *region, int x, int y, const bool sel)
3140{
3141 Text *text = st->text;
3142 int max = space_text_wrap_width(st, region); /* column */
3143 int charp = -1; /* mem */
3144 bool found = false; /* flags */
3145
3146 /* Point to line matching given y position, if any. */
3147 TextLine *linep = space_text_get_line_pos_wrapped(st, region, &y);
3148
3149 if (linep) {
3150 int i = 0, start = 0, end = max; /* column */
3151 int j, curs = 0, endj = 0; /* mem */
3152 bool chop = true; /* flags */
3153 char ch;
3154
3155 for (j = 0; !found && ((ch = linep->line[j]) != '\0');
3156 j += BLI_str_utf8_size_safe(linep->line + j))
3157 {
3158 int chars;
3159 const int columns = BLI_str_utf8_char_width_safe(linep->line + j); /* = 1 for tab */
3160
3161 /* Mimic replacement of tabs */
3162 if (ch == '\t') {
3163 chars = st->tabnumber - i % st->tabnumber;
3164 ch = ' ';
3165 }
3166 else {
3167 chars = 1;
3168 }
3169
3170 while (chars--) {
3171 /* Gone too far, go back to last wrap point */
3172 if (y < 0) {
3173 charp = endj;
3174 y = 0;
3175 found = true;
3176 break;
3177 /* Exactly at the cursor */
3178 }
3179 if (y == 0 && i - start <= x && i + columns - start > x) {
3180 /* current position could be wrapped to next line */
3181 /* this should be checked when end of current line would be reached */
3182 charp = curs = j;
3183 found = true;
3184 /* Prepare curs for next wrap */
3185 }
3186 else if (i - end <= x && i + columns - end > x) {
3187 curs = j;
3188 }
3189 if (i + columns - start > max) {
3190 end = std::min(end, i);
3191
3192 if (found) {
3193 /* exact cursor position was found, check if it's still on needed line
3194 * (hasn't been wrapped) */
3195 if (charp > endj && !chop && ch != '\0') {
3196 charp = endj;
3197 }
3198 break;
3199 }
3200
3201 if (chop) {
3202 endj = j;
3203 }
3204 start = end;
3205 end += max;
3206
3207 if (j < linep->len) {
3208 y--;
3209 }
3210
3211 chop = true;
3212 if (y == 0 && i + columns - start > x) {
3213 charp = curs;
3214 found = true;
3215 break;
3216 }
3217 }
3218 else if (ELEM(ch, ' ', '-', '\0')) {
3219 if (found) {
3220 break;
3221 }
3222
3223 if (y == 0 && i + columns - start > x) {
3224 charp = curs;
3225 found = true;
3226 break;
3227 }
3228 end = i + 1;
3229 endj = j;
3230 chop = false;
3231 }
3232 i += columns;
3233 }
3234 }
3235
3236 BLI_assert(y == 0);
3237
3238 if (!found) {
3239 /* On correct line but didn't meet cursor, must be at end */
3240 charp = linep->len;
3241 }
3242 }
3243 else if (y < 0) { /* Before start of text. */
3244 linep = static_cast<TextLine *>(st->text->lines.first);
3245 charp = 0;
3246 }
3247 else { /* Beyond end of text */
3248 linep = static_cast<TextLine *>(st->text->lines.last);
3249 charp = linep->len;
3250 }
3251
3252 BLI_assert(linep && charp != -1);
3253
3254 if (sel) {
3255 text->sell = linep;
3256 text->selc = charp;
3257 }
3258 else {
3259 text->curl = linep;
3260 text->curc = charp;
3261 }
3262}
3263
3265 SpaceText *st, const ARegion *region, int x, int y, const bool sel)
3266{
3267 Text *text = st->text;
3269 y = (region->winy - 2 - y) / TXT_LINE_HEIGHT(st);
3270
3271 x -= TXT_BODY_LEFT(st);
3272 if (x < 0) {
3273 x = 0;
3274 }
3275 x = space_text_pixel_x_to_column(st, x) + st->left;
3276
3277 if (st->wordwrap) {
3278 space_text_cursor_set_to_pos_wrapped(st, region, x, y, sel);
3279 }
3280 else {
3281 TextLine **linep;
3282 int *charp;
3283 int w;
3284
3285 if (sel) {
3286 linep = &text->sell;
3287 charp = &text->selc;
3288 }
3289 else {
3290 linep = &text->curl;
3291 charp = &text->curc;
3292 }
3293
3294 y -= txt_get_span(static_cast<TextLine *>(text->lines.first), *linep) - st->top;
3295
3296 if (y > 0) {
3297 while (y-- != 0) {
3298 if ((*linep)->next) {
3299 *linep = (*linep)->next;
3300 }
3301 }
3302 }
3303 else if (y < 0) {
3304 while (y++ != 0) {
3305 if ((*linep)->prev) {
3306 *linep = (*linep)->prev;
3307 }
3308 }
3309 }
3310
3311 w = flatten_width(st, (*linep)->line);
3312 if (x < w) {
3313 *charp = flatten_column_to_offset(st, (*linep)->line, x);
3314 }
3315 else {
3316 *charp = (*linep)->len;
3317 }
3318 }
3319 if (!sel) {
3320 txt_pop_sel(text);
3321 }
3322}
3323
3325{
3326 if (ssel->timer == nullptr) {
3328 wmWindow *win = CTX_wm_window(C);
3329
3330 ssel->timer = WM_event_timer_add(wm, win, TIMER, 0.02f);
3331 }
3332}
3333
3335{
3336 if (ssel->timer) {
3338 wmWindow *win = CTX_wm_window(C);
3339
3340 WM_event_timer_remove(wm, win, ssel->timer);
3341 }
3342 ssel->timer = nullptr;
3343}
3344
3345static void text_cursor_set_apply(bContext *C, wmOperator *op, const wmEvent *event)
3346{
3348 ARegion *region = CTX_wm_region(C);
3349 SetSelection *ssel = static_cast<SetSelection *>(op->customdata);
3350
3351 if (event->mval[1] < 0 || event->mval[1] > region->winy) {
3352 text_cursor_timer_ensure(C, ssel);
3353
3354 if (event->type == TIMER) {
3355 text_cursor_set_to_pos(st, region, event->mval[0], event->mval[1], true);
3356 ED_space_text_scroll_to_cursor(st, region, false);
3358 }
3359 }
3360 else if (!st->wordwrap && (event->mval[0] < 0 || event->mval[0] > region->winx)) {
3361 text_cursor_timer_ensure(C, ssel);
3362
3363 if (event->type == TIMER) {
3365 st, region, std::clamp(event->mval[0], 0, int(region->winx)), event->mval[1], true);
3366 ED_space_text_scroll_to_cursor(st, region, false);
3368 }
3369 }
3370 else {
3371 text_cursor_timer_remove(C, ssel);
3372
3373 if (event->type != TIMER) {
3374 text_cursor_set_to_pos(st, region, event->mval[0], event->mval[1], true);
3375 ED_space_text_scroll_to_cursor(st, region, false);
3377
3378 ssel->mval_prev[0] = event->mval[0];
3379 ssel->mval_prev[1] = event->mval[1];
3380 }
3381 }
3382}
3383
3385{
3387 SetSelection *ssel = static_cast<SetSelection *>(op->customdata);
3388
3391
3393
3394 text_cursor_timer_remove(C, ssel);
3395 MEM_freeN(ssel);
3396}
3397
3398static int text_selection_set_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3399{
3401 SetSelection *ssel;
3402
3403 if (event->mval[0] >= st->runtime->scroll_region_handle.xmin) {
3404 return OPERATOR_PASS_THROUGH;
3405 }
3406
3407 op->customdata = MEM_callocN(sizeof(SetSelection), "SetCursor");
3408 ssel = static_cast<SetSelection *>(op->customdata);
3409
3410 ssel->mval_prev[0] = event->mval[0];
3411 ssel->mval_prev[1] = event->mval[1];
3412
3413 ssel->sell = txt_get_span(static_cast<TextLine *>(st->text->lines.first), st->text->sell);
3414 ssel->selc = st->text->selc;
3415
3417
3418 text_cursor_set_apply(C, op, event);
3419
3421}
3422
3423static int text_selection_set_modal(bContext *C, wmOperator *op, const wmEvent *event)
3424{
3425 switch (event->type) {
3426 case LEFTMOUSE:
3427 case MIDDLEMOUSE:
3428 case RIGHTMOUSE:
3429 text_cursor_set_exit(C, op);
3430 return OPERATOR_FINISHED;
3431 case TIMER:
3432 case MOUSEMOVE:
3433 text_cursor_set_apply(C, op, event);
3434 break;
3435 }
3436
3438}
3439
3441{
3442 text_cursor_set_exit(C, op);
3443}
3444
3446{
3447 /* identifiers */
3448 ot->name = "Set Selection";
3449 ot->idname = "TEXT_OT_selection_set";
3450 ot->description = "Set text selection";
3451
3452 /* api callbacks */
3457}
3458
3461/* -------------------------------------------------------------------- */
3466{
3468 ARegion *region = CTX_wm_region(C);
3469 int x = RNA_int_get(op->ptr, "x");
3470 int y = RNA_int_get(op->ptr, "y");
3471
3472 text_cursor_set_to_pos(st, region, x, y, false);
3473
3476
3477 return OPERATOR_PASS_THROUGH;
3478}
3479
3480static int text_cursor_set_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3481{
3483
3484 if (event->mval[0] >= st->runtime->scroll_region_handle.xmin) {
3485 return OPERATOR_PASS_THROUGH;
3486 }
3487
3488 RNA_int_set(op->ptr, "x", event->mval[0]);
3489 RNA_int_set(op->ptr, "y", event->mval[1]);
3490
3491 return text_cursor_set_exec(C, op);
3492}
3493
3495{
3496 /* identifiers */
3497 ot->name = "Set Cursor";
3498 ot->idname = "TEXT_OT_cursor_set";
3499 ot->description = "Set cursor position";
3500
3501 /* api callbacks */
3505
3506 /* properties */
3507 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
3508 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
3509}
3510
3513/* -------------------------------------------------------------------- */
3517static int text_line_number_invoke(bContext *C, wmOperator * /*op*/, const wmEvent *event)
3518{
3520 Text *text = CTX_data_edit_text(C);
3521 ARegion *region = CTX_wm_region(C);
3522 const int *mval = event->mval;
3523 double time;
3524 static int jump_to = 0;
3525 static double last_jump = 0;
3526
3528
3529 if (!st->showlinenrs) {
3530 return OPERATOR_PASS_THROUGH;
3531 }
3532
3533 if (!(mval[0] > 2 &&
3534 mval[0] < (TXT_NUMCOL_WIDTH(st) + (TXT_BODY_LPAD * st->runtime->cwidth_px)) &&
3535 mval[1] > 2 && mval[1] < region->winy - 2))
3536 {
3537 return OPERATOR_PASS_THROUGH;
3538 }
3539
3540 const char event_ascii = WM_event_utf8_to_ascii(event);
3541 if (!(event_ascii >= '0' && event_ascii <= '9')) {
3542 return OPERATOR_PASS_THROUGH;
3543 }
3544
3545 time = BLI_time_now_seconds();
3546 if (last_jump < time - 1) {
3547 jump_to = 0;
3548 }
3549
3550 jump_to *= 10;
3551 jump_to += int(event_ascii - '0');
3552
3553 txt_move_toline(text, jump_to - 1, false);
3554 last_jump = time;
3555
3558
3559 return OPERATOR_FINISHED;
3560}
3561
3563{
3564 /* identifiers */
3565 ot->name = "Line Number";
3566 ot->idname = "TEXT_OT_line_number";
3567 ot->description = "The current line number";
3568
3569 /* api callbacks */
3572}
3573
3576/* -------------------------------------------------------------------- */
3581{
3583 Text *text = CTX_data_edit_text(C);
3584 char *str;
3585 int str_len;
3586 bool done = false;
3587 size_t i = 0;
3588 uint code;
3589
3591
3592 str = RNA_string_get_alloc(op->ptr, "text", nullptr, 0, &str_len);
3593
3595
3596 if (st && st->overwrite) {
3597 while (str[i]) {
3598 code = BLI_str_utf8_as_unicode_step_safe(str, str_len, &i);
3599 done |= txt_replace_char(text, code);
3600 }
3601 }
3602 else {
3603 while (str[i]) {
3604 code = BLI_str_utf8_as_unicode_step_safe(str, str_len, &i);
3605 done |= txt_add_char(text, code);
3606 }
3607 }
3608
3609 MEM_freeN(str);
3610
3611 if (!done) {
3612 return OPERATOR_CANCELLED;
3613 }
3614
3615 text_update_line_edited(text->curl);
3616
3619
3620 return OPERATOR_FINISHED;
3621}
3622
3623static int text_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
3624{
3626 int ret;
3627
3628 /* Auto-close variables. */
3629 bool do_auto_close = false;
3630 bool do_auto_close_select = false;
3631
3632 uint auto_close_char_input = 0;
3633 uint auto_close_char_match = 0;
3634 /* Variables needed to restore the selection when auto-closing around an existing selection. */
3635 struct {
3636 TextLine *sell;
3637 TextLine *curl;
3638 int selc;
3639 int curc;
3640 } auto_close_select = {nullptr}, auto_close_select_backup = {nullptr};
3641
3642 /* NOTE: the "text" property is always set from key-map,
3643 * so we can't use #RNA_struct_property_is_set, check the length instead. */
3644 if (!RNA_string_length(op->ptr, "text")) {
3645 /* If Alt/Control/Super are pressed pass through except for utf8 character event
3646 * (when input method are used for utf8 inputs, the user may assign key event
3647 * including Alt/Control/Super like Control-M to commit utf8 string.
3648 * In such case, the modifiers in the utf8 character event make no sense). */
3649 if ((event->modifier & (KM_CTRL | KM_OSKEY)) && !event->utf8_buf[0]) {
3650 return OPERATOR_PASS_THROUGH;
3651 }
3652
3653 char str[BLI_UTF8_MAX + 1];
3654 const size_t len = BLI_str_utf8_size_safe(event->utf8_buf);
3655 memcpy(str, event->utf8_buf, len);
3656 str[len] = '\0';
3657 RNA_string_set(op->ptr, "text", str);
3658
3659 if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) {
3660 auto_close_char_input = BLI_str_utf8_as_unicode_or_error(str);
3661 if (isascii(auto_close_char_input)) {
3662 auto_close_char_match = text_closing_character_pair_get(auto_close_char_input);
3663 if (auto_close_char_match != 0) {
3664 do_auto_close = true;
3665
3666 if (txt_has_sel(st->text) &&
3667 !text_span_is_blank(st->text->sell, st->text->selc, st->text->curl, st->text->curc))
3668 {
3669 do_auto_close_select = true;
3670
3671 auto_close_select_backup.curl = st->text->curl;
3672 auto_close_select_backup.curc = st->text->curc;
3673 auto_close_select_backup.sell = st->text->sell;
3674 auto_close_select_backup.selc = st->text->selc;
3675
3676 /* Movers the cursor to the start of the selection. */
3677 txt_order_cursors(st->text, false);
3678
3679 auto_close_select.curl = st->text->curl;
3680 auto_close_select.curc = st->text->curc;
3681 auto_close_select.sell = st->text->sell;
3682 auto_close_select.selc = st->text->selc;
3683
3684 txt_pop_sel(st->text);
3685 }
3686 }
3687 }
3688 }
3689 }
3690
3691 ret = text_insert_exec(C, op);
3692
3693 if (do_auto_close) {
3694 if (ret == OPERATOR_FINISHED) {
3695 const int auto_close_char_len = BLI_str_utf8_from_unicode_len(auto_close_char_input);
3696 /* If there was a selection, move cursor to the end of it. */
3697 if (do_auto_close_select) {
3698 /* Update the value in-place as needed. */
3699 if (auto_close_select.curl == auto_close_select.sell) {
3700 auto_close_select.selc += auto_close_char_len;
3701 }
3702 /* Move the cursor to the end of the selection. */
3703 st->text->curl = auto_close_select.sell;
3704 st->text->curc = auto_close_select.selc;
3705 txt_pop_sel(st->text);
3706 }
3707
3708 txt_add_char(st->text, auto_close_char_match);
3709 txt_move_left(st->text, false);
3710
3711 /* If there was a selection, restore it. */
3712 if (do_auto_close_select) {
3713 /* Mark the selection as edited. */
3714 if (auto_close_select.curl != auto_close_select.sell) {
3715 TextLine *line = auto_close_select.curl;
3716 do {
3717 line = line->next;
3719 } while (line != auto_close_select.sell);
3720 }
3721 st->text->curl = auto_close_select.curl;
3722 st->text->curc = auto_close_select.curc + auto_close_char_len;
3723 st->text->sell = auto_close_select.sell;
3724 st->text->selc = auto_close_select.selc;
3725 }
3726 }
3727 else {
3728 /* If nothing was done & the selection was removed, restore the selection. */
3729 if (do_auto_close_select) {
3730 st->text->curl = auto_close_select_backup.curl;
3731 st->text->curc = auto_close_select_backup.curc;
3732 st->text->sell = auto_close_select_backup.sell;
3733 st->text->selc = auto_close_select_backup.selc;
3734 }
3735 }
3736 }
3737
3738 /* run the script while editing, evil but useful */
3739 if (ret == OPERATOR_FINISHED && st->live_edit) {
3740 text_run_script(C, nullptr);
3741 }
3742
3743 return ret;
3744}
3745
3747{
3748 PropertyRNA *prop;
3749
3750 /* identifiers */
3751 ot->name = "Insert";
3752 ot->idname = "TEXT_OT_insert";
3753 ot->description = "Insert text at cursor position";
3754
3755 /* api callbacks */
3759
3760 /* flags */
3761 ot->flag = OPTYPE_UNDO;
3762
3763 /* properties */
3764 prop = RNA_def_string(
3765 ot->srna, "text", nullptr, 0, "Text", "Text to insert at the cursor position");
3767}
3768
3771/* -------------------------------------------------------------------- */
3775/* mode */
3776enum {
3779};
3780
3781static int text_find_and_replace(bContext *C, wmOperator *op, short mode)
3782{
3783 Main *bmain = CTX_data_main(C);
3785 Text *text = st->text;
3786 int flags;
3787 int found = 0;
3788 char *tmp;
3789
3790 if (!st->findstr[0]) {
3791 return OPERATOR_CANCELLED;
3792 }
3793
3794 flags = st->flags;
3795 if (flags & ST_FIND_ALL) {
3796 flags &= ~ST_FIND_WRAP;
3797 }
3798
3799 /* Replace current */
3800 if (mode != TEXT_FIND && txt_has_sel(text)) {
3801 tmp = txt_sel_to_buf(text, nullptr);
3802
3803 if (flags & ST_MATCH_CASE) {
3804 found = STREQ(st->findstr, tmp);
3805 }
3806 else {
3807 found = BLI_strcasecmp(st->findstr, tmp) == 0;
3808 }
3809
3810 if (found) {
3811 if (mode == TEXT_REPLACE) {
3813 txt_insert_buf(text, st->replacestr, strlen(st->replacestr));
3814 if (text->curl && text->curl->format) {
3815 MEM_freeN(text->curl->format);
3816 text->curl->format = nullptr;
3817 }
3821 }
3822 }
3823 MEM_freeN(tmp);
3824 tmp = nullptr;
3825 }
3826
3827 /* Find next */
3828 if (txt_find_string(text, st->findstr, flags & ST_FIND_WRAP, flags & ST_MATCH_CASE)) {
3831 }
3832 else if (flags & ST_FIND_ALL) {
3833 if (text->id.next) {
3834 text = st->text = static_cast<Text *>(text->id.next);
3835 }
3836 else {
3837 text = st->text = static_cast<Text *>(bmain->texts.first);
3838 }
3839 txt_move_toline(text, 0, false);
3842 }
3843 else {
3844 if (!found) {
3845 BKE_reportf(op->reports, RPT_INFO, "Text not found: %s", st->findstr);
3846 }
3847 }
3848
3849 return OPERATOR_FINISHED;
3850}
3851
3853{
3854 return text_find_and_replace(C, op, TEXT_FIND);
3855}
3856
3858{
3859 /* identifiers */
3860 ot->name = "Find Next";
3861 ot->idname = "TEXT_OT_find";
3862 ot->description = "Find specified text";
3863
3864 /* api callbacks */
3867}
3868
3871/* -------------------------------------------------------------------- */
3876{
3878 Text *text = st->text;
3879 const int flags = st->flags;
3880 int found = 0;
3881
3882 if (!st->findstr[0]) {
3883 return OPERATOR_CANCELLED;
3884 }
3885
3886 const int orig_curl = BLI_findindex(&text->lines, text->curl);
3887 const int orig_curc = text->curc;
3888 bool has_sel = txt_has_sel(text);
3889
3890 txt_move_toline(text, 0, false);
3891
3892 found = txt_find_string(text, st->findstr, 0, flags & ST_MATCH_CASE);
3893 if (found) {
3895
3896 do {
3897 txt_insert_buf(text, st->replacestr, strlen(st->replacestr));
3898 if (text->curl && text->curl->format) {
3899 MEM_freeN(text->curl->format);
3900 text->curl->format = nullptr;
3901 }
3902 found = txt_find_string(text, st->findstr, 0, flags & ST_MATCH_CASE);
3903 } while (found);
3904
3907 }
3908 else {
3909 /* Restore position */
3910 txt_move_to(text, orig_curl, orig_curc, has_sel);
3911 return OPERATOR_CANCELLED;
3912 }
3913
3914 return OPERATOR_FINISHED;
3915}
3916
3918{
3919 bool replace_all = RNA_boolean_get(op->ptr, "all");
3920 if (replace_all) {
3921 return text_replace_all(C);
3922 }
3923 return text_find_and_replace(C, op, TEXT_REPLACE);
3924}
3925
3927{
3928 /* identifiers */
3929 ot->name = "Replace";
3930 ot->idname = "TEXT_OT_replace";
3931 ot->description = "Replace text with the specified text";
3932
3933 /* api callbacks */
3936
3937 /* flags */
3938 ot->flag = OPTYPE_UNDO;
3939
3940 /* properties */
3941 PropertyRNA *prop;
3942 prop = RNA_def_boolean(ot->srna, "all", false, "Replace All", "Replace all occurrences");
3944}
3945
3948/* -------------------------------------------------------------------- */
3953{
3955 Text *text = CTX_data_edit_text(C);
3956 char *tmp;
3957
3958 tmp = txt_sel_to_buf(text, nullptr);
3959 STRNCPY(st->findstr, tmp);
3960 MEM_freeN(tmp);
3961
3962 if (!st->findstr[0]) {
3963 return OPERATOR_FINISHED;
3964 }
3965
3966 return text_find_and_replace(C, op, TEXT_FIND);
3967}
3968
3970{
3971 /* identifiers */
3972 ot->name = "Find & Set Selection";
3973 ot->idname = "TEXT_OT_find_set_selected";
3974 ot->description = "Find specified text and set as selected";
3975
3976 /* api callbacks */
3979}
3980
3983/* -------------------------------------------------------------------- */
3988{
3990 Text *text = CTX_data_edit_text(C);
3991 char *tmp;
3992
3993 tmp = txt_sel_to_buf(text, nullptr);
3994 STRNCPY(st->replacestr, tmp);
3995 MEM_freeN(tmp);
3996
3997 return OPERATOR_FINISHED;
3998}
3999
4001{
4002 /* identifiers */
4003 ot->name = "Replace & Set Selection";
4004 ot->idname = "TEXT_OT_replace_set_selected";
4005 ot->description = "Replace text with specified text and set as selected";
4006
4007 /* api callbacks */
4010
4011 /* flags */
4012 ot->flag = OPTYPE_UNDO;
4013}
4014
4017/* -------------------------------------------------------------------- */
4022 ReportList *reports,
4023 const char *filepath,
4024 const int line_index,
4025 const int column_index)
4026{
4027 bool success = false;
4028#ifdef WITH_PYTHON
4029 BPy_RunErrInfo err_info = {};
4030 err_info.reports = reports;
4031 err_info.report_prefix = "External editor";
4032
4033 const char *expr_imports[] = {"bl_text_utils", "bl_text_utils.external_editor", "os", nullptr};
4034 std::string expr;
4035 {
4036 std::stringstream expr_stream;
4037 expr_stream << "bl_text_utils.external_editor.open_external_editor(os.fsdecode(b'";
4038 for (const char *ch = filepath; *ch; ch++) {
4039 expr_stream << "\\x" << std::hex << int(*ch);
4040 }
4041 expr_stream << "'), " << std::dec << line_index << ", " << std::dec << column_index << ")";
4042 expr = expr_stream.str();
4043 }
4044
4045 char *expr_result = nullptr;
4046 if (BPY_run_string_as_string(C, expr_imports, expr.c_str(), &err_info, &expr_result)) {
4047 /* No error. */
4048 if (expr_result[0] == '\0') {
4050 reports, RPT_INFO, "See '%s' in the external editor", BLI_path_basename(filepath));
4051 success = true;
4052 }
4053 else {
4054 BKE_report(reports, RPT_ERROR, expr_result);
4055 }
4056 MEM_freeN(expr_result);
4057 }
4058#else
4059 UNUSED_VARS(C, reports, filepath, line_index, column_index);
4060#endif /* WITH_PYTHON */
4061 return success;
4062}
4063
4065 ReportList *reports,
4066 const char *filepath,
4067 const int line_index,
4068 const int column_index)
4069{
4070 Main *bmain = CTX_data_main(C);
4071 Text *text = nullptr;
4072
4073 LISTBASE_FOREACH (Text *, text_iter, &bmain->texts) {
4074 if (text_iter->filepath && BLI_path_cmp(text_iter->filepath, filepath) == 0) {
4075 text = text_iter;
4076 break;
4077 }
4078 }
4079
4080 if (text == nullptr) {
4081 text = BKE_text_load(bmain, filepath, BKE_main_blendfile_path(bmain));
4082 }
4083
4084 if (text == nullptr) {
4085 BKE_reportf(reports, RPT_WARNING, "File '%s' cannot be opened", filepath);
4086 return false;
4087 }
4088
4089 txt_move_to(text, line_index, column_index, false);
4090
4091 /* naughty!, find text area to set, not good behavior
4092 * but since this is a developer tool lets allow it - campbell */
4093 if (!ED_text_activate_in_screen(C, text)) {
4094 BKE_reportf(reports, RPT_INFO, "See '%s' in the text editor", text->id.name + 2);
4095 }
4096
4098
4099 return true;
4100}
4101
4103{
4104 PropertyRNA *prop_filepath = RNA_struct_find_property(op->ptr, "filepath");
4105 PropertyRNA *prop_line = RNA_struct_find_property(op->ptr, "line");
4106 PropertyRNA *prop_column = RNA_struct_find_property(op->ptr, "column");
4107
4108 if (!RNA_property_is_set(op->ptr, prop_filepath)) {
4109 if (const Text *text = CTX_data_edit_text(C)) {
4110 if (text->filepath != nullptr) {
4111 const TextLine *line = text->curl;
4112 const int line_index = BLI_findindex(&text->lines, text->curl);
4113 const int column_index = BLI_str_utf8_offset_to_index(line->line, line->len, text->curc);
4114
4115 RNA_property_string_set(op->ptr, prop_filepath, text->filepath);
4116 RNA_property_int_set(op->ptr, prop_line, line_index);
4117 RNA_property_int_set(op->ptr, prop_column, column_index);
4118 }
4119 }
4120 }
4121
4122 char filepath[FILE_MAX];
4123 RNA_property_string_get(op->ptr, prop_filepath, filepath);
4124 const int line_index = RNA_property_int_get(op->ptr, prop_line);
4125 const int column_index = RNA_property_int_get(op->ptr, prop_column);
4126
4127 if (filepath[0] == '\0') {
4128 BKE_report(op->reports, RPT_WARNING, "File path property not set");
4129 return OPERATOR_CANCELLED;
4130 }
4131
4132 /* Useful to copy-paste from the terminal. */
4133 printf("%s:%d:%d\n", filepath, line_index + 1, column_index);
4134
4135 bool success;
4136 if (U.text_editor[0] != '\0') {
4138 C, op->reports, filepath, line_index, column_index);
4139 }
4140 else {
4142 C, op->reports, filepath, line_index, column_index);
4143 }
4144
4145 return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
4146}
4147
4149{
4150 PropertyRNA *prop;
4151
4152 /* identifiers */
4153 ot->name = "Jump to File at Point";
4154 ot->idname = "TEXT_OT_jump_to_file_at_point";
4155 ot->description = "Jump to a file for the text editor";
4156
4157 /* api callbacks */
4159
4160 /* flags */
4161 ot->flag = 0;
4162
4163 prop = RNA_def_string(ot->srna, "filepath", nullptr, FILE_MAX, "Filepath", "");
4165 prop = RNA_def_int(ot->srna, "line", 0, 0, INT_MAX, "Line", "Line to jump to", 1, 10000);
4167 prop = RNA_def_int(ot->srna, "column", 0, 0, INT_MAX, "Column", "Column to jump to", 1, 10000);
4169}
4170
4173/* -------------------------------------------------------------------- */
4179 {RESOLVE_IGNORE, "IGNORE", 0, "Ignore", ""},
4180 {RESOLVE_RELOAD, "RELOAD", 0, "Reload", ""},
4181 {RESOLVE_SAVE, "SAVE", 0, "Save", ""},
4182 {RESOLVE_MAKE_INTERNAL, "MAKE_INTERNAL", 0, "Make Internal", ""},
4183 {0, nullptr, 0, nullptr, nullptr},
4184};
4185
4187{
4188 Text *text = CTX_data_edit_text(C);
4189
4190 if (!text_edit_poll(C)) {
4191 return false;
4192 }
4193
4194 return ((text->filepath != nullptr) && !(text->flags & TXT_ISMEM));
4195}
4196
4198{
4199 Text *text = CTX_data_edit_text(C);
4200 int resolution = RNA_enum_get(op->ptr, "resolution");
4201
4202 switch (resolution) {
4203 case RESOLVE_RELOAD:
4204 return text_reload_exec(C, op);
4205 case RESOLVE_SAVE:
4206 return text_save_exec(C, op);
4208 return text_make_internal_exec(C, op);
4209 case RESOLVE_IGNORE:
4211 return OPERATOR_FINISHED;
4212 }
4213
4214 return OPERATOR_CANCELLED;
4215}
4216
4217static int text_resolve_conflict_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
4218{
4219 Text *text = CTX_data_edit_text(C);
4220 uiPopupMenu *pup;
4221 uiLayout *layout;
4222
4223 switch (BKE_text_file_modified_check(text)) {
4224 case 1:
4225 if (text->flags & TXT_ISDIRTY) {
4226 /* Modified locally and externally, ah. offer more possibilities. */
4227 pup = UI_popup_menu_begin(
4228 C, IFACE_("File Modified Outside and Inside Blender"), ICON_NONE);
4229 layout = UI_popup_menu_layout(pup);
4230 uiItemEnumO_ptr(layout,
4231 op->type,
4232 IFACE_("Reload from disk (ignore local changes)"),
4233 ICON_NONE,
4234 "resolution",
4236 uiItemEnumO_ptr(layout,
4237 op->type,
4238 IFACE_("Save to disk (ignore outside changes)"),
4239 ICON_NONE,
4240 "resolution",
4241 RESOLVE_SAVE);
4242 uiItemEnumO_ptr(layout,
4243 op->type,
4244 IFACE_("Make text internal (separate copy)"),
4245 ICON_NONE,
4246 "resolution",
4248 UI_popup_menu_end(C, pup);
4249 }
4250 else {
4251 pup = UI_popup_menu_begin(C, IFACE_("File Modified Outside Blender"), ICON_NONE);
4252 layout = UI_popup_menu_layout(pup);
4254 layout, op->type, IFACE_("Reload from disk"), ICON_NONE, "resolution", RESOLVE_RELOAD);
4255 uiItemEnumO_ptr(layout,
4256 op->type,
4257 IFACE_("Make text internal (separate copy)"),
4258 ICON_NONE,
4259 "resolution",
4262 layout, op->type, IFACE_("Ignore"), ICON_NONE, "resolution", RESOLVE_IGNORE);
4263 UI_popup_menu_end(C, pup);
4264 }
4265 break;
4266 case 2:
4267 pup = UI_popup_menu_begin(C, IFACE_("File Deleted Outside Blender"), ICON_NONE);
4268 layout = UI_popup_menu_layout(pup);
4269 uiItemEnumO_ptr(layout,
4270 op->type,
4271 IFACE_("Make text internal"),
4272 ICON_NONE,
4273 "resolution",
4276 layout, op->type, IFACE_("Recreate file"), ICON_NONE, "resolution", RESOLVE_SAVE);
4277 UI_popup_menu_end(C, pup);
4278 break;
4279 }
4280
4281 return OPERATOR_INTERFACE;
4282}
4283
4285{
4286 /* identifiers */
4287 ot->name = "Resolve Conflict";
4288 ot->idname = "TEXT_OT_resolve_conflict";
4289 ot->description = "When external text is out of sync, resolve the conflict";
4290
4291 /* api callbacks */
4295
4296 /* properties */
4298 "resolution",
4301 "Resolution",
4302 "How to solve conflict due to differences in internal and external text");
4303}
4304
4307/* -------------------------------------------------------------------- */
4312{
4313 const Text *text = CTX_data_edit_text(C);
4314 const bool split_lines = RNA_boolean_get(op->ptr, "split_lines");
4315
4316 ED_text_to_object(C, text, split_lines);
4317
4318 return OPERATOR_FINISHED;
4319}
4320
4322{
4323 /* identifiers */
4324 ot->name = "To 3D Object";
4325 ot->idname = "TEXT_OT_to_3d_object";
4326 ot->description = "Create 3D text object from active text data-block";
4327
4328 /* api callbacks */
4331
4332 /* flags */
4334
4335 /* properties */
4337 ot->srna, "split_lines", false, "Split Lines", "Create one object per line in the text");
4338}
4339
SpaceText * CTX_wm_space_text(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Text * CTX_data_edit_text(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
void BKE_id_delete(Main *bmain, void *idv) ATTR_NONNULL()
bool BKE_id_is_editable(const Main *bmain, const ID *id)
Definition lib_id.cc:2456
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:832
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
void txt_move_down(struct Text *text, bool sel)
Definition text.cc:796
void void txt_split_curline(struct Text *text)
Definition text.cc:1652
int txt_setcurr_tab_spaces(struct Text *text, int space)
Definition text.cc:2207
bool txt_has_sel(const struct Text *text)
void txt_move_eof(struct Text *text, bool sel)
Definition text.cc:1071
void txt_delete_selected(struct Text *text)
Definition text.cc:1926
void txt_delete_char(struct Text *text)
Definition text.cc:1764
bool txt_cursor_is_line_end(const struct Text *text)
void txt_sel_line(struct Text *text)
Definition text.cc:1271
void txt_move_toline(struct Text *text, unsigned int line, bool sel)
Definition text.cc:1094
bool txt_replace_char(struct Text *text, unsigned int add)
Definition text.cc:1932
int txt_calc_tab_right(const struct TextLine *tl, int ch)
void txt_backspace_char(struct Text *text)
Definition text.cc:1809
void txt_sel_clear(struct Text *text)
Definition text.cc:1263
void txt_move_left(struct Text *text, bool sel)
Definition text.cc:869
bool txt_add_char(struct Text *text, unsigned int add)
Definition text.cc:1916
int txt_calc_tab_left(const struct TextLine *tl, int ch)
void txt_delete_word(struct Text *text)
Definition text.cc:1802
@ TXT_MOVE_LINE_UP
Definition BKE_text.h:145
@ TXT_MOVE_LINE_DOWN
Definition BKE_text.h:146
void txt_move_bof(struct Text *text, bool sel)
Definition text.cc:1048
void txt_move_right(struct Text *text, bool sel)
Definition text.cc:912
int txt_get_span(const struct TextLine *from, const struct TextLine *to)
int txt_find_string(struct Text *text, const char *findstr, int wrap, int match_case)
Definition text.cc:1594
void txt_move_lines(struct Text *text, int direction)
Definition text.cc:2176
struct Text * BKE_text_add(struct Main *bmain, const char *name)
Definition text.cc:280
void txt_comment(struct Text *text, const char *prefix)
Definition text.cc:2135
struct Text struct Text * BKE_text_load(struct Main *bmain, const char *filepath, const char *relbase) ATTR_NONNULL(1
void txt_jump_left(struct Text *text, bool sel, bool use_init_step)
Definition text.cc:956
void int BKE_text_file_modified_check(const struct Text *text)
void txt_move_eol(struct Text *text, bool sel)
Definition text.cc:1026
void txt_backspace_word(struct Text *text)
Definition text.cc:1851
void txt_jump_right(struct Text *text, bool sel, bool use_init_step)
Definition text.cc:980
void txt_move_up(struct Text *text, bool sel)
Definition text.cc:764
void BKE_text_file_modified_ignore(struct Text *text)
Definition text.cc:558
void txt_move_bol(struct Text *text, bool sel)
Definition text.cc:1004
struct Text * BKE_text_load_ex(struct Main *bmain, const char *filepath, const char *relbase, bool is_internal) ATTR_NONNULL(1
void txt_sel_all(struct Text *text)
Definition text.cc:1254
void txt_order_cursors(struct Text *text, bool reverse)
Definition text.cc:1182
bool txt_unindent(struct Text *text)
Definition text.cc:2165
void txt_indent(struct Text *text)
Definition text.cc:2154
void txt_duplicate_line(struct Text *text)
Definition text.cc:1747
char * txt_sel_to_buf(const struct Text *text, size_t *r_buf_strlen)
void txt_insert_buf(struct Text *text, const char *in_buffer, int in_buffer_len) ATTR_NONNULL(1
void txt_move_to(struct Text *text, unsigned int line, unsigned int ch, bool sel)
Definition text.cc:1099
bool txt_cursor_is_line_start(const struct Text *text)
void txt_pop_sel(struct Text *text)
Definition text.cc:1176
bool BKE_text_reload(struct Text *text)
Definition text.cc:414
bool txt_uncomment(struct Text *text, const char *prefix)
Definition text.cc:2145
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_INLINE
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:350
bool BLI_file_is_writable(const char *filepath) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition fileops_c.cc:291
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int BLI_stat(const char *path, BLI_stat_t *buffer) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
struct stat BLI_stat_t
#define LISTBASE_FOREACH(type, var, list)
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE int max_ii(int a, int b)
MINLINE void sub_v2_v2v2_int(int r[2], const int a[2], const int b[2])
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILE_MAX
#define BLI_path_cmp
BLI_INLINE int BLI_rcti_cent_y(const struct rcti *rct)
Definition BLI_rect.h:176
BLI_INLINE int BLI_rcti_cent_x(const struct rcti *rct)
Definition BLI_rect.h:172
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
#define STRNCPY(dst, src)
Definition BLI_string.h:593
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.c:29
int char char int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
void BLI_str_cursor_step_bounds_utf8(const char *str, int str_maxlen, int pos, int *r_start, int *r_end)
#define BLI_UTF8_MAX
int BLI_str_utf8_char_width_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_str_utf8_size_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
size_t size_t size_t int BLI_str_utf8_offset_to_index(const char *str, size_t str_len, int offset_target) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
const char * BLI_str_find_prev_char_utf8(const char *p, const char *str_start) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1
unsigned int BLI_str_utf8_as_unicode_step_safe(const char *__restrict p, size_t p_len, size_t *__restrict index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
unsigned int unsigned int size_t BLI_str_utf8_from_unicode_len(unsigned int c) ATTR_WARN_UNUSED_RESULT
unsigned int BLI_str_utf8_as_unicode_or_error(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_str_utf8_offset_from_column_with_tabs(const char *str, size_t str_len, int column_target, int tab_width) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_str_utf8_offset_to_column_with_tabs(const char *str, size_t str_len, int offset_target, int tab_width) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
unsigned int uint
Platform independent time functions.
double BLI_time_now_seconds(void)
Definition time.c:65
#define UNUSED_VARS(...)
#define ELEM(...)
#define STREQ(a, b)
#define BLT_I18NCONTEXT_ID_TEXT
#define RPT_(msgid)
#define IFACE_(msgid)
#define DATA_(msgid)
void BPY_pyconstraint_update(Object *owner, bConstraint *con)
Definition stubs.cc:26
void BPY_text_free_code(Text *text)
bool bool BPY_run_text(bContext *C, Text *text, ReportList *reports, bool do_jump) ATTR_NONNULL(1
bool bool bool bool BPY_run_string_as_string(bContext *C, const char *imports[], const char *expr, BPy_RunErrInfo *err_info, char **r_value) ATTR_NONNULL(1
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ CONSTRAINT_TYPE_PYTHON
@ OB_ARMATURE
@ RGN_TYPE_WINDOW
@ FILE_SORT_DEFAULT
@ FILE_SPECIAL
@ FILE_TYPE_TEXT
@ FILE_TYPE_PYSCRIPT
@ FILE_TYPE_FOLDER
@ FILE_DEFAULTDISPLAY
@ ST_FIND_WRAP
@ ST_SCROLL_SELECT
@ ST_MATCH_CASE
@ ST_FIND_ALL
@ TXT_TABSTOSPACES
@ TXT_ISDIRTY
@ TXT_ISMEM
#define TXT_TABSIZE
@ USER_TEXT_EDIT_AUTO_CLOSE
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:708
bool ED_text_activate_in_screen(bContext *C, Text *text)
const char * ED_text_format_comment_line_prefix(Text *text)
UndoStep * ED_text_undo_push_init(bContext *C)
Definition text_undo.cc:249
void ED_space_text_scroll_to_cursor(SpaceText *st, ARegion *region, bool center)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
PropertyFlag
Definition RNA_types.hh:201
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_HIDDEN
Definition RNA_types.hh:239
void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
uiPopupMenu * UI_popup_menu_begin(bContext *C, const char *title, int icon) ATTR_NONNULL()
uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void UI_context_active_but_prop_get_templateID(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop)
void uiItemEnumO_ptr(uiLayout *layout, wmOperatorType *ot, const char *name, int icon, const char *propname, int value)
@ ALERT_ICON_NONE
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:936
@ WM_CAPABILITY_PRIMARY_CLIPBOARD
Definition WM_api.hh:176
@ FILE_OPENFILE
Definition WM_api.hh:945
@ FILE_SAVE
Definition WM_api.hh:946
@ OPTYPE_INTERNAL
Definition WM_types.hh:182
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_GRAB_CURSOR_XY
Definition WM_types.hh:168
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define NC_WINDOW
Definition WM_types.hh:342
#define ND_CURSOR
Definition WM_types.hh:457
@ KM_RELEASE
Definition WM_types.hh:285
#define NA_ADDED
Definition WM_types.hh:552
#define NA_EDITED
Definition WM_types.hh:550
#define NC_TEXT
Definition WM_types.hh:353
#define NA_REMOVED
Definition WM_types.hh:553
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:225
@ KM_CTRL
Definition WM_types.hh:256
@ KM_OSKEY
Definition WM_types.hh:259
#define NEXT_CHAR(fmt)
unsigned int U
Definition btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
#define printf
@ DEL_PREV_WORD
@ DEL_PREV_CHAR
@ DEL_NEXT_WORD
@ DEL_NEXT_CHAR
@ NEXT_LINE
@ LINE_BEGIN
@ PREV_WORD
@ PREV_LINE
@ PREV_CHAR
@ LINE_END
@ PREV_PAGE
@ NEXT_PAGE
@ NEXT_WORD
double time
int len
void ED_text_to_object(bContext *C, const Text *text, const bool split_lines)
Definition editfont.cc:872
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define str(s)
uint col
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
ccl_device_inline float4 select(const int4 mask, const float4 a, const float4 b)
static void update(bNodeTree *ntree)
return ret
void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
int RNA_property_int_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
int RNA_int_get(PointerRNA *ptr, const char *name)
char * RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
int RNA_string_length(PointerRNA *ptr, const char *name)
std::string RNA_property_string_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_id_pointer_create(ID *id)
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value)
PropertyRNA * RNA_def_string(StructOrFunctionRNA *cont_, const char *identifier, const char *default_value, const int maxlen, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
const char * report_prefix
ReportList * reports
void * next
Definition DNA_ID.h:416
void * last
void * first
ListBase texts
Definition BKE_main.hh:227
ListBase objects
Definition BKE_main.hh:212
ListBase constraints
struct bPose * pose
PropertyRNA * prop
Definition RNA_types.hh:49
wmTimer * timer
Definition text_ops.cc:3080
short mval_prev[2]
Definition text_ops.cc:3079
char replacestr[256]
SpaceText_Runtime * runtime
struct Text * text
char findstr[256]
char * line
struct TextLine * prev
struct TextLine * next
bool is_first
Definition text_ops.cc:2700
int mval_delta[2]
Definition text_ops.cc:2698
bool is_scrollbar
Definition text_ops.cc:2701
int ofs_init[2]
Definition text_ops.cc:2707
enum eScrollZone zone
Definition text_ops.cc:2703
int mval_prev[2]
Definition text_ops.cc:2697
struct TextScroll::@527 state
int size_px[2]
Definition text_ops.cc:2709
int ofs_max[2]
Definition text_ops.cc:2708
int ofs_delta[2]
Definition text_ops.cc:2711
int ofs_delta_px[2]
Definition text_ops.cc:2712
ListBase lines
TextLine * curl
TextLine * sell
struct bConstraint * next
struct bPoseChannel * next
ListBase chanbase
short val
Definition WM_types.hh:724
int xy[2]
Definition WM_types.hh:726
char utf8_buf[6]
Definition WM_types.hh:736
int mval[2]
Definition WM_types.hh:728
uint8_t modifier
Definition WM_types.hh:739
short type
Definition WM_types.hh:722
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
PropertyRNA * prop
Definition WM_types.hh:1092
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct ReportList * reports
struct wmOperatorType * type
struct PointerRNA * ptr
int flatten_string(const SpaceText *st, FlattenString *fs, const char *in)
void flatten_string_free(FlattenString *fs)
void space_text_drawcache_tag_update(SpaceText *st, bool full)
#define TXT_SCROLL_SPACE
int space_text_wrap_width(const SpaceText *st, const ARegion *region)
#define TXT_LINE_HEIGHT(st)
#define TXT_NUMCOL_WIDTH(st)
void space_text_update_cursor_moved(bContext *C)
void space_text_update_character_width(SpaceText *st)
@ FILE_TOP
@ FILE_BOTTOM
int space_text_get_visible_lines(const SpaceText *st, const ARegion *region, const char *str)
void space_text_wrap_offset_in_line(const SpaceText *st, const ARegion *region, TextLine *linein, int cursin, int *offl, int *offc)
#define TXT_BODY_LEFT(st)
int space_text_get_total_lines(SpaceText *st, const ARegion *region)
int space_text_get_char_pos(const SpaceText *st, const char *line, int cur)
#define TXT_BODY_LPAD
static int text_scroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:2897
static int text_replace_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:3917
void TEXT_OT_replace_set_selected(wmOperatorType *ot)
Definition text_ops.cc:4000
static int text_resolve_conflict_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition text_ops.cc:4217
static bool text_edit_poll(bContext *C)
Definition text_ops.cc:248
static int text_replace_all(bContext *C)
Definition text_ops.cc:3875
static int text_save_as_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition text_ops.cc:801
static int text_convert_whitespace_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:1448
static bool text_span_is_blank(TextLine *line1, const int line1_char, TextLine *line2, const int line2_char)
Definition text_ops.cc:108
static bool text_data_poll(bContext *C)
Definition text_ops.cc:239
static int text_to_3d_object_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:4311
void TEXT_OT_unlink(wmOperatorType *ot)
Definition text_ops.cc:616
static int text_insert_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:3580
void TEXT_OT_overwrite_toggle(wmOperatorType *ot)
Definition text_ops.cc:2648
static void text_cursor_set_to_pos(SpaceText *st, const ARegion *region, int x, int y, const bool sel)
Definition text_ops.cc:3264
static int text_line_break_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1315
static void space_text_screen_clamp(SpaceText *st, const ARegion *region)
Definition text_ops.cc:2666
void TEXT_OT_reload(wmOperatorType *ot)
Definition text_ops.cc:554
void TEXT_OT_open(wmOperatorType *ot)
Definition text_ops.cc:464
static int text_save_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:744
void text_update_edited(Text *text)
Definition text_ops.cc:319
static int cursor_skip_find_line(const SpaceText *st, const ARegion *region, int lines, TextLine **linep, int *charp, int *rell, int *relc)
Definition text_ops.cc:1873
static void text_open_init(bContext *C, wmOperator *op)
Definition text_ops.cc:385
static int text_resolve_conflict_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:4197
void TEXT_OT_replace(wmOperatorType *ot)
Definition text_ops.cc:3926
static const EnumPropertyItem resolution_items[]
Definition text_ops.cc:4178
eScrollZone
Definition text_ops.cc:2689
@ SCROLLHANDLE_BAR
Definition text_ops.cc:2691
@ SCROLLHANDLE_MIN_OUTSIDE
Definition text_ops.cc:2692
@ SCROLLHANDLE_MAX_OUTSIDE
Definition text_ops.cc:2693
@ SCROLLHANDLE_INVALID_OUTSIDE
Definition text_ops.cc:2690
void TEXT_OT_run_script(wmOperatorType *ot)
Definition text_ops.cc:907
@ TEXT_REPLACE
Definition text_ops.cc:3778
@ TEXT_FIND
Definition text_ops.cc:3777
static int text_run_script(bContext *C, ReportList *reports)
Definition text_ops.cc:855
@ RESOLVE_SAVE
Definition text_ops.cc:4177
@ RESOLVE_MAKE_INTERNAL
Definition text_ops.cc:4177
@ RESOLVE_RELOAD
Definition text_ops.cc:4177
@ RESOLVE_IGNORE
Definition text_ops.cc:4177
static TextLine * space_text_get_line_pos_wrapped(const SpaceText *st, const ARegion *region, int *y)
Definition text_ops.cc:3114
static void text_scroll_apply(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:2753
static void text_scroll_state_init(TextScroll *tsc, SpaceText *st, ARegion *region)
Definition text_ops.cc:2715
void TEXT_OT_copy(wmOperatorType *ot)
Definition text_ops.cc:1131
static int text_toggle_overwrite_exec(bContext *C, wmOperator *)
Definition text_ops.cc:2637
static int text_find_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:3852
static int text_selection_set_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:3423
static int text_copy_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1122
void TEXT_OT_select_line(wmOperatorType *ot)
Definition text_ops.cc:1659
static void text_selection_set_cancel(bContext *C, wmOperator *op)
Definition text_ops.cc:3440
static int text_unlink_exec(bContext *C, wmOperator *)
Definition text_ops.cc:579
static int text_find_and_replace(bContext *C, wmOperator *op, short mode)
Definition text_ops.cc:3781
void TEXT_OT_new(wmOperatorType *ot)
Definition text_ops.cc:364
void TEXT_OT_indent_or_autocomplete(wmOperatorType *ot)
Definition text_ops.cc:1207
void TEXT_OT_scroll(wmOperatorType *ot)
Definition text_ops.cc:2937
static int text_cursor_set_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:3480
void TEXT_OT_line_break(wmOperatorType *ot)
Definition text_ops.cc:1351
static int text_selection_set_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:3398
static int text_delete_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:2516
static bool text_region_edit_poll(bContext *C)
Definition text_ops.cc:281
void TEXT_OT_save_as(wmOperatorType *ot)
Definition text_ops.cc:827
static int text_jump_to_file_at_point_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:4102
static bool text_region_scroll_poll(bContext *C)
Definition text_ops.cc:2968
static void txt_copy_clipboard(const Text *text)
Definition text_ops.cc:1106
static int text_select_word_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1677
static int text_open_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:399
static int move_lines_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:1710
static void text_cursor_set_exit(bContext *C, wmOperator *op)
Definition text_ops.cc:3384
void TEXT_OT_paste(wmOperatorType *ot)
Definition text_ops.cc:1037
static int text_new_exec(bContext *C, wmOperator *)
Definition text_ops.cc:332
static int text_save_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:731
void TEXT_OT_make_internal(wmOperatorType *ot)
Definition text_ops.cc:652
void TEXT_OT_to_3d_object(wmOperatorType *ot)
Definition text_ops.cc:4321
void TEXT_OT_indent(wmOperatorType *ot)
Definition text_ops.cc:1253
bool text_space_edit_poll(bContext *C)
Definition text_ops.cc:264
void TEXT_OT_select_all(wmOperatorType *ot)
Definition text_ops.cc:1627
static void txt_wrap_move_eol(SpaceText *st, ARegion *region, const bool sel)
Definition text_ops.cc:2054
static bool text_jump_to_file_at_point_external(bContext *C, ReportList *reports, const char *filepath, const int line_index, const int column_index)
Definition text_ops.cc:4021
static int text_duplicate_line_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1067
void TEXT_OT_select_word(wmOperatorType *ot)
Definition text_ops.cc:1692
void TEXT_OT_save(wmOperatorType *ot)
Definition text_ops.cc:756
static int text_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition text_ops.cc:605
static int text_replace_set_selected_exec(bContext *C, wmOperator *)
Definition text_ops.cc:3987
BLI_INLINE int space_text_pixel_x_to_column(const SpaceText *st, const int x)
Definition text_ops.cc:206
static int text_scroll_bar_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:2986
void TEXT_OT_move_lines(wmOperatorType *ot)
Definition text_ops.cc:1730
static int text_scroll_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:2735
static int text_make_internal_exec(bContext *C, wmOperator *)
Definition text_ops.cc:638
void TEXT_OT_cursor_set(wmOperatorType *ot)
Definition text_ops.cc:3494
static int text_move_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:2394
static char * buf_tabs_to_spaces(const char *in_buf, const int tab_size, int *r_out_buf_len)
Definition text_ops.cc:152
static int text_cursor_set_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:3465
static int text_comment_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:1372
static int text_cut_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1149
static int text_indent_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1228
static int text_jump_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:2455
static const EnumPropertyItem delete_type_items[]
Definition text_ops.cc:2508
static void space_text_cursor_set_to_pos_wrapped(const SpaceText *st, const ARegion *region, int x, int y, const bool sel)
Definition text_ops.cc:3138
void TEXT_OT_scroll_bar(wmOperatorType *ot)
Definition text_ops.cc:3047
void TEXT_OT_find(wmOperatorType *ot)
Definition text_ops.cc:3857
static int text_move_cursor(bContext *C, int type, bool select)
Definition text_ops.cc:2269
void TEXT_OT_duplicate_line(wmOperatorType *ot)
Definition text_ops.cc:1085
void TEXT_OT_move_select(wmOperatorType *ot)
Definition text_ops.cc:2429
static int flatten_width(SpaceText *st, const char *str)
Definition text_ops.cc:3083
static int text_jump_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition text_ops.cc:2479
static int text_reload_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:498
static int text_run_script_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:894
static void text_cursor_timer_ensure(bContext *C, SetSelection *ssel)
Definition text_ops.cc:3324
static bool text_new_poll(bContext *)
Definition text_ops.cc:234
void TEXT_OT_jump(wmOperatorType *ot)
Definition text_ops.cc:2484
static int text_scroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:2860
static void text_cursor_timer_remove(bContext *C, SetSelection *ssel)
Definition text_ops.cc:3334
static int text_move_select_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:2422
void TEXT_OT_delete(wmOperatorType *ot)
Definition text_ops.cc:2606
void TEXT_OT_selection_set(wmOperatorType *ot)
Definition text_ops.cc:3445
static bool text_scroll_poll(bContext *C)
Definition text_ops.cc:2728
static int flatten_column_to_offset(SpaceText *st, const char *str, int index)
Definition text_ops.cc:3096
static int text_open_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition text_ops.cc:447
static int text_select_line_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1645
static int text_refresh_pyconstraints_exec(bContext *, wmOperator *)
Definition text_ops.cc:928
void TEXT_OT_find_set_selected(wmOperatorType *ot)
Definition text_ops.cc:3969
static int text_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:3623
static void txt_wrap_move_bol(SpaceText *st, ARegion *region, const bool sel)
Definition text_ops.cc:1967
void TEXT_OT_unindent(wmOperatorType *ot)
Definition text_ops.cc:1294
void TEXT_OT_insert(wmOperatorType *ot)
Definition text_ops.cc:3746
@ TO_SPACES
Definition text_ops.cc:1441
@ TO_TABS
Definition text_ops.cc:1441
static const EnumPropertyItem whitespace_type_items[]
Definition text_ops.cc:1442
void TEXT_OT_comment_toggle(wmOperatorType *ot)
Definition text_ops.cc:1409
static int text_reload_invoke(bContext *C, wmOperator *op, const wmEvent *)
Definition text_ops.cc:543
static int space_text_get_cursor_rel(const SpaceText *st, const ARegion *region, TextLine *linein, int rell, int relc)
Definition text_ops.cc:1779
void TEXT_OT_jump_to_file_at_point(wmOperatorType *ot)
Definition text_ops.cc:4148
static void space_text_cursor_skip(const SpaceText *st, const ARegion *region, Text *text, int lines, const bool sel)
Definition text_ops.cc:2226
static char text_closing_character_pair_get(const char character)
Definition text_ops.cc:81
static bool text_unlink_poll(bContext *C)
Definition text_ops.cc:573
static int text_line_number_invoke(bContext *C, wmOperator *, const wmEvent *event)
Definition text_ops.cc:3517
static int text_find_set_selected_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:3952
void TEXT_OT_resolve_conflict(wmOperatorType *ot)
Definition text_ops.cc:4284
void TEXT_OT_move(wmOperatorType *ot)
Definition text_ops.cc:2401
static int text_select_all_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1613
static void space_text_screen_skip(SpaceText *st, ARegion *region, int lines)
Definition text_ops.cc:2682
static void text_open_cancel(bContext *, wmOperator *op)
Definition text_ops.cc:394
void TEXT_OT_line_number(wmOperatorType *ot)
Definition text_ops.cc:3562
void text_update_line_edited(TextLine *line)
Definition text_ops.cc:309
static void test_line_start(char c, bool *r_last_state)
Definition text_ops.cc:66
static int text_save_as_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:775
static bool text_resolve_conflict_poll(bContext *C)
Definition text_ops.cc:4186
void TEXT_OT_convert_whitespace(wmOperatorType *ot)
Definition text_ops.cc:1584
static void text_select_update_primary_clipboard(const Text *text)
Definition text_ops.cc:212
static void txt_wrap_move_down(SpaceText *st, ARegion *region, const bool sel)
Definition text_ops.cc:2180
void TEXT_OT_cut(wmOperatorType *ot)
Definition text_ops.cc:1172
static int text_indent_or_autocomplete_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1193
static int text_unindent_exec(bContext *C, wmOperator *)
Definition text_ops.cc:1274
static bool text_jump_to_file_at_point_internal(bContext *C, ReportList *reports, const char *filepath, const int line_index, const int column_index)
Definition text_ops.cc:4064
void TEXT_OT_refresh_pyconstraints(wmOperatorType *ot)
Definition text_ops.cc:975
static void txt_wrap_move_up(SpaceText *st, ARegion *region, const bool sel)
Definition text_ops.cc:2139
static void text_cursor_set_apply(bContext *C, wmOperator *op, const wmEvent *event)
Definition text_ops.cc:3345
static int text_paste_exec(bContext *C, wmOperator *op)
Definition text_ops.cc:993
static void text_scroll_cancel(bContext *C, wmOperator *op)
Definition text_ops.cc:2892
static void scroll_exit(bContext *C, wmOperator *op)
Definition text_ops.cc:2842
static const EnumPropertyItem move_type_items[]
Definition text_ops.cc:1760
static void txt_write_file(Main *bmain, Text *text, ReportList *reports)
Definition text_ops.cc:673
float max
char WM_event_utf8_to_ascii(const wmEvent *event)
void WM_event_add_fileselect(bContext *C, wmOperator *op)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
@ MOUSEPAN
@ RIGHTMOUSE
@ TIMER
@ MOUSEMOVE
@ LEFTMOUSE
@ MIDDLEMOUSE
PointerRNA * ptr
Definition wm_files.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125
void WM_operator_properties_filesel(wmOperatorType *ot, const int filter, const short type, const eFileSel_Action action, const eFileSel_Flag flag, const short display, const short sort)
int WM_operator_confirm_ex(bContext *C, wmOperator *op, const char *title, const char *message, const char *confirm_text, int icon, bool cancel_default)
int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, std::optional< std::string > title, std::optional< std::string > confirm_text, const bool cancel_default)
void WM_clipboard_text_set(const char *buf, bool selection)
char * WM_clipboard_text_get(bool selection, bool ensure_utf8, int *r_len)
eWM_CapabilitiesFlag WM_capabilities_flag()
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const int event_type, const double time_step)