Blender V5.0
space_graph.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_anim_types.h"
14#include "DNA_scene_types.h"
15#include "DNA_space_types.h"
16
17#include "MEM_guardedalloc.h"
18
19#include "BLI_listbase.h"
20#include "BLI_math_color.h"
21#include "BLI_math_vector.h"
22#include "BLI_string_utf8.h"
23#include "BLI_utildefines.h"
24
25#include "BKE_context.hh"
26#include "BKE_fcurve.hh"
27#include "BKE_lib_query.hh"
28#include "BKE_lib_remap.hh"
29#include "BKE_screen.hh"
30
31#include "ED_anim_api.hh"
32#include "ED_markers.hh"
33#include "ED_screen.hh"
34#include "ED_space_api.hh"
35#include "ED_time_scrub_ui.hh"
36
37#include "GPU_immediate.hh"
38#include "GPU_state.hh"
39
40#include "WM_api.hh"
41#include "WM_message.hh"
42#include "WM_types.hh"
43
44#include "RNA_access.hh"
45#include "RNA_define.hh"
46#include "RNA_enum_types.hh"
47
48#include "UI_interface.hh"
49#include "UI_resources.hh"
50#include "UI_view2d.hh"
51
52#include "BLO_read_write.hh"
53
54#include "graph_intern.hh" /* own include */
55
56/* ******************** default callbacks for ipo space ***************** */
57
58static SpaceLink *graph_create(const ScrArea * /*area*/, const Scene *scene)
59{
60 ARegion *region;
61 SpaceGraph *sipo;
62
63 /* Graph Editor - general stuff */
64 sipo = MEM_callocN<SpaceGraph>("init graphedit");
65 sipo->spacetype = SPACE_GRAPH;
66
67 /* allocate DopeSheet data for Graph Editor */
68 sipo->ads = MEM_callocN<bDopeSheet>("GraphEdit DopeSheet");
69 sipo->ads->source = (ID *)scene;
70
71 /* settings for making it easier by default to just see what you're interested in tweaking */
73 sipo->flag |= SIPO_SHOW_MARKERS;
74
75 /* header */
76 region = BKE_area_region_new();
77
78 BLI_addtail(&sipo->regionbase, region);
81
82 /* footer */
83 region = BKE_area_region_new();
84
85 BLI_addtail(&sipo->regionbase, region);
88 region->flag = RGN_FLAG_HIDDEN;
89
90 /* channels */
91 region = BKE_area_region_new();
92
93 BLI_addtail(&sipo->regionbase, region);
95 region->alignment = RGN_ALIGN_LEFT;
96
98
99 /* ui buttons */
100 region = BKE_area_region_new();
101
102 BLI_addtail(&sipo->regionbase, region);
103 region->regiontype = RGN_TYPE_UI;
104 region->alignment = RGN_ALIGN_RIGHT;
105
106 /* main region */
107 region = BKE_area_region_new();
108
109 BLI_addtail(&sipo->regionbase, region);
110 region->regiontype = RGN_TYPE_WINDOW;
111
112 region->v2d.tot.xmin = 0.0f;
113 region->v2d.tot.ymin = float(scene->r.sfra) - 10.0f;
114 region->v2d.tot.xmax = float(scene->r.efra);
115 region->v2d.tot.ymax = 10.0f;
116
117 region->v2d.cur = region->v2d.tot;
118
119 region->v2d.min[0] = FLT_MIN;
120 region->v2d.min[1] = FLT_MIN;
121
122 region->v2d.max[0] = MAXFRAMEF;
123 region->v2d.max[1] = FLT_MAX;
124
127
128 region->v2d.keeptot = 0;
129
130 return (SpaceLink *)sipo;
131}
132
133/* Doesn't free the space-link itself. */
134static void graph_free(SpaceLink *sl)
135{
136 SpaceGraph *si = (SpaceGraph *)sl;
137
138 if (si->ads) {
140 MEM_freeN(si->ads);
141 }
142
143 if (si->runtime.ghost_curves.first) {
145 }
146}
147
148/* spacetype; init callback */
149static void graph_init(wmWindowManager *wm, ScrArea *area)
150{
151 SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
152
153 /* Init dope-sheet if non-existent (i.e. for old files). */
154 if (sipo->ads == nullptr) {
155 wmWindow *win = WM_window_find_by_area(wm, area);
156 sipo->ads = MEM_callocN<bDopeSheet>("GraphEdit DopeSheet");
157 sipo->ads->source = win ? (ID *)WM_window_get_active_scene(win) : nullptr;
158 }
159
160 /* force immediate init of any invalid F-Curve colors */
161 /* XXX: but, don't do SIPO_TEMP_NEEDCHANSYNC (i.e. channel select state sync)
162 * as this is run on each region resize; setting this here will cause selection
163 * state to be lost on area/region resizing. #35744.
164 */
166}
167
169{
170 SpaceGraph *sipon = static_cast<SpaceGraph *>(MEM_dupallocN(sl));
171
172 sipon->runtime = SpaceGraph_Runtime{};
173
174 /* clear or remove stuff from old */
175 BLI_duplicatelist(&sipon->runtime.ghost_curves, &((SpaceGraph *)sl)->runtime.ghost_curves);
176 sipon->ads = static_cast<bDopeSheet *>(MEM_dupallocN(sipon->ads));
177
178 return (SpaceLink *)sipon;
179}
180
181/* add handlers, stuff you only do once or on area/region changes */
183{
184 wmKeyMap *keymap;
185
186 UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_CUSTOM, region->winx, region->winy);
187
188 /* own keymap */
189 keymap = WM_keymap_ensure(
190 wm->runtime->defaultconf, "Graph Editor", SPACE_GRAPH, RGN_TYPE_WINDOW);
192 &region->runtime->handlers, keymap, WM_event_handler_region_v2d_mask_no_marker_poll);
193 keymap = WM_keymap_ensure(
194 wm->runtime->defaultconf, "Graph Editor Generic", SPACE_GRAPH, RGN_TYPE_WINDOW);
195 WM_event_add_keymap_handler(&region->runtime->handlers, keymap);
196}
197
198/* Draw a darker area above 1 and below -1. */
199static void draw_normalization_borders(Scene *scene, View2D *v2d)
200{
202
205 format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
206
209
210 if (v2d->cur.ymax >= 1) {
211 immRectf(pos, scene->r.sfra, 1, scene->r.efra, v2d->cur.ymax);
212 }
213 if (v2d->cur.ymin <= -1) {
214 immRectf(pos, scene->r.sfra, v2d->cur.ymin, scene->r.efra, -1);
215 }
216
219}
220
221static void graph_main_region_draw(const bContext *C, ARegion *region)
222{
223 /* draw entirely, view changes should be handled here */
225 Scene *scene = CTX_data_scene(C);
226 bAnimContext ac;
227 View2D *v2d = &region->v2d;
228
229 const int min_height = UI_ANIM_MINY;
230
231 /* clear and setup matrix */
233
235
236 /* In driver mode, both X and Y axes are in the same units as the driven property, and so the
237 * grid size should be independent of the scene's frame rate. */
238 constexpr int driver_step = 10;
239 /* grid */
240 bool display_seconds = (sipo->mode == SIPO_MODE_ANIMATION) && (sipo->flag & SIPO_DRAWTIME);
241 if (region->winy > min_height) {
242 if (sipo->mode == SIPO_MODE_DRIVERS) {
243 UI_view2d_draw_lines_x__values(v2d, driver_step);
244 }
245 else {
246 UI_view2d_draw_lines_x__frames_or_seconds(v2d, scene, display_seconds);
247 }
249 }
250
252
253 /* start and end frame (in F-Curve mode only) */
254 if (sipo->mode != SIPO_MODE_DRIVERS && region->winy > min_height) {
255 ANIM_draw_framerange(scene, v2d);
256 }
257
258 if (sipo->mode == SIPO_MODE_ANIMATION && (sipo->flag & SIPO_NORMALIZE)) {
259 draw_normalization_borders(scene, v2d);
260 }
261
262 /* draw data */
263 if (ANIM_animdata_get_context(C, &ac)) {
264 /* draw ghost curves */
265 graph_draw_ghost_curves(&ac, sipo, region);
266
267 /* draw curves twice - unselected, then selected, so that the are fewer occlusion problems */
268 graph_draw_curves(&ac, sipo, region, 0);
269 graph_draw_curves(&ac, sipo, region, 1);
270
271 /* XXX(ton): the slow way to set tot rect... but for nice sliders needed. */
272 /* Excluding handles from the calculation to save performance. This cuts the time it takes for
273 * this function to run in half which is a major performance bottleneck on heavy scenes. */
275 &ac, &v2d->tot.xmin, &v2d->tot.xmax, &v2d->tot.ymin, &v2d->tot.ymax, false, false);
276 /* extra offset so that these items are visible */
277 v2d->tot.xmin -= 10.0f;
278 v2d->tot.xmax += 10.0f;
279 }
280
281 if ((sipo->flag & SIPO_NODRAWCURSOR) == 0) {
283 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
284
286
287 /* horizontal component of value-cursor (value line before the current frame line) */
288 float y = sipo->cursorVal;
289
290 /* Draw a line to indicate the cursor value. */
293 GPU_line_width(2.0);
294
296 immVertex2f(pos, v2d->cur.xmin, y);
297 immVertex2f(pos, v2d->cur.xmax, y);
298 immEnd();
299
301
302 /* Vertical component of the cursor. */
303 if (sipo->mode == SIPO_MODE_DRIVERS) {
304 /* cursor x-value */
305 float x = sipo->cursorTime;
306
307 /* to help differentiate this from the current frame,
308 * draw slightly darker like the horizontal one */
311 GPU_line_width(2.0);
312
314 immVertex2f(pos, x, v2d->cur.ymin);
315 immVertex2f(pos, x, v2d->cur.ymax);
316 immEnd();
317
319 }
320
322 }
323
324 /* markers */
325 if (sipo->mode != SIPO_MODE_DRIVERS) {
326 UI_view2d_view_orthoSpecial(region, v2d, true);
327 int marker_draw_flag = DRAW_MARKERS_MARGIN;
329 ED_markers_draw(C, marker_draw_flag);
330 }
331 }
332
333 /* preview range */
334 if (sipo->mode != SIPO_MODE_DRIVERS) {
336 ANIM_draw_previewrange(scene, v2d, 0);
337 }
338
339 /* callback */
342
343 /* reset view matrix */
345
346 /* time-scrubbing */
347 int base = round_db_to_int(scene->frames_per_second());
348 if (sipo->mode == SIPO_MODE_DRIVERS) {
349 base = driver_step;
350 }
351 ED_time_scrub_draw(region, scene, display_seconds, false, base);
352}
353
355{
356 /* draw entirely, view changes should be handled here */
357 const SpaceGraph *sipo = CTX_wm_space_graph(C);
358 const bool minimized = (region->winy < UI_ANIM_MINY);
359
360 const Scene *scene = CTX_data_scene(C);
361 View2D *v2d = &region->v2d;
362
363 /* Driver Editor's X axis is not time. */
364 if (sipo->mode != SIPO_MODE_DRIVERS) {
365 /* scrubbing region */
366 ED_time_scrub_draw_current_frame(region, scene, sipo->flag & SIPO_DRAWTIME, !minimized);
367 }
368
369 if (!minimized) {
370 /* scrollers */
371 const rcti scroller_mask = ED_time_scrub_clamp_scroller_mask(v2d->mask);
372 /* FIXME: args for scrollers depend on the type of data being shown. */
373 region->v2d.scroll |= V2D_SCROLL_BOTTOM;
374 UI_view2d_scrollers_draw(v2d, &scroller_mask);
375
376 /* scale numbers */
377 {
378 rcti rect;
380 &rect, 0, 15 * UI_SCALE_FAC, 15 * UI_SCALE_FAC, region->winy - UI_TIME_SCRUB_MARGIN_Y);
381 UI_view2d_draw_scale_y__values(region, v2d, &rect, TH_SCROLL_TEXT, 10);
382 }
383 }
384 else {
385 region->v2d.scroll &= ~V2D_SCROLL_BOTTOM;
386 }
387}
388
390{
391 wmKeyMap *keymap;
392
393 /* make sure we keep the hide flags */
394 region->v2d.scroll |= V2D_SCROLL_RIGHT;
395
396 /* prevent any noise of past */
398
401
402 UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
403
404 /* own keymap */
405 keymap = WM_keymap_ensure(
406 wm->runtime->defaultconf, "Animation Channels", SPACE_EMPTY, RGN_TYPE_WINDOW);
407 WM_event_add_keymap_handler_v2d_mask(&region->runtime->handlers, keymap);
408 keymap = WM_keymap_ensure(
409 wm->runtime->defaultconf, "Graph Editor Generic", SPACE_GRAPH, RGN_TYPE_WINDOW);
410 WM_event_add_keymap_handler(&region->runtime->handlers, keymap);
411}
412
413static void set_v2d_height(View2D *v2d, const size_t item_count)
414{
415 const int height = ANIM_UI_get_channels_total_height(v2d, item_count);
416 v2d->tot.ymin = -height;
418}
419
420static void graph_channel_region_draw(const bContext *C, ARegion *region)
421{
422 bAnimContext ac;
423 if (!ANIM_animdata_get_context(C, &ac)) {
424 return;
425 }
426 View2D *v2d = &region->v2d;
427
428 /* clear and setup matrix */
430
431 ListBase anim_data = {nullptr, nullptr};
434 const size_t item_count = ANIM_animdata_filter(
435 &ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
436 set_v2d_height(v2d, item_count);
438
439 /* draw channels */
440 graph_draw_channel_names((bContext *)C, &ac, region, anim_data);
441
442 /* channel filter next to scrubbing area */
444
445 /* reset view matrix */
447
448 /* scrollers */
449 UI_view2d_scrollers_draw(v2d, nullptr);
450
451 ANIM_animdata_freelist(&anim_data);
452}
453
454/* add handlers, stuff you only do once or on area/region changes */
456{
457 ED_region_header_init(region);
458}
459
460static void graph_header_region_draw(const bContext *C, ARegion *region)
461{
462 ED_region_header(C, region);
463}
464
465/* add handlers, stuff you only do once or on area/region changes */
467{
468 wmKeyMap *keymap;
469
470 ED_region_panels_init(wm, region);
471
472 keymap = WM_keymap_ensure(
473 wm->runtime->defaultconf, "Graph Editor Generic", SPACE_GRAPH, RGN_TYPE_WINDOW);
474 WM_event_add_keymap_handler_v2d_mask(&region->runtime->handlers, keymap);
475}
476
477static void graph_buttons_region_draw(const bContext *C, ARegion *region)
478{
479 ED_region_panels(C, region);
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 case ND_SEQUENCER:
502 if (wmn->action == NA_SELECTED) {
503 ED_region_tag_redraw(region);
504 }
505 break;
506 }
507 break;
508 case NC_OBJECT:
509 switch (wmn->data) {
510 case ND_BONE_ACTIVE:
511 case ND_BONE_SELECT:
512 case ND_KEYS:
513 ED_region_tag_redraw(region);
514 break;
515 case ND_MODIFIER:
516 if (wmn->action == NA_RENAME) {
517 ED_region_tag_redraw(region);
518 }
519 break;
520 }
521 break;
522 case NC_NODE:
523 switch (wmn->action) {
524 case NA_EDITED:
525 case NA_SELECTED:
526 ED_region_tag_redraw(region);
527 break;
528 }
529 break;
530 case NC_ID:
531 if (wmn->action == NA_RENAME) {
532 ED_region_tag_redraw(region);
533 }
534 break;
535 case NC_SCREEN:
536 if (ELEM(wmn->data, ND_LAYER)) {
537 ED_region_tag_redraw(region);
538 }
539 break;
540 default:
541 if (wmn->data == ND_KEYS) {
542 ED_region_tag_redraw(region);
543 }
544 break;
545 }
546}
547
549{
550 wmMsgBus *mbus = params->message_bus;
551 Scene *scene = params->scene;
552 ARegion *region = params->region;
553
554 wmMsgSubscribeValue msg_sub_value_region_tag_redraw{};
555 msg_sub_value_region_tag_redraw.owner = region;
556 msg_sub_value_region_tag_redraw.user_data = region;
557 msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw;
558
559 /* Timeline depends on scene properties. */
560 {
561 bool use_preview = (scene->r.flag & SCER_PRV_RANGE);
562 const PropertyRNA *props[] = {
563 use_preview ? &rna_Scene_frame_preview_start : &rna_Scene_frame_start,
564 use_preview ? &rna_Scene_frame_preview_end : &rna_Scene_frame_end,
565 &rna_Scene_use_preview_range,
566 &rna_Scene_frame_current,
567 };
568
569 PointerRNA idptr = RNA_id_pointer_create(&scene->id);
570
571 for (int i = 0; i < ARRAY_SIZE(props); i++) {
572 WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_region_tag_redraw, __func__);
573 }
574 }
575
576 /* All dope-sheet filter settings, etc. affect the drawing of this editor,
577 * also same applies for all animation-related data-types that may appear here,
578 * so just whitelist the entire structs for updates
579 */
580 {
581 wmMsgParams_RNA msg_key_params = {{}};
582 StructRNA *type_array[] = {
583 &RNA_DopeSheet, /* dope-sheet filters */
584
585 &RNA_ActionGroup, /* channel groups */
586 &RNA_FCurve, /* F-Curve */
587 &RNA_Keyframe,
588 &RNA_FCurveSample,
589
590 &RNA_FModifier, /* F-Modifiers (XXX: Why can't we just do all subclasses too?) */
591 &RNA_FModifierCycles,
592 &RNA_FModifierEnvelope,
593 &RNA_FModifierEnvelopeControlPoint,
594 &RNA_FModifierFunctionGenerator,
595 &RNA_FModifierGenerator,
596 &RNA_FModifierLimits,
597 &RNA_FModifierNoise,
598 &RNA_FModifierStepped,
599 };
600
601 for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
602 msg_key_params.ptr.type = type_array[i];
604 mbus, &msg_key_params, &msg_sub_value_region_tag_redraw, __func__);
605 }
606 }
607}
608
609/* editor level listener */
611{
612 ScrArea *area = params->area;
613 const wmNotifier *wmn = params->notifier;
614 SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
615
616 /* context changes */
617 switch (wmn->category) {
618 case NC_ANIMATION:
619 /* For selection changes of animation data, we can just redraw...
620 * otherwise auto-color might need to be done again. */
621 if (ELEM(wmn->data, ND_KEYFRAME, ND_ANIMCHAN) && (wmn->action == NA_SELECTED)) {
622 ED_area_tag_redraw(area);
623 }
624 else {
626 }
627 break;
628 case NC_SCENE:
629 switch (wmn->data) {
630 case ND_OB_ACTIVE: /* Selection changed, so force refresh to flush
631 * (needs flag set to do syncing). */
632 case ND_OB_SELECT:
635 break;
636
637 default: /* just redrawing the view will do */
638 ED_area_tag_redraw(area);
639 break;
640 }
641 break;
642 case NC_OBJECT:
643 switch (wmn->data) {
644 case ND_BONE_SELECT: /* Selection changed, so force refresh to flush
645 * (needs flag set to do syncing). */
646 case ND_BONE_ACTIVE:
649 break;
650 case ND_TRANSFORM:
651 break; /* Do nothing. */
652
653 default: /* just redrawing the view will do */
654 ED_area_tag_redraw(area);
655 break;
656 }
657 break;
658 case NC_NODE:
659 if (wmn->action == NA_SELECTED) {
660 /* selection changed, so force refresh to flush (needs flag set to do syncing) */
663 }
664 break;
665 case NC_SPACE:
666 if (wmn->data == ND_SPACE_GRAPH) {
667 ED_area_tag_redraw(area);
668 }
669 break;
670 case NC_WINDOW:
671 if (sipo->runtime.flag &
673 {
674 /* force redraw/refresh after undo/redo - prevents "black curve" problem */
676 }
677 break;
678
679#if 0 /* XXX: restore the case below if not enough updates occur... */
680 default: {
681 if (wmn->data == ND_KEYS) {
682 ED_area_tag_redraw(area);
683 }
684 }
685#endif
686 }
687}
688
689/* Update F-Curve colors */
691{
692 bAnimContext ac;
693
694 ListBase anim_data = {nullptr, nullptr};
695 bAnimListElem *ale;
696 size_t items;
697 int filter;
698 int i;
699
700 if (ANIM_animdata_get_context(C, &ac) == false) {
701 return;
702 }
703
705
706 /* build list of F-Curves which will be visible as channels in channel-region
707 * - we don't include ANIMFILTER_CURVEVISIBLE filter, as that will result in a
708 * mismatch between channel-colors and the drawn curves
709 */
711 items = ANIM_animdata_filter(
712 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
713
714 /* loop over F-Curves, assigning colors */
715 for (ale = static_cast<bAnimListElem *>(anim_data.first), i = 0; ale; ale = ale->next, i++) {
717 "Expecting only FCurves when using the ANIMFILTER_FCURVESONLY filter");
718 FCurve *fcu = (FCurve *)ale->data;
719
720 /* set color of curve here */
721 switch (fcu->color_mode) {
722 case FCURVE_COLOR_CUSTOM: {
723 /* User has defined a custom color for this curve already
724 * (we assume it's not going to cause clashes with text colors),
725 * which should be left alone... Nothing needs to be done here.
726 */
727 break;
728 }
730 /* F-Curve's array index is automatically mapped to RGB values.
731 * This works best of 3-value vectors.
732 * TODO: find a way to module the hue so that not all curves have same color...
733 */
734 float *col = fcu->color;
735
736 switch (fcu->array_index) {
737 case 0:
739 break;
740 case 1:
742 break;
743 case 2:
745 break;
746 default:
747 /* 'unknown' color - bluish so as to not conflict with handles */
748 col[0] = 0.3f;
749 col[1] = 0.8f;
750 col[2] = 1.0f;
751 break;
752 }
753 break;
754 }
756 /* Like FCURVE_COLOR_AUTO_RGB, except this is for quaternions... */
757 float *col = fcu->color;
758
759 switch (fcu->array_index) {
760 case 1:
762 break;
763 case 2:
765 break;
766 case 3:
768 break;
769
770 case 0: {
772 break;
773 }
774
775 default:
776 /* 'unknown' color - bluish so as to not conflict with handles */
777 col[0] = 0.3f;
778 col[1] = 0.8f;
779 col[2] = 1.0f;
780 break;
781 }
782 break;
783 }
785 default: {
786 /* determine color 'automatically' using 'magic function' which uses the given args
787 * of current item index + total items to determine some RGB color
788 */
789 getcolor_fcurve_rainbow(i, items, fcu->color);
790 break;
791 }
792 }
793 }
794
795 /* free temp list */
796 ANIM_animdata_freelist(&anim_data);
797}
798
799static void graph_refresh(const bContext *C, ScrArea *area)
800{
801 SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
802
803 /* updates to data needed depends on Graph Editor mode... */
804 switch (sipo->mode) {
805 case SIPO_MODE_ANIMATION: /* all animation */
806 {
807 break;
808 }
809
810 case SIPO_MODE_DRIVERS: /* Drivers only. */
811 {
812 break;
813 }
814 }
815
816 /* region updates? */
817 /* XXX re-sizing y-extents of tot should go here? */
818
819 /* Update the state of the animchannels in response to changes from the data they represent
820 * NOTE: the temp flag is used to indicate when this needs to be done,
821 * and will be cleared once handled. */
825 ED_area_tag_redraw(area);
826 }
827
828 /* We could check 'SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC_COLOR', but color is recalculated anyway. */
831#if 0 /* Done below. */
833#endif
834 ED_area_tag_redraw(area);
835 }
836
839
840 /* init/adjust F-Curve colors */
842}
843
844static void graph_id_remap(ScrArea * /*area*/,
845 SpaceLink *slink,
846 const blender::bke::id::IDRemapper &mappings)
847{
848 SpaceGraph *sgraph = (SpaceGraph *)slink;
849 if (!sgraph->ads) {
850 return;
851 }
852
853 mappings.apply(reinterpret_cast<ID **>(&sgraph->ads->filter_grp), ID_REMAP_APPLY_DEFAULT);
854 mappings.apply((&sgraph->ads->source), ID_REMAP_APPLY_DEFAULT);
855}
856
858{
859 SpaceGraph *sgraph = reinterpret_cast<SpaceGraph *>(space_link);
860 const int data_flags = BKE_lib_query_foreachid_process_flags_get(data);
861 const bool is_readonly = (data_flags & IDWALK_READONLY) != 0;
862
863 /* NOTE: Could be deduplicated with the #bDopeSheet handling of #SpaceAction and #SpaceNla. */
864 if (sgraph->ads == nullptr) {
865 return;
866 }
867
870
871 if (!is_readonly) {
872 /* Force recalc of list of channels (i.e. including calculating F-Curve colors) to
873 * prevent the "black curves" problem post-undo. */
875 }
876}
877
879{
880 SpaceGraph *sgraph = static_cast<SpaceGraph *>(area->spacedata.first);
881 return sgraph->mode;
882}
883
884static void graph_space_subtype_set(ScrArea *area, int value)
885{
886 SpaceGraph *sgraph = static_cast<SpaceGraph *>(area->spacedata.first);
887 sgraph->mode = value;
888}
889
891 EnumPropertyItem **item,
892 int *totitem)
893{
895}
896
898{
899 SpaceGraph *sgraph = static_cast<SpaceGraph *>(area->spacedata.first);
900 const int index = RNA_enum_from_value(rna_enum_space_graph_mode_items, sgraph->mode);
902 return item.name;
903}
904
905static int graph_space_icon_get(const ScrArea *area)
906{
907 SpaceGraph *sgraph = static_cast<SpaceGraph *>(area->spacedata.first);
908 const int index = RNA_enum_from_value(rna_enum_space_graph_mode_items, sgraph->mode);
910 return item.icon;
911}
912
914{
915 SpaceGraph *sipo = (SpaceGraph *)sl;
916
917 BLO_read_struct(reader, bDopeSheet, &sipo->ads);
918 sipo->runtime = SpaceGraph_Runtime{};
919}
920
922{
923 SpaceGraph *sipo = (SpaceGraph *)sl;
924 ListBase tmpGhosts = sipo->runtime.ghost_curves;
925
926 /* temporarily disable ghost curves when saving */
928
929 BLO_write_struct(writer, SpaceGraph, sl);
930 if (sipo->ads) {
931 BLO_write_struct(writer, bDopeSheet, sipo->ads);
932 }
933
934 /* Re-enable ghost curves. */
935 sipo->runtime.ghost_curves = tmpGhosts;
936}
937
939{
940 BLI_assert(params->area->spacetype == SPACE_GRAPH);
941 const SpaceGraph *sipo = static_cast<const SpaceGraph *>(params->area->spacedata.first);
942 return sipo->mode != SIPO_MODE_DRIVERS;
943}
944
946{
947 std::unique_ptr<SpaceType> st = std::make_unique<SpaceType>();
948 ARegionType *art;
949
950 st->spaceid = SPACE_GRAPH;
951 STRNCPY_UTF8(st->name, "Graph");
952
953 st->create = graph_create;
954 st->free = graph_free;
955 st->init = graph_init;
956 st->duplicate = graph_duplicate;
957 st->operatortypes = graphedit_operatortypes;
958 st->keymap = graphedit_keymap;
959 st->listener = graph_listener;
960 st->refresh = graph_refresh;
961 st->id_remap = graph_id_remap;
962 st->foreach_id = graph_foreach_id;
963 st->space_subtype_item_extend = graph_space_subtype_item_extend;
964 st->space_subtype_get = graph_space_subtype_get;
965 st->space_subtype_set = graph_space_subtype_set;
966 st->space_name_get = graph_space_name_get;
967 st->space_icon_get = graph_space_icon_get;
968 st->blend_read_data = graph_space_blend_read_data;
969 st->blend_read_after_liblink = nullptr;
970 st->blend_write = graph_space_blend_write;
971
972 /* regions: main window */
973 art = MEM_callocN<ARegionType>("spacetype graphedit region");
981
982 BLI_addhead(&st->regiontypes, art);
983
984 /* regions: header */
985 art = MEM_callocN<ARegionType>("spacetype graphedit region");
987 art->prefsizey = HEADERY;
992
993 BLI_addhead(&st->regiontypes, art);
994
995 /* regions: footer */
996 art = static_cast<ARegionType *>(MEM_callocN(sizeof(ARegionType), "spacetype graphedit region"));
998 art->prefsizey = HEADERY;
1003
1004 BLI_addhead(&st->regiontypes, art);
1005
1006 /* regions: channels */
1007 art = MEM_callocN<ARegionType>("spacetype graphedit region");
1009 /* 200 is the 'standard', but due to scrollers, we want a bit more to fit the lock icons in */
1010 art->prefsizex = 200 + V2D_SCROLL_WIDTH;
1016
1017 BLI_addhead(&st->regiontypes, art);
1018
1019 /* regions: UI buttons */
1020 art = MEM_callocN<ARegionType>("spacetype graphedit region");
1021 art->regionid = RGN_TYPE_UI;
1027
1028 BLI_addhead(&st->regiontypes, art);
1029
1031
1032 art = ED_area_type_hud(st->spaceid);
1033 BLI_addhead(&st->regiontypes, art);
1034
1035 BKE_spacetype_register(std::move(st));
1036}
SpaceGraph * CTX_wm_space_graph(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
void BKE_fcurves_free(ListBase *list)
#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 BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
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
void void void void void void BLI_duplicatelist(ListBase *dst, const ListBase *src) ATTR_NONNULL(1
MINLINE int round_db_to_int(double a)
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.cc:414
#define STRNCPY_UTF8(dst, src)
unsigned int uint
#define ARRAY_SIZE(arr)
#define ELEM(...)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_read_struct(reader, struct_name, ptr_p)
@ ADS_FILTER_ONLYSEL
@ FCURVE_COLOR_AUTO_RGB
@ FCURVE_COLOR_AUTO_RAINBOW
@ FCURVE_COLOR_CUSTOM
@ FCURVE_COLOR_AUTO_YRGB
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_EMPTY
@ SPACE_GRAPH
@ SIPO_MODE_DRIVERS
@ SIPO_MODE_ANIMATION
@ SIPO_DRAWTIME
@ SIPO_NODRAWCURSOR
@ SIPO_SHOW_MARKERS
@ SIPO_NORMALIZE
@ SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC
@ SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC_COLOR
@ SIPO_RUNTIME_FLAG_TWEAK_HANDLES_RIGHT
@ SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT
#define UI_SCALE_FAC
@ USER_HEADER_BOTTOM
@ V2D_SCROLL_LEFT
@ V2D_SCROLL_HORIZONTAL_HIDE
@ V2D_SCROLL_VERTICAL_HIDE
@ V2D_SCROLL_TOP
@ V2D_SCROLL_VERTICAL_HANDLES
@ V2D_SCROLL_RIGHT
@ V2D_SCROLL_BOTTOM
@ V2D_SCROLL_HORIZONTAL_HANDLES
@ ANIMTYPE_NLACURVE
@ ANIMTYPE_FCURVE
eAnimCont_Types
eAnimFilter_Flags
@ ANIMFILTER_DATA_VISIBLE
@ ANIMFILTER_LIST_VISIBLE
@ ANIMFILTER_LIST_CHANNELS
@ ANIMFILTER_NODUPLIS
@ ANIMFILTER_FCURVESONLY
@ DRAW_MARKERS_MARGIN
Definition ED_markers.hh:28
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_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 immEnd()
void immUnbindProgram()
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset)
void immVertex2f(uint attr_id, float x, float y)
GPUVertFormat * immVertexFormat()
void immBegin(GPUPrimType, uint vertex_len)
void immRectf(uint pos, float x1, float y1, float x2, float y2)
@ GPU_PRIM_LINES
@ GPU_SHADER_3D_UNIFORM_COLOR
void GPU_line_width(float width)
Definition gpu_state.cc:166
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(GPUBlend blend)
Definition gpu_state.cc:42
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
#define UI_SIDEBAR_PANEL_WIDTH
void UI_GetThemeColor3fv(int colorid, float col[3])
@ TH_BACK
@ TH_CFRAME
@ TH_SCROLL_TEXT
@ TH_AXIS_Y
@ TH_AXIS_X
@ TH_AXIS_W
@ TH_AXIS_Z
void UI_ThemeClearColor(int colorid)
void UI_SetTheme(int spacetype, int regionid)
void UI_view2d_draw_scale_y__values(const ARegion *region, const View2D *v2d, const rcti *rect, int colorid, int base)
#define UI_ANIM_MINY
Definition UI_view2d.hh:481
void UI_view2d_draw_lines_y__values(const View2D *v2d, int base)
void UI_view2d_view_orthoSpecial(ARegion *region, View2D *v2d, bool xaxis)
Definition view2d.cc:1136
void UI_view2d_draw_lines_x__frames_or_seconds(const View2D *v2d, const Scene *scene, bool display_seconds)
void UI_view2d_draw_lines_x__values(const View2D *v2d, int base)
void UI_view2d_curRect_clamp_y(View2D *v2d)
Definition view2d.cc:844
#define V2D_SCROLL_WIDTH
Definition UI_view2d.hh:54
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
#define UI_TIME_SCRUB_MARGIN_Y
Definition UI_view2d.hh:479
void UI_view2d_view_ortho(const View2D *v2d)
Definition view2d.cc:1095
@ V2D_COMMONVIEW_LIST
Definition UI_view2d.hh:35
@ V2D_COMMONVIEW_CUSTOM
Definition UI_view2d.hh:31
#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_OB_ACTIVE
Definition WM_types.hh:440
#define ND_RENDER_OPTIONS
Definition WM_types.hh:435
#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 NC_SCENE
Definition WM_types.hh:378
#define ND_MODIFIER
Definition WM_types.hh:462
#define NA_EDITED
Definition WM_types.hh:584
#define ND_SPACE_GRAPH
Definition WM_types.hh:532
#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_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_KEYS
Definition WM_types.hh:463
#define NA_RENAME
Definition WM_types.hh:588
#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
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_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)
void getcolor_fcurve_rainbow(int cur, int tot, float out[3])
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
uint pos
uint col
#define filter
void graph_buttons_register(ARegionType *art)
void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region)
void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region, const ListBase &anim_data)
void graph_draw_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, short sel)
void graphedit_operatortypes()
Definition graph_ops.cc:423
void graphedit_keymap(wmKeyConfig *keyconf)
Definition graph_ops.cc:527
void get_graph_keyframe_extents(bAnimContext *ac, float *xmin, float *xmax, float *ymin, float *ymax, bool do_sel_only, bool include_handles)
Definition graph_view.cc:43
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
format
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
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_graph_mode_items[]
Definition rna_space.cc:172
static void graph_channel_region_draw(const bContext *C, ARegion *region)
static void graph_refresh(const bContext *C, ScrArea *area)
static void graph_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
static void draw_normalization_borders(Scene *scene, View2D *v2d)
static void graph_space_subtype_item_extend(bContext *, EnumPropertyItem **item, int *totitem)
static void graph_main_region_draw_overlay(const bContext *C, ARegion *region)
static void graph_region_listener(const wmRegionListenerParams *params)
static void graph_channel_region_init(wmWindowManager *wm, ARegion *region)
void ED_spacetype_ipo()
static int graph_space_subtype_get(ScrArea *area)
static void graph_main_region_init(wmWindowManager *wm, ARegion *region)
static void graph_header_region_draw(const bContext *C, ARegion *region)
static void graph_listener(const wmSpaceTypeListenerParams *params)
static SpaceLink * graph_duplicate(SpaceLink *sl)
static void graph_space_blend_write(BlendWriter *writer, SpaceLink *sl)
static void graph_free(SpaceLink *sl)
static void set_v2d_height(View2D *v2d, const size_t item_count)
static void graph_space_subtype_set(ScrArea *area, int value)
static blender::StringRefNull graph_space_name_get(const ScrArea *area)
static void graph_header_region_init(wmWindowManager *, ARegion *region)
static void graph_main_region_draw(const bContext *C, ARegion *region)
static void graph_refresh_fcurve_colors(const bContext *C)
static void graph_buttons_region_init(wmWindowManager *wm, ARegion *region)
static void graph_buttons_region_draw(const bContext *C, ARegion *region)
static bool action_region_poll_hide_in_driver_mode(const RegionPollParams *params)
static void graph_id_remap(ScrArea *, SpaceLink *slink, const blender::bke::id::IDRemapper &mappings)
static void graph_init(wmWindowManager *wm, ScrArea *area)
static void graph_space_blend_read_data(BlendDataReader *reader, SpaceLink *sl)
static int graph_space_icon_get(const ScrArea *area)
static SpaceLink * graph_create(const ScrArea *, const Scene *scene)
static void graph_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
#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
float color[3]
int array_index
Definition DNA_ID.h:414
void * first
StructRNA * type
Definition RNA_types.hh:52
struct RenderData r
ListBase spacedata
struct bDopeSheet * ads
SpaceGraph_Runtime runtime
ListBase regionbase
short keeptot
float max[2]
float min[2]
eAnimCont_Types datatype
bDopeSheet * ads
bAnimListElem * next
eAnim_ChannelType type
ListBase chanbase
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
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)
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)
wmWindow * WM_window_find_by_area(wmWindowManager *wm, const ScrArea *area)
Scene * WM_window_get_active_scene(const wmWindow *win)