Blender V4.5
sequencer_text_edit.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstddef>
10
11#include "DNA_sequence_types.h"
12
13#include "BLI_math_matrix.hh"
14#include "BLI_math_vector.hh"
15#include "BLI_string.h"
16#include "BLI_string_utf8.h"
17
18#include "BKE_context.hh"
19#include "BKE_scene.hh"
20
21#include "SEQ_effects.hh"
22#include "SEQ_relations.hh"
23#include "SEQ_select.hh"
24#include "SEQ_time.hh"
25#include "SEQ_transform.hh"
26
27#include "WM_api.hh"
28
29#include "RNA_define.hh"
30
31#include "UI_view2d.hh"
32
33#include "ED_screen.hh"
34
35/* Own include. */
36#include "sequencer_intern.hh"
37
38namespace blender::ed::vse {
39
41{
43 return false;
44 }
45
47 if (strip == nullptr || strip->type != STRIP_TYPE_TEXT || !seq::effects_can_render_text(strip)) {
48 return false;
49 }
50
51 const TextVars *data = static_cast<TextVars *>(strip->effectdata);
52 if (data == nullptr || data->runtime == nullptr) {
53 return false;
54 }
55
56 return true;
57}
58
60{
62 if (strip == nullptr || !sequencer_text_editing_poll(C)) {
63 return false;
64 }
65
67 return false;
68 }
69
70 const Scene *scene = CTX_data_scene(C);
71
72 if (!seq::time_strip_intersects_frame(scene, strip, BKE_scene_frame_get(scene))) {
73 return false;
74 }
75
76 return (strip->flag & SEQ_FLAG_TEXT_EDITING_ACTIVE) != 0;
77}
78
80{
81 cursor_offset = std::clamp(cursor_offset, 0, text->character_count);
82
83 int2 cursor_position{0, 0};
84 for (const seq::LineInfo &line : text->lines) {
85 if (cursor_offset < line.characters.size()) {
86 cursor_position.x = cursor_offset;
87 break;
88 }
89 cursor_offset -= line.characters.size();
90 cursor_position.y += 1;
91 }
92
93 cursor_position.y = std::clamp(cursor_position.y, 0, int(text->lines.size() - 1));
94 cursor_position.x = std::clamp(
95 cursor_position.x, 0, int(text->lines[cursor_position.y].characters.size() - 1));
96
97 return cursor_position;
98}
99
101 const int2 cursor_pos)
102{
103 return text->lines[cursor_pos.y].characters[cursor_pos.x];
104}
105
107 const int cursor_offset)
108{
109 const int2 cursor_pos = strip_text_cursor_offset_to_position(text, cursor_offset);
110 return character_at_cursor_pos_get(text, cursor_pos);
111}
112
113static int cursor_position_to_offset(const TextVarsRuntime *text, int2 cursor_position)
114{
115 return character_at_cursor_pos_get(text, cursor_position).index;
116}
117
119{
120 data->selection_start_offset = 0;
121 data->selection_end_offset = 0;
122}
123
125{
126 /* Ensure, that selection start < selection end. */
127 int sel_start_offset = data->selection_start_offset;
128 int sel_end_offset = data->selection_end_offset;
129 if (sel_start_offset > sel_end_offset) {
130 std::swap(sel_start_offset, sel_end_offset);
131 }
132
133 return IndexRange(sel_start_offset, sel_end_offset - sel_start_offset);
134}
135
137{
139}
140
142{
143 if (!text_has_selection(data)) {
144 return;
145 }
146
147 TextVarsRuntime *text = data->runtime;
149
150 seq::CharInfo char_start = character_at_cursor_offset_get(text, sel_range.first());
151 seq::CharInfo char_end = character_at_cursor_offset_get(text, sel_range.last());
152
153 char *addr_start = const_cast<char *>(char_start.str_ptr);
154 char *addr_end = const_cast<char *>(char_end.str_ptr) + char_end.byte_length;
155
156 std::memmove(addr_start, addr_end, BLI_strnlen(addr_end, sizeof(data->text)) + 1);
157
158 const int2 sel_start = strip_text_cursor_offset_to_position(text, sel_range.first());
159 data->cursor_offset = cursor_position_to_offset(text, sel_start);
161}
162
169
170enum {
181};
182
184 {LINE_BEGIN, "LINE_BEGIN", 0, "Line Begin", ""},
185 {LINE_END, "LINE_END", 0, "Line End", ""},
186 {TEXT_BEGIN, "TEXT_BEGIN", 0, "Text Begin", ""},
187 {TEXT_END, "TEXT_END", 0, "Text End", ""},
188 {PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
189 {NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
190 {PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""},
191 {NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""},
192 {PREV_LINE, "PREVIOUS_LINE", 0, "Previous Line", ""},
193 {NEXT_LINE, "NEXT_LINE", 0, "Next Line", ""},
194 {0, nullptr, 0, nullptr, nullptr},
195};
196
197static int2 cursor_move_by_character(int2 cursor_position, const TextVarsRuntime *text, int offset)
198{
199 const seq::LineInfo &cur_line = text->lines[cursor_position.y];
200 /* Move to next line. */
201 if (cursor_position.x + offset > cur_line.characters.size() - 1 &&
202 cursor_position.y < text->lines.size() - 1)
203 {
204 cursor_position.x = 0;
205 cursor_position.y++;
206 }
207 /* Move to previous line. */
208 else if (cursor_position.x + offset < 0 && cursor_position.y > 0) {
209 cursor_position.y--;
210 cursor_position.x = text->lines[cursor_position.y].characters.size() - 1;
211 }
212 else {
213 cursor_position.x += offset;
214 const int position_max = text->lines[cursor_position.y].characters.size() - 1;
215 cursor_position.x = std::clamp(cursor_position.x, 0, position_max);
216 }
217 return cursor_position;
218}
219
220static int2 cursor_move_by_line(int2 cursor_position, const TextVarsRuntime *text, int offset)
221{
222 const seq::LineInfo &cur_line = text->lines[cursor_position.y];
223 const int cur_pos_x = cur_line.characters[cursor_position.x].position.x;
224
225 const int line_max = text->lines.size() - 1;
226 const int new_line_index = std::clamp(cursor_position.y + offset, 0, line_max);
227 const seq::LineInfo &new_line = text->lines[new_line_index];
228
229 if (cursor_position.y == new_line_index) {
230 return cursor_position;
231 }
232
233 /* Find character in another line closest to current position. */
234 int best_distance = std::numeric_limits<int>::max();
235 int best_character_index = 0;
236
237 for (int i : new_line.characters.index_range()) {
238 seq::CharInfo character = new_line.characters[i];
239 const int distance = std::abs(character.position.x - cur_pos_x);
240 if (distance < best_distance) {
241 best_distance = distance;
242 best_character_index = i;
243 }
244 }
245
246 cursor_position.x = best_character_index;
247 cursor_position.y = new_line_index;
248 return cursor_position;
249}
250
251static int2 cursor_move_line_end(int2 cursor_position, const TextVarsRuntime *text)
252{
253 const seq::LineInfo &cur_line = text->lines[cursor_position.y];
254 cursor_position.x = cur_line.characters.size() - 1;
255 return cursor_position;
256}
257
258static bool is_whitespace_transition(char chr1, char chr2)
259{
260 return ELEM(chr1, ' ', '\t', '\n') && !ELEM(chr2, ' ', '\t', '\n');
261}
262
263static int2 cursor_move_prev_word(int2 cursor_position, const TextVarsRuntime *text)
264{
265 cursor_position = cursor_move_by_character(cursor_position, text, -1);
266
267 while (cursor_position.x > 0 || cursor_position.y > 0) {
268 const seq::CharInfo character = character_at_cursor_pos_get(text, cursor_position);
269 const int2 prev_cursor_pos = cursor_move_by_character(cursor_position, text, -1);
270 const seq::CharInfo prev_character = character_at_cursor_pos_get(text, prev_cursor_pos);
271
272 if (is_whitespace_transition(prev_character.str_ptr[0], character.str_ptr[0])) {
273 break;
274 }
275 cursor_position = prev_cursor_pos;
276 }
277 return cursor_position;
278}
279
280static int2 cursor_move_next_word(int2 cursor_position, const TextVarsRuntime *text)
281{
282 const int maxline = text->lines.size() - 1;
283 const int maxchar = text->lines.last().characters.size() - 1;
284
285 while ((cursor_position.x < maxchar) || (cursor_position.y < maxline)) {
286 const seq::CharInfo character = character_at_cursor_pos_get(text, cursor_position);
287 cursor_position = cursor_move_by_character(cursor_position, text, 1);
288 const seq::CharInfo next_character = character_at_cursor_pos_get(text, cursor_position);
289
290 if (is_whitespace_transition(next_character.str_ptr[0], character.str_ptr[0])) {
291 break;
292 }
293 }
294 return cursor_position;
295}
296
298{
300 TextVars *data = static_cast<TextVars *>(strip->effectdata);
301 const TextVarsRuntime *text = data->runtime;
302
303 if (RNA_boolean_get(op->ptr, "select_text") && !text_has_selection(data)) {
304 data->selection_start_offset = data->cursor_offset;
305 }
306
307 int2 cursor_position = strip_text_cursor_offset_to_position(text, data->cursor_offset);
308
309 switch (RNA_enum_get(op->ptr, "type")) {
310 case PREV_CHAR:
311 cursor_position = cursor_move_by_character(cursor_position, text, -1);
312 break;
313 case NEXT_CHAR:
314 cursor_position = cursor_move_by_character(cursor_position, text, 1);
315 break;
316 case PREV_LINE:
317 cursor_position = cursor_move_by_line(cursor_position, text, -1);
318 break;
319 case NEXT_LINE:
320 cursor_position = cursor_move_by_line(cursor_position, text, 1);
321 break;
322 case LINE_BEGIN:
323 cursor_position.x = 0;
324 break;
325 case LINE_END:
326 cursor_position = cursor_move_line_end(cursor_position, text);
327 break;
328 case TEXT_BEGIN:
329 cursor_position = {0, 0};
330 break;
331 case TEXT_END:
332 cursor_position.y = text->lines.size() - 1;
333 cursor_position = cursor_move_line_end(cursor_position, text);
334 break;
335 case PREV_WORD:
336 cursor_position = cursor_move_prev_word(cursor_position, text);
337 break;
338 case NEXT_WORD:
339 cursor_position = cursor_move_next_word(cursor_position, text);
340 break;
341 }
342
343 data->cursor_offset = cursor_position_to_offset(text, cursor_position);
344 if (RNA_boolean_get(op->ptr, "select_text")) {
345 data->selection_end_offset = data->cursor_offset;
346 }
347
348 if (!RNA_boolean_get(op->ptr, "select_text") ||
349 data->cursor_offset == data->selection_start_offset)
350 {
352 }
353
355 return OPERATOR_FINISHED;
356}
357
359{
360 /* identifiers */
361 ot->name = "Move Cursor";
362 ot->description = "Move cursor in text";
363 ot->idname = "SEQUENCER_OT_text_cursor_move";
364
365 /* API callbacks. */
368
369 /* flags */
371
372 /* properties */
373 RNA_def_enum(ot->srna,
374 "type",
377 "Type",
378 "Where to move cursor to, to make a selection");
379
381 ot->srna, "select_text", false, "Select Text", "Select text while moving cursor");
383}
384
385static bool text_insert(TextVars *data, const char *buf, const size_t buf_len)
386{
387 BLI_assert(strlen(buf) == buf_len);
388 const TextVarsRuntime *text = data->runtime;
389
390 const bool selection_was_deleted = text_has_selection(data);
392
393 const size_t text_str_len = STRNLEN(data->text);
394
395 if (text_str_len + buf_len + 1 > sizeof(data->text)) {
396 return selection_was_deleted;
397 }
398
399 const seq::CharInfo cur_char = character_at_cursor_offset_get(text, data->cursor_offset);
400 char *cursor_addr = const_cast<char *>(cur_char.str_ptr);
401 const size_t move_str_len = BLI_strnlen(cursor_addr, sizeof(data->text)) + 1;
402
403 std::memmove(cursor_addr + buf_len, cursor_addr, move_str_len);
404 std::memcpy(cursor_addr, buf, buf_len);
405
406 data->cursor_offset += 1;
407 return true;
408}
409
411{
413 TextVars *data = static_cast<TextVars *>(strip->effectdata);
414
415 char str[512];
416 RNA_string_get(op->ptr, "string", str);
417
418 const size_t in_buf_len = STRNLEN(str);
419 if (in_buf_len == 0) {
421 }
422
423 if (!text_insert(data, str, in_buf_len)) {
424 return OPERATOR_CANCELLED;
425 }
426
428 return OPERATOR_FINISHED;
429}
430
432 wmOperator *op,
433 const wmEvent *event)
434{
435 char str[6];
437 RNA_string_set(op->ptr, "string", str);
438 return sequencer_text_insert_exec(C, op);
439}
440
442{
443 /* identifiers */
444 ot->name = "Insert Character";
445 ot->description = "Insert text at cursor position";
446 ot->idname = "SEQUENCER_OT_text_insert";
447
448 /* API callbacks. */
452
453 /* flags */
454 ot->flag = OPTYPE_UNDO;
455
456 /* properties */
458 ot->srna, "string", nullptr, 512, "String", "String to be inserted at cursor position");
459}
460
463 {DEL_NEXT_SEL, "NEXT_OR_SELECTION", 0, "Next or Selection", ""},
464 {DEL_PREV_SEL, "PREVIOUS_OR_SELECTION", 0, "Previous or Selection", ""},
465 {0, nullptr, 0, nullptr, nullptr},
466};
467
468static void delete_character(const seq::CharInfo character, const TextVars *data)
469{
470 char *cursor_addr = const_cast<char *>(character.str_ptr);
471 char *next_char_addr = cursor_addr + character.byte_length;
472 std::memmove(cursor_addr, next_char_addr, BLI_strnlen(next_char_addr, sizeof(data->text)) + 1);
473}
474
476{
478 TextVars *data = static_cast<TextVars *>(strip->effectdata);
479 const TextVarsRuntime *text = data->runtime;
480 const int type = RNA_enum_get(op->ptr, "type");
481
485 return OPERATOR_FINISHED;
486 }
487
488 if (type == DEL_NEXT_SEL) {
489 if (data->cursor_offset >= text->character_count) {
490 return OPERATOR_CANCELLED;
491 }
492
494 }
495 if (type == DEL_PREV_SEL) {
496 if (data->cursor_offset == 0) {
497 return OPERATOR_CANCELLED;
498 }
499
501 data->cursor_offset -= 1;
502 }
503
505 return OPERATOR_FINISHED;
506}
507
509{
510 /* identifiers */
511 ot->name = "Delete Character";
512 ot->description = "Delete text at cursor position";
513 ot->idname = "SEQUENCER_OT_text_delete";
514
515 /* API callbacks. */
518
519 /* flags */
520 ot->flag = OPTYPE_UNDO;
521
522 /* properties */
523 RNA_def_enum(ot->srna,
524 "type",
527 "Type",
528 "Which part of the text to delete");
529}
530
532{
534 TextVars *data = static_cast<TextVars *>(strip->effectdata);
535
536 if (!text_insert(data, "\n", 1)) {
537 return OPERATOR_CANCELLED;
538 }
539
541 return OPERATOR_FINISHED;
542}
543
545{
546 /* identifiers */
547 ot->name = "Insert Line Break";
548 ot->description = "Insert line break at cursor position";
549 ot->idname = "SEQUENCER_OT_text_line_break";
550
551 /* API callbacks. */
554
555 /* flags */
556 ot->flag = OPTYPE_UNDO;
557}
558
560{
562 TextVars *data = static_cast<TextVars *>(strip->effectdata);
563 data->selection_start_offset = 0;
564 data->selection_end_offset = data->runtime->character_count;
566 return OPERATOR_FINISHED;
567}
568
570{
571 /* identifiers */
572 ot->name = "Select All";
573 ot->description = "Select all characters";
574 ot->idname = "SEQUENCER_OT_text_select_all";
575
576 /* API callbacks. */
579
580 /* flags */
581 ot->flag = OPTYPE_UNDO;
582}
583
585{
587 TextVars *data = static_cast<TextVars *>(strip->effectdata);
588
589 if (!text_has_selection(data)) {
590 /* Exit edit mode, so text can be translated by mouse. */
592 }
593 else {
595 }
596
598 return OPERATOR_FINISHED;
599}
600
602{
603 /* identifiers */
604 ot->name = "Deselect All";
605 ot->description = "Deselect all characters";
606 ot->idname = "SEQUENCER_OT_text_deselect_all";
607
608 /* API callbacks. */
611
612 /* flags */
613 ot->flag = OPTYPE_UNDO;
614}
615
629
631{
632 /* identifiers */
633 ot->name = "Edit Text";
634 ot->description = "Toggle text editing";
635 ot->idname = "SEQUENCER_OT_text_edit_mode_toggle";
636
637 /* API callbacks. */
640
641 /* flags */
642 ot->flag = OPTYPE_UNDO;
643}
644
645static int find_closest_cursor_offset(const TextVars *data, float2 mouse_loc)
646{
647 const TextVarsRuntime *text = data->runtime;
648 int best_cursor_offset = 0;
649 float best_distance = std::numeric_limits<float>::max();
650
651 for (const seq::LineInfo &line : text->lines) {
652 for (const seq::CharInfo &character : line.characters) {
653 const float distance = math::distance(mouse_loc, character.position);
654 if (distance < best_distance) {
655 best_distance = distance;
656 best_cursor_offset = character.index;
657 }
658 }
659 }
660
661 return best_cursor_offset;
662}
663
664static void cursor_set_by_mouse_position(const bContext *C, const wmEvent *event)
665{
666 const Scene *scene = CTX_data_scene(C);
667 const Strip *strip = seq::select_active_get(scene);
668 TextVars *data = static_cast<TextVars *>(strip->effectdata);
669 const View2D *v2d = UI_view2d_fromcontext(C);
670
671 int2 mval_region;
672 WM_event_drag_start_mval(event, CTX_wm_region(C), mval_region);
673 float2 mouse_loc;
674 UI_view2d_region_to_view(v2d, mval_region.x, mval_region.y, &mouse_loc.x, &mouse_loc.y);
675
676 /* Convert cursor coordinates to domain of CharInfo::position. */
677 const blender::float2 view_offs{-scene->r.xsch / 2.0f, -scene->r.ysch / 2.0f};
678 const float view_aspect = scene->r.xasp / scene->r.yasp;
680 // MSVC 2019 can't decide here for some reason, pick the template for it.
681 transform_mat = blender::math::invert<float, 3>(transform_mat);
682
683 mouse_loc.x /= view_aspect;
684 mouse_loc = blender::math::transform_point(transform_mat, mouse_loc);
685 mouse_loc -= view_offs;
686 data->cursor_offset = find_closest_cursor_offset(data, float2(mouse_loc));
687}
688
690 wmOperator * /*op*/,
691 const wmEvent *event)
692{
693 const Scene *scene = CTX_data_scene(C);
694 const Strip *strip = seq::select_active_get(scene);
695 TextVars *data = static_cast<TextVars *>(strip->effectdata);
696 bool make_selection = false;
697
698 switch (event->type) {
699 case LEFTMOUSE:
700 if (event->val == KM_RELEASE) {
702 if (make_selection) {
703 data->selection_end_offset = data->cursor_offset;
704 }
705 return OPERATOR_FINISHED;
706 }
707 break;
708 case MIDDLEMOUSE:
709 case RIGHTMOUSE:
710 return OPERATOR_FINISHED;
711 case MOUSEMOVE:
712 make_selection = true;
713 if (!text_has_selection(data)) {
714 data->selection_start_offset = data->cursor_offset;
715 }
717 data->selection_end_offset = data->cursor_offset;
718 break;
719 default: {
720 break;
721 }
722 }
723
726}
727
729 wmOperator *op,
730 const wmEvent *event)
731{
732 const Scene *scene = CTX_data_scene(C);
733 Strip *strip = seq::select_active_get(scene);
734 TextVars *data = static_cast<TextVars *>(strip->effectdata);
735 const View2D *v2d = UI_view2d_fromcontext(C);
736
737 int2 mval_region;
738 WM_event_drag_start_mval(event, CTX_wm_region(C), mval_region);
739 float2 mouse_loc;
740 UI_view2d_region_to_view(v2d, mval_region.x, mval_region.y, &mouse_loc.x, &mouse_loc.y);
741
742 if (!strip_point_image_isect(scene, strip, mouse_loc)) {
745 }
746
749
753}
754
756{
757 /* identifiers */
758 ot->name = "Set Cursor";
759 ot->description = "Set cursor position in text";
760 ot->idname = "SEQUENCER_OT_text_cursor_set";
761
762 /* API callbacks. */
766
767 /* flags */
769
770 /* properties */
771
773 ot->srna, "select_text", false, "Select Text", "Select text while moving cursor");
775}
776
777static void text_edit_copy(const TextVars *data)
778{
779 const TextVarsRuntime *text = data->runtime;
780 const IndexRange selection_range = strip_text_selection_range_get(data);
781 const seq::CharInfo start = character_at_cursor_offset_get(text, selection_range.first());
782 const seq::CharInfo end = character_at_cursor_offset_get(text, selection_range.last());
783 const size_t len = end.str_ptr + end.byte_length - start.str_ptr;
784
785 char clipboard_buf[sizeof(data->text)] = {0};
786 memcpy(clipboard_buf, start.str_ptr, math::min(len, sizeof(clipboard_buf)));
787 WM_clipboard_text_set(clipboard_buf, false);
788}
789
791{
793 const TextVars *data = static_cast<TextVars *>(strip->effectdata);
794
795 if (!text_has_selection(data)) {
796 return OPERATOR_CANCELLED;
797 }
798
800
801 return OPERATOR_FINISHED;
802}
803
805{
806 /* identifiers */
807 ot->name = "Copy Text";
808 ot->description = "Copy text to clipboard";
809 ot->idname = "SEQUENCER_OT_text_edit_copy";
810
811 /* API callbacks. */
814
815 /* flags */
816 ot->flag = OPTYPE_UNDO;
817}
818
820{
822 TextVars *data = static_cast<TextVars *>(strip->effectdata);
823 const TextVarsRuntime *text = data->runtime;
824
825 int clipboard_len;
826 char *clipboard_buf = WM_clipboard_text_get(false, true, &clipboard_len);
827
828 if (clipboard_len == 0) {
829 return OPERATOR_CANCELLED;
830 }
831
833 const int max_str_len = sizeof(data->text) - (STRNLEN(data->text) + 1);
834
835 /* Maximum bytes that can be filled into `data->text`. */
836 const int fillable_len = std::min(clipboard_len, max_str_len);
837
838 /* Truncated string could contain invalid UTF8 sequence, thus ensure the length inserted is
839 * always valid. */
840 size_t valid_str_len;
841 const int extra_offset = BLI_strnlen_utf8_ex(clipboard_buf, fillable_len, &valid_str_len);
842
843 const seq::CharInfo cur_char = character_at_cursor_offset_get(text, data->cursor_offset);
844 char *cursor_addr = const_cast<char *>(cur_char.str_ptr);
845 const size_t move_str_len = BLI_strnlen(cursor_addr, sizeof(data->text)) + 1;
846
847 std::memmove(cursor_addr + valid_str_len, cursor_addr, move_str_len);
848 std::memcpy(cursor_addr, clipboard_buf, valid_str_len);
849
850 data->cursor_offset += extra_offset;
851
852 MEM_freeN(clipboard_buf);
854 return OPERATOR_FINISHED;
855}
856
858{
859 /* identifiers */
860 ot->name = "Paste Text";
861 ot->description = "Paste text from clipboard";
862 ot->idname = "SEQUENCER_OT_text_edit_paste";
863
864 /* API callbacks. */
867
868 /* flags */
869 ot->flag = OPTYPE_UNDO;
870}
871
873{
875 TextVars *data = static_cast<TextVars *>(strip->effectdata);
876
877 if (!text_has_selection(data)) {
878 return OPERATOR_CANCELLED;
879 }
880
883
885 return OPERATOR_FINISHED;
886}
887
889{
890 /* identifiers */
891 ot->name = "Cut Text";
892 ot->description = "Cut text to clipboard";
893 ot->idname = "SEQUENCER_OT_text_edit_cut";
894
895 /* API callbacks. */
898
899 /* flags */
900 ot->flag = OPTYPE_UNDO;
901}
902
903} // namespace blender::ed::vse
Scene * CTX_data_scene(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
float BKE_scene_frame_get(const Scene *scene)
Definition scene.cc:2381
#define BLI_assert(a)
Definition BLI_assert.h:46
int char char int int int int size_t BLI_strnlen(const char *str, size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.cc:923
#define STRNLEN(str)
Definition BLI_string.h:608
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
int BLI_str_utf8_size_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
size_t BLI_strnlen_utf8_ex(const char *strc, size_t strc_maxlen, size_t *r_len_bytes) ATTR_NONNULL(1
#define ELEM(...)
struct TextVarsRuntime TextVarsRuntime
@ STRIP_TYPE_TEXT
@ SEQ_FLAG_TEXT_EDITING_ACTIVE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
bScreen * ED_screen_animation_no_scrub(const wmWindowManager *wm)
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
#define C
Definition RandGen.cpp:29
View2D * UI_view2d_fromcontext(const bContext *C)
Definition view2d.cc:1854
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
Definition view2d.cc:1667
#define ND_SEQUENCER
Definition WM_types.hh:434
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NC_SCENE
Definition WM_types.hh:375
@ KM_RELEASE
Definition WM_types.hh:309
BMesh const char void * data
constexpr int64_t first() const
constexpr int64_t last(const int64_t n=0) const
constexpr bool is_empty() const
#define str(s)
float distance(VecOp< float, D >, VecOp< float, D >) RET
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
blender::IndexRange strip_text_selection_range_get(const TextVars *data)
void SEQUENCER_OT_text_edit_copy(wmOperatorType *ot)
void SEQUENCER_OT_text_line_break(wmOperatorType *ot)
static bool text_insert(TextVars *data, const char *buf, const size_t buf_len)
static void cursor_set_by_mouse_position(const bContext *C, const wmEvent *event)
static wmOperatorStatus sequencer_text_insert_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void SEQUENCER_OT_text_delete(wmOperatorType *ot)
void SEQUENCER_OT_text_edit_cut(wmOperatorType *ot)
static const EnumPropertyItem move_type_items[]
bool sequencer_text_editing_active_poll(bContext *C)
static wmOperatorStatus sequencer_text_edit_mode_toggle_exec(bContext *C, wmOperator *)
static const EnumPropertyItem delete_type_items[]
static void delete_character(const seq::CharInfo character, const TextVars *data)
static wmOperatorStatus sequencer_text_edit_paste_exec(bContext *C, wmOperator *)
void SEQUENCER_OT_text_insert(wmOperatorType *ot)
void SEQUENCER_OT_text_deselect_all(wmOperatorType *ot)
bool sequencer_editing_initialized_and_active(bContext *C)
static wmOperatorStatus sequencer_text_edit_copy_exec(bContext *C, wmOperator *)
static int2 cursor_move_by_line(int2 cursor_position, const TextVarsRuntime *text, int offset)
static void text_editing_update(const bContext *C)
static const seq::CharInfo & character_at_cursor_offset_get(const TextVarsRuntime *text, const int cursor_offset)
void SEQUENCER_OT_text_select_all(wmOperatorType *ot)
static wmOperatorStatus sequencer_text_deselect_all_exec(bContext *C, wmOperator *)
static int2 cursor_move_line_end(int2 cursor_position, const TextVarsRuntime *text)
static bool sequencer_text_editing_poll(bContext *C)
static wmOperatorStatus sequencer_text_cursor_move_exec(bContext *C, wmOperator *op)
static wmOperatorStatus sequencer_text_cursor_set_invoke(bContext *C, wmOperator *op, const wmEvent *event)
blender::int2 strip_text_cursor_offset_to_position(const TextVarsRuntime *text, int cursor_offset)
static wmOperatorStatus sequencer_text_delete_exec(bContext *C, wmOperator *op)
static void text_selection_cancel(TextVars *data)
static int2 cursor_move_next_word(int2 cursor_position, const TextVarsRuntime *text)
static int2 cursor_move_prev_word(int2 cursor_position, const TextVarsRuntime *text)
static bool is_whitespace_transition(char chr1, char chr2)
static wmOperatorStatus sequencer_text_insert_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_text_edit_paste(wmOperatorType *ot)
static void delete_selected_text(TextVars *data)
static int cursor_position_to_offset(const TextVarsRuntime *text, int2 cursor_position)
bool strip_point_image_isect(const Scene *scene, const Strip *strip, float point_view[2])
static const seq::CharInfo & character_at_cursor_pos_get(const TextVarsRuntime *text, const int2 cursor_pos)
static bool text_has_selection(const TextVars *data)
void SEQUENCER_OT_text_cursor_move(wmOperatorType *ot)
static int find_closest_cursor_offset(const TextVars *data, float2 mouse_loc)
static wmOperatorStatus sequencer_text_edit_cut_exec(bContext *C, wmOperator *)
static wmOperatorStatus sequencer_text_select_all_exec(bContext *C, wmOperator *)
static void text_edit_copy(const TextVars *data)
static wmOperatorStatus sequencer_text_line_break_exec(bContext *C, wmOperator *)
static int2 cursor_move_by_character(int2 cursor_position, const TextVarsRuntime *text, int offset)
void SEQUENCER_OT_text_cursor_set(wmOperatorType *ot)
void SEQUENCER_OT_text_edit_mode_toggle(wmOperatorType *ot)
static wmOperatorStatus sequencer_text_cursor_set_modal(bContext *C, wmOperator *, const wmEvent *event)
T distance(const T &a, const T &b)
T min(const T &a, const T &b)
CartesianBasis invert(const CartesianBasis &basis)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
float3x3 image_transform_matrix_get(const Scene *scene, const Strip *strip)
void relations_invalidate_cache_raw(Scene *scene, Strip *strip)
Strip * select_active_get(const Scene *scene)
bool time_strip_intersects_frame(const Scene *scene, const Strip *strip, const int timeline_frame)
bool effects_can_render_text(const Strip *strip)
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
MatBase< float, 3, 3 > float3x3
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
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_flag(PropertyRNA *prop, PropertyFlag flag)
struct RenderData r
void * effectdata
Vector< CharInfo > characters
wmEventType type
Definition WM_types.hh:754
short val
Definition WM_types.hh:756
char utf8_buf[6]
Definition WM_types.hh:768
struct PointerRNA * ptr
i
Definition text_draw.cc:230
uint len
void WM_event_drag_start_mval(const wmEvent *event, const ARegion *region, int r_mval[2])
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ RIGHTMOUSE
@ MOUSEMOVE
@ LEFTMOUSE
@ MIDDLEMOUSE
wmOperatorType * ot
Definition wm_files.cc:4225
void WM_clipboard_text_set(const char *buf, bool selection)
char * WM_clipboard_text_get(bool selection, bool ensure_utf8, int *r_len)