Blender V5.0
scene_edit.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstdio>
10#include <cstring>
11
12#include "BLI_listbase.h"
13#include "BLI_string_utf8.h"
14
15#include "DNA_sequence_types.h"
16
17#include "BKE_context.hh"
18#include "BKE_global.hh"
19#include "BKE_layer.hh"
20#include "BKE_lib_id.hh"
21#include "BKE_main.hh"
22#include "BKE_node.hh"
23#include "BKE_report.hh"
24#include "BKE_scene.hh"
25
26#include "DEG_depsgraph.hh"
28
29#include "BLT_translation.hh"
30
31#include "ED_render.hh"
32#include "ED_scene.hh"
33#include "ED_screen.hh"
34#include "ED_util.hh"
35
36#include "SEQ_relations.hh"
37#include "SEQ_select.hh"
38#include "SEQ_sequencer.hh"
39
40#include "RNA_access.hh"
41#include "RNA_define.hh"
42
43#include "WM_api.hh"
44#include "WM_types.hh"
45
46/* -------------------------------------------------------------------- */
49
50static Scene *scene_add(Main *bmain, Scene *scene_old, eSceneCopyMethod method)
51{
52 Scene *scene_new = nullptr;
53 if (method == SCE_COPY_NEW) {
54 scene_new = BKE_scene_add(bmain, DATA_("Scene"));
55 }
56 else { /* different kinds of copying */
57 /* We are going to deep-copy collections, objects and various object data, we need to have
58 * up-to-date obdata for that. */
59 if (method == SCE_COPY_FULL) {
61 }
62
63 scene_new = BKE_scene_duplicate(bmain,
64 scene_old,
65 method,
66 static_cast<eDupli_ID_Flags>(U.dupflag | USER_DUP_OBJECT),
68 }
69
70 return scene_new;
71}
72
74{
75 Scene *active_scene = CTX_data_scene(C);
76 Scene *scene_new = scene_add(bmain, active_scene, method);
77
78 return scene_new;
79}
80
82{
83 Scene *scene_old = WM_window_get_active_scene(win);
84 Scene *scene_new = scene_add(bmain, scene_old, method);
85
86 WM_window_set_active_scene(bmain, C, win, scene_new);
87
89
90 return scene_new;
91}
92
93bool ED_scene_delete(bContext *C, Main *bmain, Scene *scene)
94{
95 Scene *scene_new;
96
97 /* kill running jobs */
98 wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
100
101 /* Cancel animation playback. */
103 ScreenAnimData *sad = static_cast<ScreenAnimData *>(screen->animtimer->customdata);
104 if (sad->scene == scene) {
106 }
107 }
108
109 if (scene->id.prev) {
110 scene_new = static_cast<Scene *>(scene->id.prev);
111 }
112 else if (scene->id.next) {
113 scene_new = static_cast<Scene *>(scene->id.next);
114 }
115 else {
116 return false;
117 }
118
119 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
120 if (win->parent != nullptr) { /* We only care about main windows here... */
121 continue;
122 }
123 if (win->scene == scene) {
124 WM_window_set_active_scene(bmain, C, win, scene_new);
125 }
126 }
127
128 /* Update scenes used by the sequencer. */
129 LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
130 if (workspace->sequencer_scene == scene) {
131 workspace->sequencer_scene = scene_new;
133 }
134 }
135
136 BKE_id_delete(bmain, scene);
137
138 return true;
139}
140
141void ED_scene_change_update(Main *bmain, Scene *scene, ViewLayer *layer)
142{
143 Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, layer);
144
145 BKE_scene_set_background(bmain, scene);
147 DEG_tag_on_visible_update(bmain, false);
148
149 ED_render_engine_changed(bmain, false);
151}
152
153static bool view_layer_remove_poll(const Scene *scene, const ViewLayer *layer)
154{
155 const int act = BLI_findindex(&scene->view_layers, layer);
156
157 if (act == -1) {
158 return false;
159 }
160 if ((scene->view_layers.first == scene->view_layers.last) && (scene->view_layers.first == layer))
161 {
162 /* ensure 1 layer is kept */
163 return false;
164 }
165
166 return true;
167}
168
169static void view_layer_remove_unset_nodetrees(const Main *bmain, Scene *scene, ViewLayer *layer)
170{
171 int act_layer_index = BLI_findindex(&scene->view_layers, layer);
172
173 for (Scene *sce = static_cast<Scene *>(bmain->scenes.first); sce;
174 sce = static_cast<Scene *>(sce->id.next))
175 {
176 if (sce->compositing_node_group) {
177 blender::bke::node_tree_remove_layer_n(sce->compositing_node_group, scene, act_layer_index);
178 }
179 }
180}
181
182bool ED_scene_view_layer_delete(Main *bmain, Scene *scene, ViewLayer *layer, ReportList *reports)
183{
184 if (view_layer_remove_poll(scene, layer) == false) {
185 if (reports) {
186 BKE_reportf(reports,
187 RPT_ERROR,
188 "View layer '%s' could not be removed from scene '%s'",
189 layer->name,
190 scene->id.name + 2);
191 }
192
193 return false;
194 }
195
196 /* We need to unset node-trees before removing the layer, otherwise its index will be -1. */
197 view_layer_remove_unset_nodetrees(bmain, scene, layer);
198
199 BLI_remlink(&scene->view_layers, layer);
201
202 /* Remove from windows. */
203 wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
204 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
205 if (win->scene == scene && STREQ(win->view_layer_name, layer->name)) {
206 ViewLayer *first_layer = BKE_view_layer_default_view(scene);
207 STRNCPY_UTF8(win->view_layer_name, first_layer->name);
208 }
209 }
210
212
213 BKE_view_layer_free(layer);
214
218
219 return true;
220}
221
223
224/* -------------------------------------------------------------------- */
227
229{
230 Main *bmain = CTX_data_main(C);
231 wmWindow *win = CTX_wm_window(C);
232 int type = RNA_enum_get(op->ptr, "type");
233
234 ED_scene_add(bmain, C, win, eSceneCopyMethod(type));
235
236 return OPERATOR_FINISHED;
237}
238
240 {SCE_COPY_NEW, "NEW", 0, "New", "Add a new, empty scene with default settings"},
242 "EMPTY",
243 0,
244 "Copy Settings",
245 "Add a new, empty scene, and copy settings from the current scene"},
247 "LINK_COPY",
248 0,
249 "Linked Copy",
250 "Link in the collections from the current scene (shallow copy)"},
251 {SCE_COPY_FULL, "FULL_COPY", 0, "Full Copy", "Make a full copy of the current scene"},
252 {0, nullptr, 0, nullptr, nullptr},
253};
254
256{
257
258 /* identifiers */
259 ot->name = "New Scene";
260 ot->description = "Add new scene by type";
261 ot->idname = "SCENE_OT_new";
262
263 /* API callbacks. */
264 ot->exec = scene_new_exec;
265 ot->invoke = WM_menu_invoke;
267
268 /* flags */
270
271 /* properties */
272 ot->prop = RNA_def_enum(ot->srna, "type", scene_new_items, SCE_COPY_NEW, "Type", "");
274}
275
277
278/* -------------------------------------------------------------------- */
281
283{
284 Main *bmain = CTX_data_main(C);
285 int type = RNA_enum_get(op->ptr, "type");
286 Scene *sequencer_scene = CTX_data_sequencer_scene(C);
287 Strip *strip = blender::seq::select_active_get(sequencer_scene);
288 BLI_assert(strip != nullptr);
289
290 if (!strip->scene) {
291 return OPERATOR_CANCELLED;
292 }
293
294 Scene *scene_new = scene_add(bmain, strip->scene, eSceneCopyMethod(type));
295 if (!scene_new) {
296 return OPERATOR_CANCELLED;
297 }
298 strip->scene = scene_new;
299 /* Do a refresh of the sequencer data. */
300 blender::seq::relations_invalidate_cache_raw(sequencer_scene, strip);
303 return OPERATOR_FINISHED;
304}
305
307{
309 const Strip *strip = blender::seq::select_active_get(scene);
310 return (strip && (strip->type == STRIP_TYPE_SCENE));
311}
312
314 PointerRNA * /*ptr*/,
315 PropertyRNA * /*prop*/,
316 bool *r_free)
317{
318 EnumPropertyItem *item = nullptr;
319 int totitem = 0;
320 uint item_index;
321
323 RNA_enum_item_add(&item, &totitem, &scene_new_items[item_index]);
324
325 bool has_scene_or_no_context = false;
326 if (C == nullptr) {
327 /* For documentation generation. */
328 has_scene_or_no_context = true;
329 }
330 else {
333 if (strip && (strip->type == STRIP_TYPE_SCENE) && (strip->scene != nullptr)) {
334 has_scene_or_no_context = true;
335 }
336 }
337
338 if (has_scene_or_no_context) {
340 for (int i = 0; i < ARRAY_SIZE(values); i++) {
341 item_index = RNA_enum_from_value(scene_new_items, values[i]);
342 RNA_enum_item_add(&item, &totitem, &scene_new_items[item_index]);
343 }
344 }
345
346 RNA_enum_item_end(&item, &totitem);
347 *r_free = true;
348 return item;
349}
350
352{
353
354 /* identifiers */
355 ot->name = "New Scene";
356 ot->description = "Add new scene by type in the sequence editor and assign to active strip";
357 ot->idname = "SCENE_OT_new_sequencer";
358
359 /* API callbacks. */
361 ot->invoke = WM_menu_invoke;
363
364 /* flags */
366
367 /* properties */
368 ot->prop = RNA_def_enum(ot->srna, "type", scene_new_items, SCE_COPY_NEW, "Type", "");
371}
372
374
375/* -------------------------------------------------------------------- */
378
380{
381 Main *bmain = CTX_data_main(C);
382 wmWindow *win = CTX_wm_window(C);
383 WorkSpace *workspace = CTX_wm_workspace(C);
384 Scene *scene_old = CTX_data_sequencer_scene(C);
385 const int type = RNA_enum_get(op->ptr, "type");
386
387 Scene *new_scene = scene_add(bmain, scene_old, eSceneCopyMethod(type));
389
390 workspace->sequencer_scene = new_scene;
391
392 /* Switching the active scene to the newly created sequencer scene should prevent confusion among
393 * new users to the VSE. For example, this prevents the case where attempting to change
394 * resolution properties would have no effect.
395 *
396 * FIXME: This logic is meant to address a temporary papercut and may be removed later in 5.1+
397 * when properties for scenes and sequencer scenes can be more properly separated. */
398 WM_window_set_active_scene(bmain, C, win, new_scene);
400 op->reports, RPT_WARNING, TIP_("Active scene changed to '%s'"), new_scene->id.name + 2);
401
403 return OPERATOR_FINISHED;
404}
405
407 wmOperator *op,
408 const wmEvent *event)
409{
410 if (CTX_data_sequencer_scene(C) == nullptr) {
411 /* When there is no sequencer scene set, create a blank new one. */
412 RNA_enum_set(op->ptr, "type", SCE_COPY_NEW);
413 return new_sequencer_scene_exec(C, op);
414 }
415 return WM_menu_invoke(C, op, event);
416}
417
419{
420 /* identifiers */
421 ot->name = "New Sequencer Scene";
422 ot->description = "Add new scene to be used by the sequencer";
423 ot->idname = "SCENE_OT_new_sequencer_scene";
424
425 /* API callbacks. */
428
429 /* flags */
431
432 /* properties */
433 ot->prop = RNA_def_enum(ot->srna, "type", scene_new_items, SCE_COPY_NEW, "Type", "");
436}
437
439
440/* -------------------------------------------------------------------- */
443
445{
446 Main *bmain = CTX_data_main(C);
447 Scene *scene = CTX_data_scene(C);
448 return BKE_scene_can_be_removed(bmain, scene);
449}
450
452{
453 Scene *scene = CTX_data_scene(C);
454
455 if (ED_scene_delete(C, CTX_data_main(C), scene) == false) {
456 return OPERATOR_CANCELLED;
457 }
458
459 if (G.debug & G_DEBUG) {
460 printf("scene delete %p\n", scene);
461 }
462
464
465 return OPERATOR_FINISHED;
466}
467
469{
470 /* identifiers */
471 ot->name = "Delete Scene";
472 ot->description = "Delete active scene";
473 ot->idname = "SCENE_OT_delete";
474
475 /* API callbacks. */
476 ot->exec = scene_delete_exec;
477 ot->poll = scene_delete_poll;
478
479 /* flags */
481}
482
484
485/* -------------------------------------------------------------------- */
488
490{
491 Main *bmain = CTX_data_main(C);
492 Scene *scene_asset = reinterpret_cast<Scene *>(
494 if (!scene_asset) {
495 return OPERATOR_CANCELLED;
496 }
497
498 wmWindow *win = CTX_wm_window(C);
499 WM_window_set_active_scene(bmain, C, win, scene_asset);
500
502
503 return OPERATOR_FINISHED;
504}
505
507{
508 /* identifiers */
509 ot->name = "Drop Scene";
510 ot->description = "Import scene and set it as the active one in the window";
511 ot->idname = "SCENE_OT_drop_scene_asset";
512
513 /* callbacks */
515
516 /* flags */
518
520}
521
523
524/* -------------------------------------------------------------------- */
527
537
WorkSpace * CTX_wm_workspace(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
Scene * CTX_data_sequencer_scene(const bContext *C)
@ G_DEBUG
ViewLayer * BKE_view_layer_default_view(const Scene *scene)
void BKE_view_layer_free(ViewLayer *view_layer)
void BKE_id_delete(Main *bmain, void *idv) ATTR_NONNULL()
@ LIB_ID_DUPLICATE_IS_ROOT_ID
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
eSceneCopyMethod
Definition BKE_scene.hh:32
@ SCE_COPY_EMPTY
Definition BKE_scene.hh:34
@ SCE_COPY_NEW
Definition BKE_scene.hh:33
@ SCE_COPY_FULL
Definition BKE_scene.hh:36
@ SCE_COPY_LINK_COLLECTION
Definition BKE_scene.hh:35
void BKE_scene_free_view_layer_depsgraph(Scene *scene, ViewLayer *view_layer)
Definition scene.cc:3320
Depsgraph * BKE_scene_ensure_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer)
Definition scene.cc:3416
bool BKE_scene_can_be_removed(const Main *bmain, const Scene *scene)
Definition scene.cc:1986
Scene * BKE_scene_add(Main *bmain, const char *name)
Definition scene.cc:2001
Scene * BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type, eDupli_ID_Flags duplicate_flags, uint duplicate_options)
Definition scene.cc:1783
void BKE_scene_set_background(Main *bmain, Scene *sce)
Definition scene.cc:2034
#define BLI_assert(a)
Definition BLI_assert.h:46
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
#define STRNCPY_UTF8(dst, src)
unsigned int uint
#define ARRAY_SIZE(arr)
#define STREQ(a, b)
#define TIP_(msgid)
#define BLT_I18NCONTEXT_ID_SCENE
#define DATA_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_tag_on_visible_update(Main *bmain, bool do_time)
void DEG_relations_tag_update(Main *bmain)
void DEG_graph_relations_update(Depsgraph *graph)
@ ID_RECALC_AUDIO
Definition DNA_ID.h:1132
@ ID_RECALC_SEQUENCER_STRIPS
Definition DNA_ID.h:1122
@ ID_RECALC_BASE_FLAGS
Definition DNA_ID.h:1104
@ ID_SCE
@ STRIP_TYPE_SCENE
eDupli_ID_Flags
@ USER_DUP_OBJECT
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
void ED_render_engine_changed(Main *bmain, bool update_scene_data)
wmOperatorStatus ED_screen_animation_play(bContext *C, int sync, int mode)
bScreen * ED_screen_animation_playing(const wmWindowManager *wm)
void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
bool ED_editors_flush_edits(Main *bmain)
Definition ed_util.cc:336
@ PROP_ENUM_NO_TRANSLATE
Definition RNA_types.hh:432
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
#define C
Definition RandGen.cpp:29
#define NC_WINDOW
Definition WM_types.hh:375
#define NC_SCENE
Definition WM_types.hh:378
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NA_REMOVED
Definition WM_types.hh:587
#define ND_LAYER
Definition WM_types.hh:450
#define ND_SCENEBROWSE
Definition WM_types.hh:432
#define U
BPy_StructRNA * depsgraph
#define printf(...)
#define G(x, y, z)
void node_tree_remove_layer_n(bNodeTree *ntree, Scene *scene, int layer_index)
Definition node.cc:5527
void relations_invalidate_cache_raw(Scene *scene, Strip *strip)
Editing * editing_ensure(Scene *scene)
Definition sequencer.cc:291
Strip * select_active_get(const Scene *scene)
int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
void RNA_enum_item_add(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
static void SCENE_OT_new_sequencer_scene(wmOperatorType *ot)
static const EnumPropertyItem * scene_new_sequencer_enum_itemf(bContext *C, PointerRNA *, PropertyRNA *, bool *r_free)
Scene * ED_scene_add(Main *bmain, bContext *C, wmWindow *win, eSceneCopyMethod method)
Definition scene_edit.cc:81
static void view_layer_remove_unset_nodetrees(const Main *bmain, Scene *scene, ViewLayer *layer)
static wmOperatorStatus new_sequencer_scene_invoke(bContext *C, wmOperator *op, const wmEvent *event)
bool ED_scene_delete(bContext *C, Main *bmain, Scene *scene)
Definition scene_edit.cc:93
static void SCENE_OT_new(wmOperatorType *ot)
static void SCENE_OT_new_sequencer(wmOperatorType *ot)
static void SCENE_OT_drop_scene_asset(wmOperatorType *ot)
static wmOperatorStatus drop_scene_asset_exec(bContext *C, wmOperator *op)
static Scene * scene_add(Main *bmain, Scene *scene_old, eSceneCopyMethod method)
Definition scene_edit.cc:50
static wmOperatorStatus scene_new_sequencer_exec(bContext *C, wmOperator *op)
bool ED_scene_view_layer_delete(Main *bmain, Scene *scene, ViewLayer *layer, ReportList *reports)
static bool scene_delete_poll(bContext *C)
Scene * ED_scene_sequencer_add(Main *bmain, bContext *C, eSceneCopyMethod method)
Definition scene_edit.cc:73
void ED_operatortypes_scene()
static bool scene_new_sequencer_poll(bContext *C)
static wmOperatorStatus scene_delete_exec(bContext *C, wmOperator *)
static bool view_layer_remove_poll(const Scene *scene, const ViewLayer *layer)
static void SCENE_OT_delete(wmOperatorType *ot)
void ED_scene_change_update(Main *bmain, Scene *scene, ViewLayer *layer)
static wmOperatorStatus new_sequencer_scene_exec(bContext *C, wmOperator *op)
static EnumPropertyItem scene_new_items[]
static wmOperatorStatus scene_new_exec(bContext *C, wmOperator *op)
char name[258]
Definition DNA_ID.h:432
void * prev
Definition DNA_ID.h:417
void * next
Definition DNA_ID.h:417
void * last
void * first
ListBase scenes
Definition BKE_main.hh:278
ListBase wm
Definition BKE_main.hh:307
ListBase workspaces
Definition BKE_main.hh:315
ListBase view_layers
struct Scene * scene
char name[64]
struct Scene * sequencer_scene
struct ReportList * reports
struct PointerRNA * ptr
i
Definition text_draw.cc:230
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4237
void WM_jobs_kill_all_from_owner(wmWindowManager *wm, const void *owner)
Definition wm_jobs.cc:638
ID * WM_operator_properties_id_lookup_from_name_or_session_uid(Main *bmain, PointerRNA *ptr, const ID_Type type)
void WM_operator_properties_id_lookup(wmOperatorType *ot, const bool add_name_prop)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
wmOperatorStatus WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *)
bool WM_operator_winactive(bContext *C)
void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene)
Scene * WM_window_get_active_scene(const wmWindow *win)