Blender V5.0
space_action.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstdio>
10#include <cstring>
11
12#include "DNA_action_types.h"
14#include "DNA_scene_types.h"
15
16#include "DNA_screen_types.h"
17#include "MEM_guardedalloc.h"
18
19#include "BLI_listbase.h"
20#include "BLI_math_base.h"
21#include "BLI_string_utf8.h"
22#include "BLI_utildefines.h"
23
24#include "BKE_context.hh"
25#include "BKE_lib_query.hh"
26#include "BKE_lib_remap.hh"
27#include "BKE_screen.hh"
28
29#include "RNA_access.hh"
30#include "RNA_define.hh"
31#include "RNA_enum_types.hh"
32
33#include "WM_api.hh"
34#include "WM_message.hh"
35#include "WM_types.hh"
36
37#include "UI_interface.hh"
38#include "UI_resources.hh"
39#include "UI_view2d.hh"
40
41#include "ED_anim_api.hh"
42#include "ED_markers.hh"
43#include "ED_screen.hh"
44#include "ED_space_api.hh"
45#include "ED_time_scrub_ui.hh"
46
47#include "BLO_read_write.hh"
48
49#include "GPU_matrix.hh"
50
51#include "action_intern.hh" /* own include */
52
53/* -------------------------------------------------------------------- */
56
57static SpaceLink *action_create(const ScrArea *area, const Scene *scene)
58{
59 SpaceAction *saction;
60 ARegion *region;
61
62 saction = MEM_callocN<SpaceAction>("initaction");
63 saction->spacetype = SPACE_ACTION;
64
65 const eAnimEdit_Context desired_mode = area ? eAnimEdit_Context(area->butspacetype_subtype) :
67 const bool is_timeline = (desired_mode == SACTCONT_TIMELINE);
68
69 /* This should always set to SACTCONT_DOPESHEET, regardless of what the desired_mode is set to.
70 * Not for fundamental reasons, but to make it safe to call this function with an invalid value
71 * in desired_mode. I (Sybren) have no idea if that's ever going to happen, but in this case I'm
72 * sticking as close as possible to what Blender 4.5 was already doing. Once this function
73 * returns, ED_area_newspace() will call action_space_subtype_set() to set the sub-type. */
74 saction->mode = SACTCONT_DOPESHEET;
77
79 if (is_timeline) {
81 }
82
86
88
89 /* header */
90 region = BKE_area_region_new();
91
92 BLI_addtail(&saction->regionbase, region);
95
96 /* footer */
97 region = BKE_area_region_new();
98
99 BLI_addtail(&saction->regionbase, region);
100 region->regiontype = RGN_TYPE_FOOTER;
102
103 /* channel list region */
104 region = BKE_area_region_new();
105 BLI_addtail(&saction->regionbase, region);
107 region->alignment = RGN_ALIGN_LEFT;
108 /* Channel list is hidden by default in timeline mode, and visible in other modes. */
109 region->flag |= is_timeline ? RGN_FLAG_HIDDEN : 0;
110
111 /* Only need to set scroll settings, as this will use `listview` v2d configuration. */
112 region->v2d.scroll = V2D_SCROLL_BOTTOM;
114
115 /* ui buttons */
116 region = BKE_area_region_new();
117
118 BLI_addtail(&saction->regionbase, region);
119 region->regiontype = RGN_TYPE_UI;
120 region->alignment = RGN_ALIGN_RIGHT;
121
122 /* main region */
123 region = BKE_area_region_new();
124
125 BLI_addtail(&saction->regionbase, region);
126 region->regiontype = RGN_TYPE_WINDOW;
127
128 region->v2d.tot.xmin = float(scene->r.sfra - 10);
129 region->v2d.tot.ymin = float(-area->winy) / 3.0f;
130 region->v2d.tot.xmax = float(scene->r.efra + 10);
131 region->v2d.tot.ymax = 0.0f;
132
133 region->v2d.cur = region->v2d.tot;
134
135 region->v2d.min[0] = 0.0f;
136 region->v2d.min[1] = 0.0f;
137
138 region->v2d.max[0] = MAXFRAMEF;
139 region->v2d.max[1] = FLT_MAX;
140
141 region->v2d.minzoom = 0.01f;
142 region->v2d.maxzoom = 50;
145 region->v2d.keepzoom = V2D_LOCKZOOM_Y;
146 region->v2d.keepofs = V2D_KEEPOFS_Y;
147 region->v2d.align = V2D_ALIGN_NO_POS_Y;
149
150 return (SpaceLink *)saction;
151}
152
153/* Doesn't free the space-link itself. */
154static void action_free(SpaceLink * /*sl*/)
155{
156 // SpaceAction *saction = (SpaceAction *) sl;
157}
158
159/* spacetype; init callback */
160static void action_init(wmWindowManager * /*wm*/, ScrArea *area)
161{
162 SpaceAction *saction = static_cast<SpaceAction *>(area->spacedata.first);
164}
165
167{
168 SpaceAction *sactionn = static_cast<SpaceAction *>(MEM_dupallocN(sl));
169
170 sactionn->runtime = SpaceAction_Runtime{};
171
172 /* clear or remove stuff from old */
173
174 return (SpaceLink *)sactionn;
175}
176
177/* add handlers, stuff you only do once or on area/region changes */
179{
180 wmKeyMap *keymap;
181
182 UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_CUSTOM, region->winx, region->winy);
183
184 /* own keymap */
185 keymap = WM_keymap_ensure(wm->runtime->defaultconf, "Dopesheet", SPACE_ACTION, RGN_TYPE_WINDOW);
187 &region->runtime->handlers, keymap, WM_event_handler_region_v2d_mask_no_marker_poll);
188
189 keymap = WM_keymap_ensure(
190 wm->runtime->defaultconf, "Dopesheet Generic", SPACE_ACTION, RGN_TYPE_WINDOW);
191 WM_event_add_keymap_handler(&region->runtime->handlers, keymap);
192}
193
194static void set_v2d_height(View2D *v2d, const size_t item_count, const bool add_marker_padding)
195{
196 const int height = ANIM_UI_get_channels_total_height(v2d, item_count);
197 float pad_bottom = add_marker_padding ? UI_MARKER_MARGIN_Y : 0;
198 /* Add padding for the collapsed redo panel. */
199 pad_bottom += HEADERY;
200 v2d->tot.ymin = -(height + pad_bottom);
202}
203
204static void action_main_region_draw(const bContext *C, ARegion *region)
205{
206 /* draw entirely, view changes should be handled here */
208 Scene *scene = CTX_data_scene(C);
209 bAnimContext ac;
210 View2D *v2d = &region->v2d;
211 short marker_flag = 0;
212
213 const int min_height = UI_ANIM_MINY;
214
215 /* scrollers */
216 if (region->winy >= UI_ANIM_MINY) {
217 region->v2d.scroll |= V2D_SCROLL_BOTTOM;
218 }
219 else {
220 region->v2d.scroll &= ~V2D_SCROLL_BOTTOM;
221 }
222
223 ListBase anim_data = {nullptr, nullptr};
224 const bool has_anim_context = ANIM_animdata_get_context(C, &ac);
225 if (has_anim_context) {
226 /* Build list of channels to draw. */
229 const size_t items = ANIM_animdata_filter(
230 &ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
231 /* The View2D's height needs to be set before calling UI_view2d_view_ortho because the latter
232 * uses the View2D's `cur` rect which might be modified when setting the height. */
234 }
235
237
238 /* clear and setup matrix */
240
242
243 /* time grid */
244 if (region->winy > min_height) {
246 v2d, scene, saction->flag & SACTION_DRAWTIME, true);
247 }
248
250
251 /* start and end frame */
252 if (region->winy > min_height) {
253 ANIM_draw_framerange(scene, v2d);
254 }
255
256 /* Draw the manually set intended playback frame range highlight in the Action editor. */
257 if (ac.active_action) {
260 }
261
262 /* data */
263 if (has_anim_context) {
264 draw_channel_strips(&ac, saction, region, &anim_data);
265 }
266
267 /* markers */
268 UI_view2d_view_orthoSpecial(region, v2d, true);
269
270 marker_flag = ((ac.markers && (ac.markers != &ac.scene->markers)) ? DRAW_MARKERS_LOCAL : 0) |
272
274 ED_markers_draw(C, marker_flag);
275 }
276
277 /* preview range */
279 ANIM_draw_previewrange(scene, v2d, 0);
280
282
283 /* callback */
286
287 /* reset view matrix */
289
290 /* gizmos */
292
293 /* scrubbing region */
294 const int fps = round_db_to_int(scene->frames_per_second());
295 ED_time_scrub_draw(region, scene, saction->flag & SACTION_DRAWTIME, true, fps);
296}
297
299{
300 /* draw entirely, view changes should be handled here */
301 const SpaceAction *saction = CTX_wm_space_action(C);
302 const Scene *scene = CTX_data_scene(C);
303 const Object *obact = CTX_data_active_object(C);
304 View2D *v2d = &region->v2d;
305
306 /* caches */
308 UI_view2d_view_orthoSpecial(region, v2d, true);
309 timeline_draw_cache(saction, obact, scene);
311
312 /* scrubbing region */
314 region, scene, saction->flag & SACTION_DRAWTIME, region->winy >= UI_ANIM_MINY);
315
316 /* scrollers */
317 const rcti scroller_mask = ED_time_scrub_clamp_scroller_mask(v2d->mask);
318 UI_view2d_scrollers_draw(v2d, &scroller_mask);
319}
320
321/* add handlers, stuff you only do once or on area/region changes */
323{
324 wmKeyMap *keymap;
325
326 /* ensure the 2d view sync works - main region has bottom scroller */
327 region->v2d.scroll = V2D_SCROLL_BOTTOM;
328
329 UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
330
331 /* own keymap */
332 keymap = WM_keymap_ensure(
333 wm->runtime->defaultconf, "Animation Channels", SPACE_EMPTY, RGN_TYPE_WINDOW);
334 WM_event_add_keymap_handler_v2d_mask(&region->runtime->handlers, keymap);
335
336 keymap = WM_keymap_ensure(
337 wm->runtime->defaultconf, "Dopesheet Generic", SPACE_ACTION, RGN_TYPE_WINDOW);
338 WM_event_add_keymap_handler(&region->runtime->handlers, keymap);
339}
340
341static void action_channel_region_draw(const bContext *C, ARegion *region)
342{
343 /* draw entirely, view changes should be handled here */
344 bAnimContext ac;
345 const bool has_valid_animcontext = ANIM_animdata_get_context(C, &ac);
346
347 /* clear and setup matrix */
349
350 if (!has_valid_animcontext) {
351 return;
352 }
353
354 View2D *v2d = &region->v2d;
355
356 ListBase anim_data = {nullptr, nullptr};
357 /* Build list of channels to draw. */
360 const size_t item_count = ANIM_animdata_filter(
361 &ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
362 /* The View2D's height needs to be set before calling UI_view2d_view_ortho because the latter
363 * uses the View2D's `cur` rect which might be modified when setting the height. */
364 set_v2d_height(v2d, item_count, !BLI_listbase_is_empty(ac.markers));
365
367 draw_channel_names((bContext *)C, &ac, region, anim_data);
368
369 /* channel filter next to scrubbing area */
371
372 /* reset view matrix */
374
375 /* no scrollers here */
376 ANIM_animdata_freelist(&anim_data);
377}
378
379/* add handlers, stuff you only do once or on area/region changes */
381{
382 ED_region_header_init(region);
383}
384
385static void action_header_region_draw(const bContext *C, ARegion *region)
386{
387 /* The anim context is not actually used, but this makes sure the action being displayed is up to
388 * date. */
389 bAnimContext ac;
391
392 ED_region_header(C, region);
393}
394
396{
397 ARegion *region = params->region;
398 const wmNotifier *wmn = params->notifier;
399
400 /* context changes */
401 switch (wmn->category) {
402 case NC_ANIMATION:
403 ED_region_tag_redraw(region);
404 break;
405 case NC_SCENE:
406 switch (wmn->data) {
407 case ND_OB_ACTIVE:
408 case ND_FRAME:
409 ED_region_tag_redraw(region);
410 break;
411 }
412 break;
413 case NC_OBJECT:
414 switch (wmn->data) {
415 case ND_BONE_ACTIVE:
416 case ND_BONE_SELECT:
417 case ND_KEYS:
418 ED_region_tag_redraw(region);
419 break;
420 case ND_MODIFIER:
421 if (wmn->action == NA_RENAME) {
422 ED_region_tag_redraw(region);
423 }
424 break;
425 }
426 break;
427 case NC_GPENCIL:
428 if (ELEM(wmn->action, NA_RENAME, NA_SELECTED)) {
429 ED_region_tag_redraw(region);
430 }
431 break;
432 case NC_ID:
433 if (wmn->action == NA_RENAME) {
434 ED_region_tag_redraw(region);
435 }
436 break;
437 default:
438 if (wmn->data == ND_KEYS) {
439 ED_region_tag_redraw(region);
440 }
441 break;
442 }
443}
444
446{
447 wmMsgBus *mbus = params->message_bus;
448 ARegion *region = params->region;
449
450 wmMsgSubscribeValue msg_sub_value_region_tag_redraw{};
451 msg_sub_value_region_tag_redraw.owner = region;
452 msg_sub_value_region_tag_redraw.user_data = region;
453 msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw;
454
455 /* All dope-sheet filter settings, etc. affect the drawing of this editor,
456 * also same applies for all animation-related data-types that may appear here,
457 * so just whitelist the entire structs for updates. */
458 {
459 wmMsgParams_RNA msg_key_params = {{}};
460 StructRNA *type_array[] = {
461 &RNA_DopeSheet, /* Dope-sheet filters. */
462
463 &RNA_ActionGroup, /* channel groups */
464
465 &RNA_FCurve, /* F-Curve */
466 &RNA_Keyframe,
467 &RNA_FCurveSample,
468
469 &RNA_Annotation, /* Grease Pencil */
470 &RNA_AnnotationLayer,
471 &RNA_AnnotationFrame,
472 };
473
474 for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
475 msg_key_params.ptr.type = type_array[i];
477 mbus, &msg_key_params, &msg_sub_value_region_tag_redraw, __func__);
478 }
479 }
480}
481
483{
484 ARegion *region = params->region;
485 const wmNotifier *wmn = params->notifier;
486
487 /* context changes */
488 switch (wmn->category) {
489 case NC_ANIMATION:
490 ED_region_tag_redraw(region);
491 break;
492 case NC_SCENE:
493 switch (wmn->data) {
495 case ND_OB_ACTIVE:
496 case ND_FRAME:
497 case ND_FRAME_RANGE:
498 case ND_MARKERS:
499 ED_region_tag_redraw(region);
500 break;
501 }
502 break;
503 case NC_OBJECT:
504 switch (wmn->data) {
505 case ND_TRANSFORM:
506 /* moving object shouldn't need to redraw action */
507 break;
508 case ND_BONE_ACTIVE:
509 case ND_BONE_SELECT:
511 case ND_KEYS:
512 ED_region_tag_redraw(region);
513 break;
514 }
515 break;
516 case NC_NODE:
517 switch (wmn->action) {
518 case NA_EDITED:
519 ED_region_tag_redraw(region);
520 break;
521 }
522 break;
523 case NC_ID:
524 if (wmn->action == NA_RENAME) {
525 ED_region_tag_redraw(region);
526 }
527 break;
528 case NC_SCREEN:
529 if (ELEM(wmn->data, ND_LAYER)) {
530 ED_region_tag_redraw(region);
531 }
532 break;
533 default:
534 if (wmn->data == ND_KEYS) {
535 ED_region_tag_redraw(region);
536 }
537 break;
538 }
539}
540
542{
543 wmMsgBus *mbus = params->message_bus;
544 Scene *scene = params->scene;
545 ARegion *region = params->region;
546
547 wmMsgSubscribeValue msg_sub_value_region_tag_redraw{};
548 msg_sub_value_region_tag_redraw.owner = region;
549 msg_sub_value_region_tag_redraw.user_data = region;
550 msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw;
551
552 /* Timeline depends on scene properties. */
553 {
554 bool use_preview = (scene->r.flag & SCER_PRV_RANGE);
555 const PropertyRNA *props[] = {
556 use_preview ? &rna_Scene_frame_preview_start : &rna_Scene_frame_start,
557 use_preview ? &rna_Scene_frame_preview_end : &rna_Scene_frame_end,
558 &rna_Scene_use_preview_range,
559 &rna_Scene_frame_current,
560 };
561
562 PointerRNA idptr = RNA_id_pointer_create(&scene->id);
563
564 for (int i = 0; i < ARRAY_SIZE(props); i++) {
565 WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_region_tag_redraw, __func__);
566 }
567 }
568
569 /* Now run the general "channels region" one - since channels and main should be in sync */
571}
572
573/* editor level listener */
575{
576 ScrArea *area = params->area;
577 const wmNotifier *wmn = params->notifier;
578 SpaceAction *saction = (SpaceAction *)area->spacedata.first;
579
580 /* context changes */
581 switch (wmn->category) {
582 case NC_GPENCIL:
583 /* only handle these events for containers in which GPencil frames are displayed */
585 if (wmn->action == NA_EDITED) {
586 ED_area_tag_redraw(area);
587 }
588 else if (wmn->action == NA_SELECTED) {
591 }
592 }
593 break;
594 case NC_ANIMATION:
595 /* For NLA tweak-mode enter/exit, need complete refresh. */
596 if (wmn->data == ND_NLA_ACTCHANGE) {
599 }
600 /* Auto-color only really needs to change when channels are added/removed,
601 * or previously hidden stuff appears
602 * (assume for now that if just adding these works, that will be fine).
603 */
604 else if (((wmn->data == ND_KEYFRAME) && ELEM(wmn->action, NA_ADDED, NA_REMOVED)) ||
605 ((wmn->data == ND_ANIMCHAN) && (wmn->action != NA_SELECTED)))
606 {
608 }
609 /* for simple edits to the curve data though (or just plain selections),
610 * a simple redraw should work
611 * (see #39851 for an example of how this can go wrong)
612 */
613 else {
614 ED_area_tag_redraw(area);
615 }
616 break;
617 case NC_SCENE:
618 switch (wmn->data) {
619 case ND_SEQUENCER:
620 if (wmn->action == NA_SELECTED) {
623 }
624 break;
625 case ND_OB_ACTIVE:
626 case ND_OB_SELECT:
627 /* Selection changed, so force refresh to flush
628 * (needs flag set to do syncing). */
631 break;
632 case ND_RENDER_RESULT:
633 ED_area_tag_redraw(area);
634 break;
635 case ND_FRAME_RANGE:
636 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
637 if (region->regiontype == RGN_TYPE_WINDOW) {
638 Scene *scene = static_cast<Scene *>(wmn->reference);
639 region->v2d.tot.xmin = float(scene->r.sfra - 4);
640 region->v2d.tot.xmax = float(scene->r.efra + 4);
641 break;
642 }
643 }
644 break;
645 default:
646 /* Just redrawing the view will do. */
647 ED_area_tag_redraw(area);
648 break;
649 }
650 break;
651 case NC_OBJECT:
652 switch (wmn->data) {
653 case ND_BONE_SELECT: /* Selection changed, so force refresh to flush
654 * (needs flag set to do syncing). */
655 case ND_BONE_ACTIVE:
658 break;
659 case ND_TRANSFORM:
660 /* moving object shouldn't need to redraw action */
661 break;
662 case ND_POINTCACHE:
663 case ND_MODIFIER:
664 case ND_PARTICLE:
665 break;
666 default: /* just redrawing the view will do */
667 ED_area_tag_redraw(area);
668 break;
669 }
670 break;
671 case NC_MASK:
672 if (saction->mode == SACTCONT_MASK) {
673 switch (wmn->data) {
674 case ND_DATA:
676 ED_area_tag_redraw(area);
677 break;
678 default: /* just redrawing the view will do */
679 ED_area_tag_redraw(area);
680 break;
681 }
682 }
683 break;
684 case NC_NODE:
685 if (wmn->action == NA_SELECTED) {
686 /* selection changed, so force refresh to flush (needs flag set to do syncing) */
689 }
690 break;
691 case NC_SPACE:
692 switch (wmn->data) {
694 ED_area_tag_redraw(area);
695 break;
696 case ND_SPACE_TIME:
697 ED_area_tag_redraw(area);
698 break;
699 case ND_SPACE_CHANGED:
702 break;
703 }
704 break;
705 case NC_WINDOW:
707 /* force redraw/refresh after undo/redo, see: #28962. */
709 }
710 break;
711 case NC_WM:
712 switch (wmn->data) {
713 case ND_FILEREAD:
715 break;
716 }
717 break;
718 }
719}
720
722{
723 ARegion *region = params->region;
724 const wmNotifier *wmn = params->notifier;
725
726 /* context changes */
727 switch (wmn->category) {
728 case NC_SCREEN:
729 break;
730 case NC_SCENE:
731 switch (wmn->data) {
732 case ND_OB_ACTIVE:
733 ED_region_tag_redraw(region);
734 break;
735 }
736 break;
737 case NC_ID:
738 if (wmn->action == NA_RENAME) {
739 ED_region_tag_redraw(region);
740 }
741 break;
742 case NC_ANIMATION:
743 switch (wmn->data) {
744 case ND_ANIMCHAN: /* set of visible animchannels changed */
745 /* NOTE: for now, this should usually just mean that the filters changed
746 * It may be better if we had a dedicated flag for that though
747 */
748 ED_region_tag_redraw(region);
749 break;
750
751 case ND_KEYFRAME: /* new keyframed added -> active action may have changed */
752 // saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
753 ED_region_tag_redraw(region);
754 break;
755 }
756 break;
757 }
758}
759
761{
762 ARegion *region = params->region;
763 const wmNotifier *wmn = params->notifier;
764
765 /* context changes */
766 switch (wmn->category) {
767 case NC_SCREEN:
768 if (wmn->data == ND_ANIMPLAY) {
769 ED_region_tag_redraw(region);
770 }
771 break;
772 case NC_SCENE:
773 switch (wmn->data) {
774 case ND_FRAME:
775 ED_region_tag_redraw(region);
776 break;
777 }
778 break;
779 }
780}
781
783{
784 BLI_assert(params->area->spacetype == SPACE_ACTION);
785 const SpaceAction *saction = static_cast<const SpaceAction *>(params->area->spacedata.first);
786 return saction->mode != SACTCONT_TIMELINE;
787}
788
789/* add handlers, stuff you only do once or on area/region changes */
791{
792 wmKeyMap *keymap;
793
794 ED_region_panels_init(wm, region);
795
796 keymap = WM_keymap_ensure(
797 wm->runtime->defaultconf, "Dopesheet Generic", SPACE_ACTION, RGN_TYPE_WINDOW);
798 WM_event_add_keymap_handler(&region->runtime->handlers, keymap);
799}
800
801static void action_buttons_area_draw(const bContext *C, ARegion *region)
802{
803 ED_region_panels(C, region);
804}
805
807{
808 ARegion *region = params->region;
809 const wmNotifier *wmn = params->notifier;
810
811 /* context changes */
812 switch (wmn->category) {
813 case NC_ANIMATION:
814 ED_region_tag_redraw(region);
815 break;
816 case NC_SCENE:
817 switch (wmn->data) {
818 case ND_OB_ACTIVE:
819 case ND_FRAME:
820 case ND_MARKERS:
821 ED_region_tag_redraw(region);
822 break;
823 }
824 break;
825 case NC_OBJECT:
826 switch (wmn->data) {
827 case ND_BONE_ACTIVE:
828 case ND_BONE_SELECT:
829 case ND_KEYS:
830 ED_region_tag_redraw(region);
831 break;
832 }
833 break;
834 default:
835 if (wmn->data == ND_KEYS) {
836 ED_region_tag_redraw(region);
837 }
838 break;
839 }
840}
841
842static void action_refresh(const bContext *C, ScrArea *area)
843{
844 SpaceAction *saction = (SpaceAction *)area->spacedata.first;
845
846 /* Update the state of the animchannels in response to changes from the data they represent
847 * NOTE: the temp flag is used to indicate when this needs to be done,
848 * and will be cleared once handled. */
850 /* Perform syncing of channel state incl. selection
851 * Active action setting also occurs here
852 * (as part of anim channel filtering in `anim_filter.cc`). */
855
856 /* Tag everything for redraw
857 * - Regions (such as header) need to be manually tagged for redraw too
858 * or else they don't update #28962.
859 */
860 ED_area_tag_redraw(area);
861 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
862 ED_region_tag_redraw(region);
863 }
864 }
865
866 /* region updates? */
867 /* XXX re-sizing y-extents of tot should go here? */
868}
869
870static void action_id_remap(ScrArea * /*area*/,
871 SpaceLink *slink,
872 const blender::bke::id::IDRemapper &mappings)
873{
874 SpaceAction *sact = (SpaceAction *)slink;
875
876 mappings.apply(reinterpret_cast<ID **>(&sact->ads.filter_grp), ID_REMAP_APPLY_DEFAULT);
877 mappings.apply(&sact->ads.source, ID_REMAP_APPLY_DEFAULT);
878}
879
881{
882 SpaceAction *sact = reinterpret_cast<SpaceAction *>(space_link);
883 const int data_flags = BKE_lib_query_foreachid_process_flags_get(data);
884 const bool is_readonly = (data_flags & IDWALK_READONLY) != 0;
885
886 /* NOTE: Could be deduplicated with the #bDopeSheet handling of #SpaceNla and #SpaceGraph. */
889
890 if (!is_readonly) {
891 /* Force recalc of list of channels, potentially updating the active action while we're
892 * at it (as it can only be updated that way) #28962. */
894 }
895}
896
898{
899 SpaceAction *sact = static_cast<SpaceAction *>(area->spacedata.first);
901}
902
903static void action_space_subtype_set(ScrArea *area, int value)
904{
905 SpaceAction *sact = static_cast<SpaceAction *>(area->spacedata.first);
906 if (value == SACTCONT_TIMELINE) {
907 /* Switching to the timeline. Remember what the current mode of the dope sheet is. */
908 if (sact->mode != SACTCONT_TIMELINE) {
909 sact->mode_prev = sact->mode;
910 }
911 sact->mode = SACTCONT_TIMELINE;
912 }
913 else {
914 /* Switching to the 'Dope Sheet' editor, so switch to the last-used mode. Unless that was
915 * Timeline, don't use the 'subtype' switch to go back to that; if the user wanted that, we'd
916 * be in the `if` case above. */
919 }
920}
921
923 EnumPropertyItem **item,
924 int *totitem)
925{
927}
928
930{
931 SpaceAction *sact = static_cast<SpaceAction *>(area->spacedata.first);
934 return item.name;
935}
936
937static int action_space_icon_get(const ScrArea *area)
938{
939 SpaceAction *sact = static_cast<SpaceAction *>(area->spacedata.first);
942 return item.icon;
943}
944
946{
947 SpaceAction *saction = (SpaceAction *)sl;
948 saction->runtime = SpaceAction_Runtime{};
949}
950
952{
953 BLO_write_struct(writer, SpaceAction, sl);
954}
955
957{
958 std::unique_ptr<SpaceType> st = std::make_unique<SpaceType>();
959 ARegionType *art;
960
961 st->spaceid = SPACE_ACTION;
962 STRNCPY_UTF8(st->name, "Action");
963
964 st->create = action_create;
965 st->free = action_free;
966 st->init = action_init;
967 st->duplicate = action_duplicate;
968 st->operatortypes = action_operatortypes;
969 st->keymap = action_keymap;
970 st->listener = action_listener;
971 st->refresh = action_refresh;
972 st->id_remap = action_id_remap;
973 st->foreach_id = action_foreach_id;
974 st->space_subtype_item_extend = action_space_subtype_item_extend;
975 st->space_subtype_get = action_space_subtype_get;
976 st->space_subtype_set = action_space_subtype_set;
977 st->space_name_get = action_space_name_get;
978 st->space_icon_get = action_space_icon_get;
979 st->blend_read_data = action_space_blend_read_data;
980 st->blend_read_after_liblink = nullptr;
981 st->blend_write = action_space_blend_write;
982
983 /* regions: main window */
984 art = MEM_callocN<ARegionType>("spacetype action region");
992
993 BLI_addhead(&st->regiontypes, art);
994
995 /* regions: header */
996 art = MEM_callocN<ARegionType>("spacetype action region");
998 art->prefsizey = HEADERY;
1000
1004
1005 BLI_addhead(&st->regiontypes, art);
1006
1007 /* regions: footer */
1008 art = MEM_callocN<ARegionType>("spacetype action region");
1010 art->prefsizey = HEADERY;
1016
1017 BLI_addhead(&st->regiontypes, art);
1018
1019 /* regions: channels */
1020 art = MEM_callocN<ARegionType>("spacetype action region");
1022 art->prefsizex = 200;
1024
1029
1030 BLI_addhead(&st->regiontypes, art);
1031
1032 /* regions: UI buttons */
1033 art = MEM_callocN<ARegionType>("spacetype action region");
1034 art->regionid = RGN_TYPE_UI;
1041
1042 BLI_addhead(&st->regiontypes, art);
1043
1045
1046 art = ED_area_type_hud(st->spaceid);
1047 BLI_addhead(&st->regiontypes, art);
1048
1049 BKE_spacetype_register(std::move(st));
1050}
1051
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:83
SpaceAction * CTX_wm_space_action(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
@ IDWALK_CB_DIRECT_WEAK_LINK
#define BKE_LIB_FOREACHID_PROCESS_ID(data_, id_, cb_flag_)
LibraryForeachIDFlag BKE_lib_query_foreachid_process_flags_get(const LibraryForeachIDData *data)
Definition lib_query.cc:129
@ IDWALK_READONLY
@ ID_REMAP_APPLY_DEFAULT
void BKE_spacetype_register(std::unique_ptr< SpaceType > st)
Definition screen.cc:282
ARegion * BKE_area_region_new()
Definition screen.cc:387
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_addhead(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:91
MINLINE int max_ii(int a, int b)
MINLINE int round_db_to_int(double a)
#define STRNCPY_UTF8(dst, src)
#define ARRAY_SIZE(arr)
#define ELEM(...)
#define BLO_write_struct(writer, struct_name, data_ptr)
@ ADS_FILTER_SUMMARY
@ ADS_SHOW_SCENE_STRIP_FRAME_RANGE
@ ADS_OVERLAY_SHOW_OVERLAYS
@ TIME_CACHE_PARTICLES
@ TIME_CACHE_RIGIDBODY
@ TIME_CACHE_DYNAMICPAINT
@ TIME_CACHE_SOFTBODY
@ TIME_CACHE_DISPLAY
@ TIME_CACHE_SIMULATION_NODES
@ TIME_CACHE_CLOTH
@ TIME_CACHE_SMOKE
@ ADS_FLAG_SUMMARY_COLLAPSED
eAnimEdit_Context
@ SACTCONT_GPENCIL
@ SACTCONT_TIMELINE
@ SACTCONT_DOPESHEET
@ SACTCONT_MASK
@ SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC
@ SACTION_SHOW_INTERPOLATION
@ SACTION_SHOW_MARKERS
@ SACTION_DRAWTIME
Object groups, one object can be in many groups at once.
#define MAXFRAMEF
@ SCER_PRV_RANGE
#define HEADERY
@ RGN_ALIGN_BOTTOM
@ RGN_ALIGN_LEFT
@ RGN_ALIGN_TOP
@ RGN_ALIGN_RIGHT
@ RGN_TYPE_CHANNELS
@ RGN_TYPE_UI
@ RGN_TYPE_WINDOW
@ RGN_TYPE_FOOTER
@ RGN_TYPE_HEADER
@ RGN_FLAG_HIDDEN
@ SPACE_ACTION
@ SPACE_EMPTY
@ USER_HEADER_BOTTOM
@ V2D_KEEPOFS_Y
@ V2D_VIEWSYNC_AREA_VERTICAL
@ V2D_LOCKZOOM_Y
@ V2D_SCROLL_VERTICAL_HIDE
@ V2D_SCROLL_RIGHT
@ V2D_SCROLL_BOTTOM
@ V2D_SCROLL_HORIZONTAL_HANDLES
@ V2D_ALIGN_NO_POS_Y
eAnimCont_Types
eAnimFilter_Flags
@ ANIMFILTER_DATA_VISIBLE
@ ANIMFILTER_LIST_VISIBLE
@ ANIMFILTER_LIST_CHANNELS
@ DRAW_MARKERS_MARGIN
Definition ED_markers.hh:28
@ DRAW_MARKERS_LOCAL
Definition ED_markers.hh:27
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:693
ARegionType * ED_area_type_hud(int space_type)
void ED_region_panels(const bContext *C, ARegion *region)
Definition area.cc:3609
void ED_region_header(const bContext *C, ARegion *region)
Definition area.cc:3935
void ED_region_header_init(ARegion *region)
Definition area.cc:3950
void ED_area_tag_refresh(ScrArea *area)
Definition area.cc:722
void ED_region_panels_init(wmWindowManager *wm, ARegion *region)
Definition area.cc:3616
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
@ ED_KEYMAP_UI
Definition ED_screen.hh:758
@ ED_KEYMAP_ANIMATION
Definition ED_screen.hh:762
@ ED_KEYMAP_HEADER
Definition ED_screen.hh:764
@ ED_KEYMAP_GIZMO
Definition ED_screen.hh:759
@ ED_KEYMAP_VIEW2D
Definition ED_screen.hh:761
@ ED_KEYMAP_FRAMES
Definition ED_screen.hh:763
@ ED_KEYMAP_FOOTER
Definition ED_screen.hh:765
void ED_region_do_msg_notify_tag_redraw(bContext *C, wmMsgSubscribeKey *msg_key, wmMsgSubscribeValue *msg_val)
Definition area.cc:361
void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
#define REGION_DRAW_POST_VIEW
#define REGION_DRAW_PRE_VIEW
void GPU_matrix_push_projection()
void GPU_matrix_pop_projection()
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
#define UI_SIDEBAR_PANEL_WIDTH
@ TH_BACK
void UI_ThemeClearColor(int colorid)
#define UI_ANIM_MINY
Definition UI_view2d.hh:481
#define UI_MARKER_MARGIN_Y
Definition UI_view2d.hh:478
void UI_view2d_view_orthoSpecial(ARegion *region, View2D *v2d, bool xaxis)
Definition view2d.cc:1136
void UI_view2d_curRect_clamp_y(View2D *v2d)
Definition view2d.cc:844
void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
Definition view2d.cc:1504
void UI_view2d_view_restore(const bContext *C)
Definition view2d.cc:1162
void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
Definition view2d.cc:221
void UI_view2d_view_ortho(const View2D *v2d)
Definition view2d.cc:1095
void UI_view2d_draw_lines_x__discrete_frames_or_seconds(const View2D *v2d, const Scene *scene, bool display_seconds, bool display_minor_lines)
@ V2D_COMMONVIEW_LIST
Definition UI_view2d.hh:35
@ V2D_COMMONVIEW_CUSTOM
Definition UI_view2d.hh:31
@ WM_GIZMOMAP_DRAWSTEP_2D
#define ND_SEQUENCER
Definition WM_types.hh:437
#define NC_WINDOW
Definition WM_types.hh:375
#define NC_ID
Definition WM_types.hh:395
#define NC_NODE
Definition WM_types.hh:394
#define ND_FILEREAD
Definition WM_types.hh:412
#define ND_NLA_ACTCHANGE
Definition WM_types.hh:498
#define ND_SPACE_CHANGED
Definition WM_types.hh:538
#define ND_OB_ACTIVE
Definition WM_types.hh:440
#define ND_RENDER_RESULT
Definition WM_types.hh:446
#define NC_WM
Definition WM_types.hh:374
#define ND_DATA
Definition WM_types.hh:509
#define ND_RENDER_OPTIONS
Definition WM_types.hh:435
#define ND_SPACE_DOPESHEET
Definition WM_types.hh:533
#define NC_ANIMATION
Definition WM_types.hh:388
#define NC_SCREEN
Definition WM_types.hh:377
#define ND_OB_SELECT
Definition WM_types.hh:442
#define ND_ANIMPLAY
Definition WM_types.hh:424
#define NC_SCENE
Definition WM_types.hh:378
#define NA_ADDED
Definition WM_types.hh:586
#define ND_MODIFIER
Definition WM_types.hh:462
#define NA_EDITED
Definition WM_types.hh:584
#define ND_PARTICLE
Definition WM_types.hh:465
#define ND_FRAME_RANGE
Definition WM_types.hh:451
#define ND_MARKERS
Definition WM_types.hh:433
#define ND_FRAME
Definition WM_types.hh:434
#define ND_SPACE_TIME
Definition WM_types.hh:531
#define NA_REMOVED
Definition WM_types.hh:587
#define NC_GPENCIL
Definition WM_types.hh:399
#define ND_BONE_ACTIVE
Definition WM_types.hh:459
#define ND_TRANSFORM
Definition WM_types.hh:456
#define ND_LAYER
Definition WM_types.hh:450
#define ND_BONE_COLLECTION
Definition WM_types.hh:474
#define NC_MASK
Definition WM_types.hh:398
#define ND_KEYS
Definition WM_types.hh:463
#define NA_RENAME
Definition WM_types.hh:588
#define ND_POINTCACHE
Definition WM_types.hh:466
#define ND_BONE_SELECT
Definition WM_types.hh:460
#define ND_KEYFRAME
Definition WM_types.hh:494
#define NC_OBJECT
Definition WM_types.hh:379
#define ND_ANIMCHAN
Definition WM_types.hh:496
#define NC_SPACE
Definition WM_types.hh:392
#define NA_SELECTED
Definition WM_types.hh:589
void action_buttons_register(ARegionType *)
void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region, const ListBase &anim_data)
void timeline_draw_cache(const SpaceAction *saction, const Object *ob, const Scene *scene)
void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region, ListBase *anim_data)
void action_operatortypes()
Definition action_ops.cc:25
void action_keymap(wmKeyConfig *keyconf)
Definition action_ops.cc:92
float ANIM_UI_get_channels_total_height(View2D *v2d, const int item_count)
void ANIM_animdata_freelist(ListBase *anim_data)
Definition anim_deps.cc:463
void ANIM_sync_animchannels_to_data(const bContext *C)
Definition anim_deps.cc:261
void ANIM_draw_action_framerange(AnimData *adt, bAction *action, View2D *v2d, float ymin, float ymax)
Definition anim_draw.cc:207
void ANIM_draw_scene_strip_range(const bContext *C, View2D *v2d)
Definition anim_draw.cc:113
void ANIM_draw_previewrange(const Scene *scene, View2D *v2d, int end_frame_width)
Definition anim_draw.cc:82
void ANIM_draw_framerange(Scene *scene, View2D *v2d)
Definition anim_draw.cc:171
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, const eAnimFilter_Flags filter_mode, void *data, const eAnimCont_Types datatype)
bool ED_markers_region_visible(const ScrArea *area, const ARegion *region)
void ED_markers_draw(const bContext *C, int flag)
#define U
BMesh const char void * data
IDRemapperApplyResult apply(ID **r_id_ptr, IDRemapperApplyOptions options, ID *id_self=nullptr) const
nullptr float
#define filter
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
PointerRNA RNA_id_pointer_create(ID *id)
void RNA_enum_items_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
const EnumPropertyItem rna_enum_space_action_mode_items[]
Definition rna_space.cc:271
static int action_space_subtype_get(ScrArea *area)
static void action_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
static void action_channel_region_init(wmWindowManager *wm, ARegion *region)
static SpaceLink * action_duplicate(SpaceLink *sl)
static void action_id_remap(ScrArea *, SpaceLink *slink, const blender::bke::id::IDRemapper &mappings)
static void action_header_region_init(wmWindowManager *, ARegion *region)
static void action_channel_region_draw(const bContext *C, ARegion *region)
static void action_space_subtype_set(ScrArea *area, int value)
static blender::StringRefNull action_space_name_get(const ScrArea *area)
static SpaceLink * action_create(const ScrArea *area, const Scene *scene)
static void action_space_subtype_item_extend(bContext *, EnumPropertyItem **item, int *totitem)
static void action_refresh(const bContext *C, ScrArea *area)
static void action_main_region_draw(const bContext *C, ARegion *region)
static void action_channel_region_listener(const wmRegionListenerParams *params)
static void action_listener(const wmSpaceTypeListenerParams *params)
static void action_header_region_listener(const wmRegionListenerParams *params)
static void action_header_region_draw(const bContext *C, ARegion *region)
static void action_footer_region_listener(const wmRegionListenerParams *params)
static void action_init(wmWindowManager *, ScrArea *area)
static void saction_channel_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
static void action_space_blend_read_data(BlendDataReader *, SpaceLink *sl)
static void action_main_region_draw_overlay(const bContext *C, ARegion *region)
static bool action_region_poll_hide_in_timeline(const RegionPollParams *params)
static void action_free(SpaceLink *)
static void action_main_region_init(wmWindowManager *wm, ARegion *region)
void ED_spacetype_action()
static void action_buttons_area_init(wmWindowManager *wm, ARegion *region)
static void set_v2d_height(View2D *v2d, const size_t item_count, const bool add_marker_padding)
static void action_space_blend_write(BlendWriter *writer, SpaceLink *sl)
static void action_main_region_listener(const wmRegionListenerParams *params)
static void action_region_listener(const wmRegionListenerParams *params)
static int action_space_icon_get(const ScrArea *area)
static void saction_main_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
static void action_buttons_area_draw(const bContext *C, ARegion *region)
#define FLT_MAX
Definition stdcycles.h:14
bool(* poll)(const RegionPollParams *params)
void(* message_subscribe)(const wmRegionMessageSubscribeParams *params)
void(* listener)(const wmRegionListenerParams *params)
void(* draw)(const bContext *C, ARegion *region)
void(* draw_overlay)(const bContext *C, ARegion *region)
void(* init)(wmWindowManager *wm, ARegion *region)
ARegionRuntimeHandle * runtime
const char * name
Definition RNA_types.hh:661
Definition DNA_ID.h:414
void * first
StructRNA * type
Definition RNA_types.hh:52
struct RenderData r
ListBase markers
ListBase spacedata
short butspacetype_subtype
ListBase regionbase
SpaceActionOverlays overlays
SpaceAction_Runtime runtime
float minzoom
float max[2]
short keepzoom
short keepofs
float min[2]
float maxzoom
ListBase * markers
eAnimCont_Types datatype
bDopeSheet * ads
ID * active_action_user
bAction * active_action
struct Collection * filter_grp
float xmax
float xmin
float ymax
float ymin
unsigned int data
Definition WM_types.hh:358
unsigned int action
Definition WM_types.hh:358
unsigned int category
Definition WM_types.hh:358
void * reference
Definition WM_types.hh:360
WindowManagerRuntimeHandle * runtime
i
Definition text_draw.cc:230
rcti ED_time_scrub_clamp_scroller_mask(const rcti &scroller_mask)
void ED_time_scrub_draw(const ARegion *region, const Scene *scene, bool display_seconds, bool discrete_frames, const int base)
void ED_time_scrub_channel_search_draw(const bContext *C, ARegion *region, bDopeSheet *dopesheet)
void ED_time_scrub_draw_current_frame(const ARegion *region, const Scene *scene, bool display_seconds, bool display_stalk)
wmEventHandler_Keymap * WM_event_add_keymap_handler_poll(ListBase *handlers, wmKeyMap *keymap, EventHandlerPoll poll)
wmEventHandler_Keymap * WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
wmEventHandler_Keymap * WM_event_add_keymap_handler_v2d_mask(ListBase *handlers, wmKeyMap *keymap)
bool WM_event_handler_region_v2d_mask_no_marker_poll(const wmWindow *win, const ScrArea *area, const ARegion *region, const wmEvent *event)
void WM_gizmomap_draw(wmGizmoMap *gzmap, const bContext *C, const eWM_GizmoFlagMapDrawStep drawstep)
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:895
void WM_msg_subscribe_rna_params(wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params, const wmMsgSubscribeValue *msg_val_params, const char *id_repr)
void WM_msg_subscribe_rna(wmMsgBus *mbus, PointerRNA *ptr, const PropertyRNA *prop, const wmMsgSubscribeValue *msg_val_params, const char *id_repr)