Blender V4.3
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
9#include <cstdio>
10#include <cstring>
11
12#include "DNA_anim_types.h"
14#include "DNA_scene_types.h"
15
16#include "MEM_guardedalloc.h"
17
18#include "BLI_blenlib.h"
19#include "BLI_math_color.h"
20#include "BLI_utildefines.h"
21
22#include "BKE_context.hh"
23#include "BKE_fcurve.hh"
24#include "BKE_lib_query.hh"
25#include "BKE_lib_remap.hh"
26#include "BKE_screen.hh"
27
28#include "ED_anim_api.hh"
29#include "ED_markers.hh"
30#include "ED_screen.hh"
31#include "ED_space_api.hh"
32#include "ED_time_scrub_ui.hh"
33
34#include "GPU_immediate.hh"
35#include "GPU_state.hh"
36
37#include "WM_api.hh"
38#include "WM_message.hh"
39#include "WM_types.hh"
40
41#include "RNA_access.hh"
42#include "RNA_define.hh"
43#include "RNA_enum_types.hh"
44
45#include "UI_interface.hh"
46#include "UI_resources.hh"
47#include "UI_view2d.hh"
48
49#include "BLO_read_write.hh"
50
51#include "graph_intern.hh" /* own include */
52
53/* ******************** default callbacks for ipo space ***************** */
54
55static SpaceLink *graph_create(const ScrArea * /*area*/, const Scene *scene)
56{
57 ARegion *region;
58 SpaceGraph *sipo;
59
60 /* Graph Editor - general stuff */
61 sipo = static_cast<SpaceGraph *>(MEM_callocN(sizeof(SpaceGraph), "init graphedit"));
62 sipo->spacetype = SPACE_GRAPH;
63
64 /* allocate DopeSheet data for Graph Editor */
65 sipo->ads = static_cast<bDopeSheet *>(MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet"));
66 sipo->ads->source = (ID *)scene;
67
68 /* settings for making it easier by default to just see what you're interested in tweaking */
70 sipo->flag |= SIPO_SHOW_MARKERS;
71
72 /* header */
73 region = static_cast<ARegion *>(MEM_callocN(sizeof(ARegion), "header for graphedit"));
74
75 BLI_addtail(&sipo->regionbase, region);
76 region->regiontype = RGN_TYPE_HEADER;
77 region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
78
79 /* channels */
80 region = static_cast<ARegion *>(MEM_callocN(sizeof(ARegion), "channels region for graphedit"));
81
82 BLI_addtail(&sipo->regionbase, region);
83 region->regiontype = RGN_TYPE_CHANNELS;
84 region->alignment = RGN_ALIGN_LEFT;
85
86 region->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM);
87
88 /* ui buttons */
89 region = static_cast<ARegion *>(MEM_callocN(sizeof(ARegion), "buttons region for graphedit"));
90
91 BLI_addtail(&sipo->regionbase, region);
92 region->regiontype = RGN_TYPE_UI;
93 region->alignment = RGN_ALIGN_RIGHT;
94
95 /* main region */
96 region = static_cast<ARegion *>(MEM_callocN(sizeof(ARegion), "main region for graphedit"));
97
98 BLI_addtail(&sipo->regionbase, region);
99 region->regiontype = RGN_TYPE_WINDOW;
100
101 region->v2d.tot.xmin = 0.0f;
102 region->v2d.tot.ymin = float(scene->r.sfra) - 10.0f;
103 region->v2d.tot.xmax = float(scene->r.efra);
104 region->v2d.tot.ymax = 10.0f;
105
106 region->v2d.cur = region->v2d.tot;
107
108 region->v2d.min[0] = FLT_MIN;
109 region->v2d.min[1] = FLT_MIN;
110
111 region->v2d.max[0] = MAXFRAMEF;
112 region->v2d.max[1] = FLT_MAX;
113
114 region->v2d.scroll = (V2D_SCROLL_BOTTOM | V2D_SCROLL_HORIZONTAL_HANDLES);
115 region->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HANDLES);
116
117 region->v2d.keeptot = 0;
118
119 return (SpaceLink *)sipo;
120}
121
122/* Doesn't free the space-link itself. */
123static void graph_free(SpaceLink *sl)
124{
125 SpaceGraph *si = (SpaceGraph *)sl;
126
127 if (si->ads) {
129 MEM_freeN(si->ads);
130 }
131
132 if (si->runtime.ghost_curves.first) {
134 }
135}
136
137/* spacetype; init callback */
138static void graph_init(wmWindowManager *wm, ScrArea *area)
139{
140 SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
141
142 /* init dopesheet data if non-existent (i.e. for old files) */
143 if (sipo->ads == nullptr) {
144 wmWindow *win = WM_window_find_by_area(wm, area);
145 sipo->ads = static_cast<bDopeSheet *>(MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet"));
146 sipo->ads->source = win ? (ID *)WM_window_get_active_scene(win) : nullptr;
147 }
148
149 /* force immediate init of any invalid F-Curve colors */
150 /* XXX: but, don't do SIPO_TEMP_NEEDCHANSYNC (i.e. channel select state sync)
151 * as this is run on each region resize; setting this here will cause selection
152 * state to be lost on area/region resizing. #35744.
153 */
155}
156
158{
159 SpaceGraph *sipon = static_cast<SpaceGraph *>(MEM_dupallocN(sl));
160
161 memset(&sipon->runtime, 0x0, sizeof(sipon->runtime));
162
163 /* clear or remove stuff from old */
164 BLI_duplicatelist(&sipon->runtime.ghost_curves, &((SpaceGraph *)sl)->runtime.ghost_curves);
165 sipon->ads = static_cast<bDopeSheet *>(MEM_dupallocN(sipon->ads));
166
167 return (SpaceLink *)sipon;
168}
169
170/* add handlers, stuff you only do once or on area/region changes */
172{
173 wmKeyMap *keymap;
174
175 UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_CUSTOM, region->winx, region->winy);
176
177 /* own keymap */
178 keymap = WM_keymap_ensure(wm->defaultconf, "Graph Editor", SPACE_GRAPH, RGN_TYPE_WINDOW);
179 WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
180 keymap = WM_keymap_ensure(wm->defaultconf, "Graph Editor Generic", SPACE_GRAPH, RGN_TYPE_WINDOW);
181 WM_event_add_keymap_handler(&region->handlers, keymap);
182}
183
184/* Draw a darker area above 1 and below -1. */
185static void draw_normalization_borders(Scene *scene, View2D *v2d)
186{
188
191
194
195 if (v2d->cur.ymax >= 1) {
196 immRectf(pos, scene->r.sfra, 1, scene->r.efra, v2d->cur.ymax);
197 }
198 if (v2d->cur.ymin <= -1) {
199 immRectf(pos, scene->r.sfra, v2d->cur.ymin, scene->r.efra, -1);
200 }
201
204}
205
206static void graph_main_region_draw(const bContext *C, ARegion *region)
207{
208 /* draw entirely, view changes should be handled here */
210 Scene *scene = CTX_data_scene(C);
211 bAnimContext ac;
212 View2D *v2d = &region->v2d;
213
214 /* clear and setup matrix */
216
218
219 /* grid */
220 bool display_seconds = (sipo->mode == SIPO_MODE_ANIMATION) && (sipo->flag & SIPO_DRAWTIME);
221 UI_view2d_draw_lines_x__frames_or_seconds(v2d, scene, display_seconds);
223
225
226 /* start and end frame (in F-Curve mode only) */
227 if (sipo->mode != SIPO_MODE_DRIVERS) {
228 ANIM_draw_framerange(scene, v2d);
229 }
230
231 if (sipo->mode == SIPO_MODE_ANIMATION && (sipo->flag & SIPO_NORMALIZE)) {
232 draw_normalization_borders(scene, v2d);
233 }
234
235 /* draw data */
236 if (ANIM_animdata_get_context(C, &ac)) {
237 /* draw ghost curves */
238 graph_draw_ghost_curves(&ac, sipo, region);
239
240 /* draw curves twice - unselected, then selected, so that the are fewer occlusion problems */
241 graph_draw_curves(&ac, sipo, region, 0);
242 graph_draw_curves(&ac, sipo, region, 1);
243
244 /* XXX(ton): the slow way to set tot rect... but for nice sliders needed. */
245 /* Excluding handles from the calculation to save performance. This cuts the time it takes for
246 * this function to run in half which is a major performance bottleneck on heavy scenes. */
248 &ac, &v2d->tot.xmin, &v2d->tot.xmax, &v2d->tot.ymin, &v2d->tot.ymax, false, false);
249 /* extra offset so that these items are visible */
250 v2d->tot.xmin -= 10.0f;
251 v2d->tot.xmax += 10.0f;
252 }
253
254 if ((sipo->flag & SIPO_NODRAWCURSOR) == 0) {
256
258
259 /* horizontal component of value-cursor (value line before the current frame line) */
260 float y = sipo->cursorVal;
261
262 /* Draw a line to indicate the cursor value. */
265 GPU_line_width(2.0);
266
268 immVertex2f(pos, v2d->cur.xmin, y);
269 immVertex2f(pos, v2d->cur.xmax, y);
270 immEnd();
271
273
274 /* Vertical component of the cursor. */
275 if (sipo->mode == SIPO_MODE_DRIVERS) {
276 /* cursor x-value */
277 float x = sipo->cursorTime;
278
279 /* to help differentiate this from the current frame,
280 * draw slightly darker like the horizontal one */
283 GPU_line_width(2.0);
284
286 immVertex2f(pos, x, v2d->cur.ymin);
287 immVertex2f(pos, x, v2d->cur.ymax);
288 immEnd();
289
291 }
292
294 }
295
296 /* markers */
297 if (sipo->mode != SIPO_MODE_DRIVERS) {
298 UI_view2d_view_orthoSpecial(region, v2d, true);
299 int marker_draw_flag = DRAW_MARKERS_MARGIN;
300 if (sipo->flag & SIPO_SHOW_MARKERS) {
301 ED_markers_draw(C, marker_draw_flag);
302 }
303 }
304
305 /* preview range */
306 if (sipo->mode != SIPO_MODE_DRIVERS) {
308 ANIM_draw_previewrange(C, v2d, 0);
309 }
310
311 /* callback */
314
315 /* reset view matrix */
317
318 /* time-scrubbing */
319 ED_time_scrub_draw(region, scene, display_seconds, false);
320}
321
322static void graph_main_region_draw_overlay(const bContext *C, ARegion *region)
323{
324 /* draw entirely, view changes should be handled here */
325 const SpaceGraph *sipo = CTX_wm_space_graph(C);
326
327 const Scene *scene = CTX_data_scene(C);
328 View2D *v2d = &region->v2d;
329
330 /* Driver Editor's X axis is not time. */
331 if (sipo->mode != SIPO_MODE_DRIVERS) {
332 /* scrubbing region */
334 }
335
336 if (region->winy > HEADERY * UI_SCALE_FAC) {
337 /* scrollers */
338 const rcti scroller_mask = ED_time_scrub_clamp_scroller_mask(v2d->mask);
339 /* FIXME: args for scrollers depend on the type of data being shown. */
340 UI_view2d_scrollers_draw(v2d, &scroller_mask);
341
342 /* scale numbers */
343 {
344 rcti rect;
346 &rect, 0, 15 * UI_SCALE_FAC, 15 * UI_SCALE_FAC, region->winy - UI_TIME_SCRUB_MARGIN_Y);
348 }
349 }
350}
351
353{
354 wmKeyMap *keymap;
355
356 /* make sure we keep the hide flags */
357 region->v2d.scroll |= V2D_SCROLL_RIGHT;
358
359 /* prevent any noise of past */
360 region->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP | V2D_SCROLL_BOTTOM);
361
362 region->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
363 region->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE;
364
365 UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
366
367 /* own keymap */
368 keymap = WM_keymap_ensure(wm->defaultconf, "Animation Channels", SPACE_EMPTY, RGN_TYPE_WINDOW);
369 WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
370 keymap = WM_keymap_ensure(wm->defaultconf, "Graph Editor Generic", SPACE_GRAPH, RGN_TYPE_WINDOW);
371 WM_event_add_keymap_handler(&region->handlers, keymap);
372}
373
374static void set_v2d_height(View2D *v2d, const size_t item_count)
375{
376 const int height = ANIM_UI_get_channels_total_height(v2d, item_count);
377 v2d->tot.ymin = -height;
379}
380
381static void graph_channel_region_draw(const bContext *C, ARegion *region)
382{
383 bAnimContext ac;
384 if (!ANIM_animdata_get_context(C, &ac)) {
385 return;
386 }
387 View2D *v2d = &region->v2d;
388
389 /* clear and setup matrix */
391
392 ListBase anim_data = {nullptr, nullptr};
395 const size_t item_count = ANIM_animdata_filter(
396 &ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
397 set_v2d_height(v2d, item_count);
399
400 /* draw channels */
401 graph_draw_channel_names((bContext *)C, &ac, region, anim_data);
402
403 /* channel filter next to scrubbing area */
405
406 /* reset view matrix */
408
409 /* scrollers */
410 UI_view2d_scrollers_draw(v2d, nullptr);
411
412 ANIM_animdata_freelist(&anim_data);
413}
414
415/* add handlers, stuff you only do once or on area/region changes */
417{
418 ED_region_header_init(region);
419}
420
421static void graph_header_region_draw(const bContext *C, ARegion *region)
422{
423 ED_region_header(C, region);
424}
425
426/* add handlers, stuff you only do once or on area/region changes */
428{
429 wmKeyMap *keymap;
430
431 ED_region_panels_init(wm, region);
432
433 keymap = WM_keymap_ensure(wm->defaultconf, "Graph Editor Generic", SPACE_GRAPH, RGN_TYPE_WINDOW);
434 WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
435}
436
437static void graph_buttons_region_draw(const bContext *C, ARegion *region)
438{
439 ED_region_panels(C, region);
440}
441
443{
444 ARegion *region = params->region;
445 const wmNotifier *wmn = params->notifier;
446
447 /* context changes */
448 switch (wmn->category) {
449 case NC_ANIMATION:
450 ED_region_tag_redraw(region);
451 break;
452 case NC_SCENE:
453 switch (wmn->data) {
455 case ND_OB_ACTIVE:
456 case ND_FRAME:
457 case ND_FRAME_RANGE:
458 case ND_MARKERS:
459 ED_region_tag_redraw(region);
460 break;
461 case ND_SEQUENCER:
462 if (wmn->action == NA_SELECTED) {
463 ED_region_tag_redraw(region);
464 }
465 break;
466 }
467 break;
468 case NC_OBJECT:
469 switch (wmn->data) {
470 case ND_BONE_ACTIVE:
471 case ND_BONE_SELECT:
472 case ND_KEYS:
473 ED_region_tag_redraw(region);
474 break;
475 case ND_MODIFIER:
476 if (wmn->action == NA_RENAME) {
477 ED_region_tag_redraw(region);
478 }
479 break;
480 }
481 break;
482 case NC_NODE:
483 switch (wmn->action) {
484 case NA_EDITED:
485 case NA_SELECTED:
486 ED_region_tag_redraw(region);
487 break;
488 }
489 break;
490 case NC_ID:
491 if (wmn->action == NA_RENAME) {
492 ED_region_tag_redraw(region);
493 }
494 break;
495 case NC_SCREEN:
496 if (ELEM(wmn->data, ND_LAYER)) {
497 ED_region_tag_redraw(region);
498 }
499 break;
500 default:
501 if (wmn->data == ND_KEYS) {
502 ED_region_tag_redraw(region);
503 }
504 break;
505 }
506}
507
509{
510 wmMsgBus *mbus = params->message_bus;
511 Scene *scene = params->scene;
512 ARegion *region = params->region;
513
514 wmMsgSubscribeValue msg_sub_value_region_tag_redraw{};
515 msg_sub_value_region_tag_redraw.owner = region;
516 msg_sub_value_region_tag_redraw.user_data = region;
517 msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw;
518
519 /* Timeline depends on scene properties. */
520 {
521 bool use_preview = (scene->r.flag & SCER_PRV_RANGE);
522 const PropertyRNA *props[] = {
523 use_preview ? &rna_Scene_frame_preview_start : &rna_Scene_frame_start,
524 use_preview ? &rna_Scene_frame_preview_end : &rna_Scene_frame_end,
525 &rna_Scene_use_preview_range,
526 &rna_Scene_frame_current,
527 };
528
529 PointerRNA idptr = RNA_id_pointer_create(&scene->id);
530
531 for (int i = 0; i < ARRAY_SIZE(props); i++) {
532 WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_region_tag_redraw, __func__);
533 }
534 }
535
536 /* All dopesheet filter settings, etc. affect the drawing of this editor,
537 * also same applies for all animation-related data-types that may appear here,
538 * so just whitelist the entire structs for updates
539 */
540 {
541 wmMsgParams_RNA msg_key_params = {{nullptr}};
542 StructRNA *type_array[] = {
543 &RNA_DopeSheet, /* dopesheet filters */
544
545 &RNA_ActionGroup, /* channel groups */
546 &RNA_FCurve, /* F-Curve */
547 &RNA_Keyframe,
548 &RNA_FCurveSample,
549
550 &RNA_FModifier, /* F-Modifiers (XXX: Why can't we just do all subclasses too?) */
551 &RNA_FModifierCycles,
552 &RNA_FModifierEnvelope,
553 &RNA_FModifierEnvelopeControlPoint,
554 &RNA_FModifierFunctionGenerator,
555 &RNA_FModifierGenerator,
556 &RNA_FModifierLimits,
557 &RNA_FModifierNoise,
558 &RNA_FModifierStepped,
559 };
560
561 for (int i = 0; i < ARRAY_SIZE(type_array); i++) {
562 msg_key_params.ptr.type = type_array[i];
564 mbus, &msg_key_params, &msg_sub_value_region_tag_redraw, __func__);
565 }
566 }
567}
568
569/* editor level listener */
571{
572 ScrArea *area = params->area;
573 const wmNotifier *wmn = params->notifier;
574 SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
575
576 /* context changes */
577 switch (wmn->category) {
578 case NC_ANIMATION:
579 /* For selection changes of animation data, we can just redraw...
580 * otherwise auto-color might need to be done again. */
581 if (ELEM(wmn->data, ND_KEYFRAME, ND_ANIMCHAN) && (wmn->action == NA_SELECTED)) {
582 ED_area_tag_redraw(area);
583 }
584 else {
586 }
587 break;
588 case NC_SCENE:
589 switch (wmn->data) {
590 case ND_OB_ACTIVE: /* Selection changed, so force refresh to flush
591 * (needs flag set to do syncing). */
592 case ND_OB_SELECT:
595 break;
596
597 default: /* just redrawing the view will do */
598 ED_area_tag_redraw(area);
599 break;
600 }
601 break;
602 case NC_OBJECT:
603 switch (wmn->data) {
604 case ND_BONE_SELECT: /* Selection changed, so force refresh to flush
605 * (needs flag set to do syncing). */
606 case ND_BONE_ACTIVE:
609 break;
610 case ND_TRANSFORM:
611 break; /* Do nothing. */
612
613 default: /* just redrawing the view will do */
614 ED_area_tag_redraw(area);
615 break;
616 }
617 break;
618 case NC_NODE:
619 if (wmn->action == NA_SELECTED) {
620 /* selection changed, so force refresh to flush (needs flag set to do syncing) */
623 }
624 break;
625 case NC_SPACE:
626 if (wmn->data == ND_SPACE_GRAPH) {
627 ED_area_tag_redraw(area);
628 }
629 break;
630 case NC_WINDOW:
631 if (sipo->runtime.flag &
633 {
634 /* force redraw/refresh after undo/redo - prevents "black curve" problem */
636 }
637 break;
638
639#if 0 /* XXX: restore the case below if not enough updates occur... */
640 default: {
641 if (wmn->data == ND_KEYS) {
642 ED_area_tag_redraw(area);
643 }
644 }
645#endif
646 }
647}
648
649/* Update F-Curve colors */
651{
652 bAnimContext ac;
653
654 ListBase anim_data = {nullptr, nullptr};
655 bAnimListElem *ale;
656 size_t items;
657 int filter;
658 int i;
659
660 if (ANIM_animdata_get_context(C, &ac) == false) {
661 return;
662 }
663
665
666 /* build list of F-Curves which will be visible as channels in channel-region
667 * - we don't include ANIMFILTER_CURVEVISIBLE filter, as that will result in a
668 * mismatch between channel-colors and the drawn curves
669 */
671 items = ANIM_animdata_filter(
672 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
673
674 /* loop over F-Curves, assigning colors */
675 for (ale = static_cast<bAnimListElem *>(anim_data.first), i = 0; ale; ale = ale->next, i++) {
677 "Expecting only FCurves when using the ANIMFILTER_FCURVESONLY filter");
678 FCurve *fcu = (FCurve *)ale->data;
679
680 /* set color of curve here */
681 switch (fcu->color_mode) {
682 case FCURVE_COLOR_CUSTOM: {
683 /* User has defined a custom color for this curve already
684 * (we assume it's not going to cause clashes with text colors),
685 * which should be left alone... Nothing needs to be done here.
686 */
687 break;
688 }
690 /* F-Curve's array index is automatically mapped to RGB values.
691 * This works best of 3-value vectors.
692 * TODO: find a way to module the hue so that not all curves have same color...
693 */
694 float *col = fcu->color;
695
696 switch (fcu->array_index) {
697 case 0:
699 break;
700 case 1:
702 break;
703 case 2:
705 break;
706 default:
707 /* 'unknown' color - bluish so as to not conflict with handles */
708 col[0] = 0.3f;
709 col[1] = 0.8f;
710 col[2] = 1.0f;
711 break;
712 }
713 break;
714 }
716 /* Like FCURVE_COLOR_AUTO_RGB, except this is for quaternions... */
717 float *col = fcu->color;
718
719 switch (fcu->array_index) {
720 case 1:
722 break;
723 case 2:
725 break;
726 case 3:
728 break;
729
730 case 0: {
731 /* Special Case: "W" channel should be yellowish, so blend X and Y channel colors... */
732 float c1[3], c2[3];
733 float h1[3], h2[3];
734 float hresult[3];
735
736 /* - get colors (rgb) */
739
740 /* - perform blending in HSV space (to keep brightness similar) */
741 rgb_to_hsv_v(c1, h1);
742 rgb_to_hsv_v(c2, h2);
743
744 interp_v3_v3v3(hresult, h1, h2, 0.5f);
745
746 /* - convert back to RGB for display */
747 hsv_to_rgb_v(hresult, col);
748 break;
749 }
750
751 default:
752 /* 'unknown' color - bluish so as to not conflict with handles */
753 col[0] = 0.3f;
754 col[1] = 0.8f;
755 col[2] = 1.0f;
756 break;
757 }
758 break;
759 }
761 default: {
762 /* determine color 'automatically' using 'magic function' which uses the given args
763 * of current item index + total items to determine some RGB color
764 */
765 getcolor_fcurve_rainbow(i, items, fcu->color);
766 break;
767 }
768 }
769 }
770
771 /* free temp list */
772 ANIM_animdata_freelist(&anim_data);
773}
774
775static void graph_refresh(const bContext *C, ScrArea *area)
776{
777 SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
778
779 /* updates to data needed depends on Graph Editor mode... */
780 switch (sipo->mode) {
781 case SIPO_MODE_ANIMATION: /* all animation */
782 {
783 break;
784 }
785
786 case SIPO_MODE_DRIVERS: /* Drivers only. */
787 {
788 break;
789 }
790 }
791
792 /* region updates? */
793 /* XXX re-sizing y-extents of tot should go here? */
794
795 /* Update the state of the animchannels in response to changes from the data they represent
796 * NOTE: the temp flag is used to indicate when this needs to be done,
797 * and will be cleared once handled. */
800 sipo->runtime.flag &= ~SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC;
801 ED_area_tag_redraw(area);
802 }
803
804 /* We could check 'SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC_COLOR', but color is recalculated anyway. */
806 sipo->runtime.flag &= ~SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC_COLOR;
807#if 0 /* Done below. */
809#endif
810 ED_area_tag_redraw(area);
811 }
812
815
816 /* init/adjust F-Curve colors */
818}
819
820static void graph_id_remap(ScrArea * /*area*/,
821 SpaceLink *slink,
822 const blender::bke::id::IDRemapper &mappings)
823{
824 SpaceGraph *sgraph = (SpaceGraph *)slink;
825 if (!sgraph->ads) {
826 return;
827 }
828
829 mappings.apply(reinterpret_cast<ID **>(&sgraph->ads->filter_grp), ID_REMAP_APPLY_DEFAULT);
830 mappings.apply(reinterpret_cast<ID **>(&sgraph->ads->source), ID_REMAP_APPLY_DEFAULT);
831}
832
833static void graph_foreach_id(SpaceLink *space_link, LibraryForeachIDData *data)
834{
835 SpaceGraph *sgraph = reinterpret_cast<SpaceGraph *>(space_link);
836 const int data_flags = BKE_lib_query_foreachid_process_flags_get(data);
837 const bool is_readonly = (data_flags & IDWALK_READONLY) != 0;
838
839 /* NOTE: Could be deduplicated with the #bDopeSheet handling of #SpaceAction and #SpaceNla. */
840 if (sgraph->ads == nullptr) {
841 return;
842 }
843
846
847 if (!is_readonly) {
848 /* Force recalc of list of channels (i.e. including calculating F-Curve colors) to
849 * prevent the "black curves" problem post-undo. */
851 }
852}
853
855{
856 SpaceGraph *sgraph = static_cast<SpaceGraph *>(area->spacedata.first);
857 return sgraph->mode;
858}
859
860static void graph_space_subtype_set(ScrArea *area, int value)
861{
862 SpaceGraph *sgraph = static_cast<SpaceGraph *>(area->spacedata.first);
863 sgraph->mode = value;
864}
865
867 EnumPropertyItem **item,
868 int *totitem)
869{
871}
872
874{
875 SpaceGraph *sgraph = static_cast<SpaceGraph *>(area->spacedata.first);
876 const int index = RNA_enum_from_value(rna_enum_space_graph_mode_items, sgraph->mode);
878 return item.name;
879}
880
881static int graph_space_icon_get(const ScrArea *area)
882{
883 SpaceGraph *sgraph = static_cast<SpaceGraph *>(area->spacedata.first);
884 const int index = RNA_enum_from_value(rna_enum_space_graph_mode_items, sgraph->mode);
886 return item.icon;
887}
888
890{
891 SpaceGraph *sipo = (SpaceGraph *)sl;
892
893 BLO_read_struct(reader, bDopeSheet, &sipo->ads);
894 memset(&sipo->runtime, 0x0, sizeof(sipo->runtime));
895}
896
898{
899 SpaceGraph *sipo = (SpaceGraph *)sl;
900 ListBase tmpGhosts = sipo->runtime.ghost_curves;
901
902 /* temporarily disable ghost curves when saving */
904
905 BLO_write_struct(writer, SpaceGraph, sl);
906 if (sipo->ads) {
907 BLO_write_struct(writer, bDopeSheet, sipo->ads);
908 }
909
910 /* Re-enable ghost curves. */
911 sipo->runtime.ghost_curves = tmpGhosts;
912}
913
915{
916 std::unique_ptr<SpaceType> st = std::make_unique<SpaceType>();
917 ARegionType *art;
918
919 st->spaceid = SPACE_GRAPH;
920 STRNCPY(st->name, "Graph");
921
922 st->create = graph_create;
923 st->free = graph_free;
924 st->init = graph_init;
925 st->duplicate = graph_duplicate;
926 st->operatortypes = graphedit_operatortypes;
927 st->keymap = graphedit_keymap;
928 st->listener = graph_listener;
929 st->refresh = graph_refresh;
930 st->id_remap = graph_id_remap;
931 st->foreach_id = graph_foreach_id;
932 st->space_subtype_item_extend = graph_space_subtype_item_extend;
933 st->space_subtype_get = graph_space_subtype_get;
934 st->space_subtype_set = graph_space_subtype_set;
935 st->space_name_get = graph_space_name_get;
936 st->space_icon_get = graph_space_icon_get;
937 st->blend_read_data = graph_space_blend_read_data;
938 st->blend_read_after_liblink = nullptr;
939 st->blend_write = graph_space_blend_write;
940
941 /* regions: main window */
942 art = static_cast<ARegionType *>(MEM_callocN(sizeof(ARegionType), "spacetype graphedit region"));
950
951 BLI_addhead(&st->regiontypes, art);
952
953 /* regions: header */
954 art = static_cast<ARegionType *>(MEM_callocN(sizeof(ARegionType), "spacetype graphedit region"));
956 art->prefsizey = HEADERY;
961
962 BLI_addhead(&st->regiontypes, art);
963
964 /* regions: channels */
965 art = static_cast<ARegionType *>(MEM_callocN(sizeof(ARegionType), "spacetype graphedit region"));
967 /* 200 is the 'standard', but due to scrollers, we want a bit more to fit the lock icons in */
968 art->prefsizex = 200 + V2D_SCROLL_WIDTH;
974
975 BLI_addhead(&st->regiontypes, art);
976
977 /* regions: UI buttons */
978 art = static_cast<ARegionType *>(MEM_callocN(sizeof(ARegionType), "spacetype graphedit region"));
979 art->regionid = RGN_TYPE_UI;
985
986 BLI_addhead(&st->regiontypes, art);
987
989
990 art = ED_area_type_hud(st->spaceid);
991 BLI_addhead(&st->regiontypes, art);
992
993 BKE_spacetype_register(std::move(st));
994}
SpaceGraph * CTX_wm_space_graph(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
int BKE_lib_query_foreachid_process_flags_get(const LibraryForeachIDData *data)
Definition lib_query.cc:120
@ IDWALK_READONLY
#define BKE_LIB_FOREACHID_PROCESS_ID(data_, id_, cb_flag_)
@ ID_REMAP_APPLY_DEFAULT
void BKE_spacetype_register(std::unique_ptr< SpaceType > st)
Definition screen.cc:268
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:90
void void void void void void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
Definition math_color.cc:57
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition math_vector.c:36
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.c:418
#define STRNCPY(dst, src)
Definition BLI_string.h:593
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.
@ SCER_PRV_RANGE
#define MAXFRAMEF
#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_HEADER
@ 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
@ USER_HEADER_BOTTOM
#define UI_SCALE_FAC
@ 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:25
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:708
ARegionType * ED_area_type_hud(int space_type)
void ED_region_panels(const bContext *C, ARegion *region)
Definition area.cc:3336
void ED_region_header(const bContext *C, ARegion *region)
Definition area.cc:3646
void ED_region_header_init(ARegion *region)
Definition area.cc:3661
void ED_area_tag_refresh(ScrArea *area)
Definition area.cc:737
void ED_region_panels_init(wmWindowManager *wm, ARegion *region)
Definition area.cc:3343
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
@ ED_KEYMAP_UI
Definition ED_screen.hh:725
@ ED_KEYMAP_ANIMATION
Definition ED_screen.hh:729
@ ED_KEYMAP_HEADER
Definition ED_screen.hh:731
@ ED_KEYMAP_VIEW2D
Definition ED_screen.hh:728
@ ED_KEYMAP_FRAMES
Definition ED_screen.hh:730
void ED_region_do_msg_notify_tag_redraw(bContext *C, wmMsgSubscribeKey *msg_key, wmMsgSubscribeValue *msg_val)
Definition area.cc:381
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 immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset)
void immVertex2f(uint attr_id, float x, float y)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
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
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
void GPU_line_width(float width)
Definition gpu_state.cc:161
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
#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_Z
void UI_ThemeClearColor(int colorid)
void UI_SetTheme(int spacetype, int regionid)
void UI_view2d_view_orthoSpecial(ARegion *region, View2D *v2d, bool xaxis)
Definition view2d.cc:1132
void UI_view2d_draw_lines_x__frames_or_seconds(const View2D *v2d, const Scene *scene, bool display_seconds)
void UI_view2d_curRect_clamp_y(View2D *v2d)
Definition view2d.cc:840
#define V2D_SCROLL_WIDTH
Definition UI_view2d.hh:54
void UI_view2d_scrollers_draw(View2D *v2d, const rcti *mask_custom)
Definition view2d.cc:1605
void UI_view2d_draw_lines_y__values(const View2D *v2d)
void UI_view2d_view_restore(const bContext *C)
Definition view2d.cc:1158
void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
Definition view2d.cc:212
#define UI_TIME_SCRUB_MARGIN_Y
Definition UI_view2d.hh:472
void UI_view2d_view_ortho(const View2D *v2d)
Definition view2d.cc:1091
void UI_view2d_draw_scale_y__values(const ARegion *region, const View2D *v2d, const rcti *rect, int colorid)
@ V2D_COMMONVIEW_LIST
Definition UI_view2d.hh:35
@ V2D_COMMONVIEW_CUSTOM
Definition UI_view2d.hh:31
#define ND_SEQUENCER
Definition WM_types.hh:404
#define NC_WINDOW
Definition WM_types.hh:342
#define NC_ID
Definition WM_types.hh:362
#define NC_NODE
Definition WM_types.hh:361
#define ND_OB_ACTIVE
Definition WM_types.hh:407
#define ND_RENDER_OPTIONS
Definition WM_types.hh:402
#define NC_ANIMATION
Definition WM_types.hh:355
#define NC_SCREEN
Definition WM_types.hh:344
#define ND_OB_SELECT
Definition WM_types.hh:409
#define NC_SCENE
Definition WM_types.hh:345
#define ND_MODIFIER
Definition WM_types.hh:429
#define NA_EDITED
Definition WM_types.hh:550
#define ND_SPACE_GRAPH
Definition WM_types.hh:498
#define ND_FRAME_RANGE
Definition WM_types.hh:418
#define ND_MARKERS
Definition WM_types.hh:400
#define ND_FRAME
Definition WM_types.hh:401
#define ND_BONE_ACTIVE
Definition WM_types.hh:426
#define ND_TRANSFORM
Definition WM_types.hh:423
#define ND_LAYER
Definition WM_types.hh:417
#define ND_KEYS
Definition WM_types.hh:430
#define NA_RENAME
Definition WM_types.hh:554
#define ND_BONE_SELECT
Definition WM_types.hh:427
#define ND_KEYFRAME
Definition WM_types.hh:461
#define NC_OBJECT
Definition WM_types.hh:346
#define ND_ANIMCHAN
Definition WM_types.hh:463
#define NC_SPACE
Definition WM_types.hh:359
#define NA_SELECTED
Definition WM_types.hh:555
float ANIM_UI_get_channels_total_height(View2D *v2d, const int item_count)
void ANIM_animdata_freelist(ListBase *anim_data)
Definition anim_deps.cc:457
void ANIM_sync_animchannels_to_data(const bContext *C)
Definition anim_deps.cc:255
void ANIM_draw_previewrange(const bContext *C, View2D *v2d, int end_frame_width)
Definition anim_draw.cc:73
void ANIM_draw_framerange(Scene *scene, View2D *v2d)
Definition anim_draw.cc:107
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])
void ED_markers_draw(const bContext *C, int flag)
unsigned int U
Definition btGjkEpa3.h:78
IDRemapperApplyResult apply(ID **r_id_ptr, IDRemapperApplyOptions options, ID *id_self=nullptr) const
draw_view in_light_buf[] float
uint col
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:420
void graphedit_keymap(wmKeyConfig *keyconf)
Definition graph_ops.cc:524
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:42
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
format
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
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:192
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 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
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)
const char * name
Definition RNA_types.hh:510
float color[3]
int array_index
Definition DNA_ID.h:413
void * first
StructRNA * type
Definition RNA_types.hh:41
struct bDopeSheet * ads
SpaceGraph_Runtime runtime
ListBase regionbase
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:325
unsigned int action
Definition WM_types.hh:325
unsigned int category
Definition WM_types.hh:325
struct wmKeyConfig * defaultconf
rcti ED_time_scrub_clamp_scroller_mask(const rcti &scroller_mask)
void ED_time_scrub_draw_current_frame(const ARegion *region, const Scene *scene, bool display_seconds)
void ED_time_scrub_channel_search_draw(const bContext *C, ARegion *region, bDopeSheet *dopesheet)
void ED_time_scrub_draw(const ARegion *region, const Scene *scene, bool display_seconds, bool discrete_frames)
wmEventHandler_Keymap * WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
wmEventHandler_Keymap * WM_event_add_keymap_handler_v2d_mask(ListBase *handlers, wmKeyMap *keymap)
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:897
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)