Blender  V3.3
spreadsheet_context.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "MEM_guardedalloc.h"
4 
5 #include "BLI_hash.h"
6 #include "BLI_hash.hh"
7 #include "BLI_hash_mm2a.h"
8 #include "BLI_listbase.h"
9 #include "BLI_string.h"
10 #include "BLI_utildefines.h"
11 #include "BLI_vector.hh"
12 
13 #include "ED_screen.h"
14 #include "ED_spreadsheet.h"
15 
16 #include "DEG_depsgraph.h"
17 
18 #include "BKE_context.h"
19 #include "BKE_main.h"
20 #include "BKE_modifier.h"
21 #include "BKE_node.h"
22 #include "BKE_object.h"
23 #include "BKE_workspace.h"
24 
25 #include "DNA_modifier_types.h"
27 
28 #include "spreadsheet_context.hh"
29 
31 using blender::Span;
32 using blender::StringRef;
33 using blender::Vector;
34 
35 namespace blender::ed::spreadsheet {
36 
38 {
39  SpreadsheetContextObject *context = MEM_cnew<SpreadsheetContextObject>(__func__);
41  return context;
42 }
43 
45  const SpreadsheetContextObject *src_context)
46 {
48  new_context->object = src_context->object;
49  return new_context;
50 }
51 
53  BLI_HashMurmur2A *mm2)
54 {
55  BLI_hash_mm2a_add(mm2, (const uchar *)&context->object, sizeof(Object *));
56 }
57 
59 {
61 }
62 
64 {
65  SpreadsheetContextModifier *context = MEM_cnew<SpreadsheetContextModifier>(__func__);
67  return context;
68 }
69 
71  const SpreadsheetContextModifier *src_context)
72 {
74  if (src_context->modifier_name) {
75  new_context->modifier_name = BLI_strdup(src_context->modifier_name);
76  }
77  return new_context;
78 }
79 
81  BLI_HashMurmur2A *mm2)
82 {
83  if (context->modifier_name) {
84  BLI_hash_mm2a_add(mm2, (const uchar *)context->modifier_name, strlen(context->modifier_name));
85  }
86 }
87 
89 {
90  if (context->modifier_name) {
91  MEM_freeN(context->modifier_name);
92  }
94 }
95 
97 {
98  SpreadsheetContextNode *context = MEM_cnew<SpreadsheetContextNode>(__func__);
99  context->base.type = SPREADSHEET_CONTEXT_NODE;
100  return context;
101 }
102 
104  const SpreadsheetContextNode *src_context)
105 {
107  if (src_context->node_name) {
108  new_context->node_name = BLI_strdup(src_context->node_name);
109  }
110  return new_context;
111 }
112 
114  BLI_HashMurmur2A *mm2)
115 {
116  if (context->node_name) {
117  BLI_hash_mm2a_add(mm2, (const uchar *)context->node_name, strlen(context->node_name));
118  }
119 }
120 
122 {
123  if (context->node_name) {
124  MEM_freeN(context->node_name);
125  }
127 }
128 
130 {
131  switch (type) {
134  }
137  }
140  }
141  }
143  return nullptr;
144 }
145 
147 {
148  switch (old_context->type) {
151  (const SpreadsheetContextObject *)old_context);
152  }
155  (const SpreadsheetContextModifier *)old_context);
156  }
159  (const SpreadsheetContextNode *)old_context);
160  }
161  }
163  return nullptr;
164 }
165 
167 {
168  BLI_hash_mm2a_add_int(mm2, context->type);
169  switch (context->type) {
172  break;
173  }
176  break;
177  }
180  break;
181  }
182  }
183 }
184 
186 {
187  switch (context->type) {
190  }
193  }
196  }
197  }
199 }
200 
207 {
208  using namespace blender;
209  Vector<const SpreadsheetContext *> context_path = sspreadsheet->context_path;
210  if (context_path.is_empty()) {
211  return false;
212  }
213  if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
214  return false;
215  }
216  SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context_path[0];
217  Object *object = object_context->object;
218  if (object == nullptr) {
219  return false;
220  }
221  if (context_path.size() == 1) {
222  /* No need to reevaluate, when the final or original object is viewed. */
223  return false;
224  }
225 
227  return true;
228 }
229 
230 } // namespace blender::ed::spreadsheet
231 
233 {
235 }
236 
238 {
240 }
241 
243 {
246  }
247  BLI_listbase_clear(&sspreadsheet->context_path);
248 }
249 
251 {
253 }
254 
256 {
257  BLI_HashMurmur2A mm2;
258  BLI_hash_mm2a_init(&mm2, 1234);
259  LISTBASE_FOREACH (const SpreadsheetContext *, context, &sspreadsheet->context_path) {
261  }
262  return BLI_hash_mm2a_end(&mm2);
263 }
264 
266  struct SpaceNode *snode,
267  struct bNode *node)
268 {
269  using namespace blender::ed::spreadsheet;
270 
271  Object *object = (Object *)snode->id;
272  /* Try to find the modifier the node tree belongs to. */
273  ModifierData *modifier = BKE_object_active_modifier(object);
274  if (modifier && modifier->type != eModifierType_Nodes) {
275  modifier = nullptr;
276  LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
277  if (md->type == eModifierType_Nodes) {
279  if (nmd->node_group == snode->nodetree) {
280  modifier = md;
281  break;
282  }
283  }
284  }
285  }
286  if (modifier == nullptr) {
287  return;
288  }
289 
290  ED_spreadsheet_context_path_clear(sspreadsheet);
291 
292  {
294  context->object = object;
295  BLI_addtail(&sspreadsheet->context_path, context);
296  }
297  {
299  context->modifier_name = BLI_strdup(modifier->name);
300  BLI_addtail(&sspreadsheet->context_path, context);
301  }
302  {
303  int i;
304  LISTBASE_FOREACH_INDEX (bNodeTreePath *, path, &snode->treepath, i) {
305  if (i == 0) {
306  continue;
307  }
309  context->node_name = BLI_strdup(path->node_name);
310  BLI_addtail(&sspreadsheet->context_path, context);
311  }
312  }
313  {
315  context->node_name = BLI_strdup(node->name);
316  BLI_addtail(&sspreadsheet->context_path, context);
317  }
318 
320 }
321 
323 {
324  wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
325  if (wm == nullptr) {
326  return;
327  }
328  LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
329  bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
330  LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
331  SpaceLink *sl = (SpaceLink *)area->spacedata.first;
332  if (sl->spacetype == SPACE_SPREADSHEET) {
333  SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
334  if ((sspreadsheet->flag & SPREADSHEET_FLAG_PINNED) == 0) {
335  const uint64_t context_hash_before = ED_spreadsheet_context_path_hash(sspreadsheet);
337  const uint64_t context_hash_after = ED_spreadsheet_context_path_hash(sspreadsheet);
338  if (context_hash_before != context_hash_after) {
340  }
342  }
343  }
344  }
345  }
346 }
347 
349  Object *object)
350 {
351  using namespace blender::ed::spreadsheet;
352  ED_spreadsheet_context_path_clear(sspreadsheet);
353 
355  context->object = object;
356  BLI_addtail(&sspreadsheet->context_path, context);
357 }
358 
360  SpaceSpreadsheet *current_space)
361 {
363  if (ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL)) {
364  /* If the spreadsheet is maximized, try to find the context in the unmaximized screen. */
365  ScrArea *main_area = (ScrArea *)screen->areabase.first;
366  SpaceLink *sl = (SpaceLink *)main_area->spacedata.first;
367  if (sl == (SpaceLink *)current_space) {
368  return main_area->full;
369  }
370  }
371  return screen;
372 }
373 
375 {
376  ED_spreadsheet_context_path_clear(sspreadsheet);
377 
378  Main *bmain = CTX_data_main(C);
379  wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
380  if (wm == nullptr) {
381  return;
382  }
383 
385  LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
386  bScreen *screen = find_screen_to_search_for_context(window, sspreadsheet);
387  LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
388  SpaceLink *sl = (SpaceLink *)area->spacedata.first;
389  if (sl == nullptr) {
390  continue;
391  }
392  if (sl->spacetype == SPACE_NODE) {
393  SpaceNode *snode = (SpaceNode *)sl;
394  if (snode->edittree != nullptr) {
395  if (snode->edittree->type == NTREE_GEOMETRY) {
396  LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
397  if (node->type == GEO_NODE_VIEWER) {
398  if (node->flag & NODE_DO_OUTPUT) {
400  return;
401  }
402  }
403  }
404  }
405  }
406  }
407  }
408  }
409  }
410 
411  Object *active_object = CTX_data_active_object(C);
412  if (active_object != nullptr) {
413  ED_spreadsheet_context_path_set_evaluated_object(sspreadsheet, active_object);
414  return;
415  }
416 }
417 
419 {
420  Main *bmain = CTX_data_main(C);
421  wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
422  if (wm == nullptr) {
423  return false;
424  }
425  Vector<SpreadsheetContext *> context_path = sspreadsheet->context_path;
426  if (context_path.is_empty()) {
427  return false;
428  }
429  if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
430  return false;
431  }
432  Object *object = ((SpreadsheetContextObject *)context_path[0])->object;
433  if (object == nullptr) {
434  return false;
435  }
436  if (context_path.size() == 1) {
438  return false;
439  }
440  Object *active_object = CTX_data_active_object(C);
441  return object == active_object;
442  }
444  return false;
445  }
446  if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) {
447  return false;
448  }
449  const char *modifier_name = ((SpreadsheetContextModifier *)context_path[1])->modifier_name;
450  const ModifierData *modifier = BKE_modifiers_findby_name(object, modifier_name);
451  if (modifier == nullptr) {
452  return false;
453  }
454  const bool modifier_is_active = modifier->flag & eModifierFlag_Active;
455  if (modifier->type != eModifierType_Nodes) {
456  return false;
457  }
458  bNodeTree *root_node_tree = ((NodesModifierData *)modifier)->node_group;
459  if (root_node_tree == nullptr) {
460  return false;
461  }
462  const Span<SpreadsheetContext *> node_context_path = context_path.as_span().drop_front(2);
463  if (node_context_path.is_empty()) {
464  return false;
465  }
466 
467  LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
468  bScreen *screen = find_screen_to_search_for_context(window, sspreadsheet);
469  LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
470  SpaceLink *sl = (SpaceLink *)area->spacedata.first;
471  if (sl == nullptr) {
472  continue;
473  }
474  if (sl->spacetype != SPACE_NODE) {
475  continue;
476  }
477  SpaceNode *snode = (SpaceNode *)sl;
478  if (snode->nodetree != root_node_tree) {
479  continue;
480  }
481  if (!modifier_is_active) {
482  if (!(snode->flag & SNODE_PIN)) {
483  /* Node tree has to be pinned when the modifier is not active. */
484  continue;
485  }
486  }
487  if (snode->id != &object->id) {
488  continue;
489  }
490  Vector<bNodeTreePath *> tree_path = snode->treepath;
491  if (node_context_path.size() != tree_path.size()) {
492  continue;
493  }
494  int valid_count = 0;
495  for (const int i : IndexRange(tree_path.size() - 1)) {
496  if (node_context_path[i]->type != SPREADSHEET_CONTEXT_NODE) {
497  break;
498  }
500  if (!STREQ(node_context->node_name, tree_path[i + 1]->node_name)) {
501  break;
502  }
503  valid_count++;
504  }
505  if (valid_count != tree_path.size() - 1) {
506  continue;
507  }
508  SpreadsheetContext *last_context = node_context_path.last();
509  if (last_context->type != SPREADSHEET_CONTEXT_NODE) {
510  return false;
511  }
512  const char *node_name = ((SpreadsheetContextNode *)last_context)->node_name;
513  bNode *node = nodeFindNodebyName(snode->edittree, node_name);
514  if (node == nullptr) {
515  return false;
516  }
517  if (node->type != GEO_NODE_VIEWER) {
518  return false;
519  }
520  if (!(node->flag & NODE_DO_OUTPUT)) {
521  return false;
522  }
523  return true;
524  }
525  }
526  return false;
527 }
528 
530 {
531  Vector<SpreadsheetContext *> context_path = sspreadsheet->context_path;
532  if (context_path.is_empty()) {
533  return false;
534  }
535  if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
536  return false;
537  }
538  Object *object = ((SpreadsheetContextObject *)context_path[0])->object;
539  if (object == nullptr) {
540  return false;
541  }
542  if (context_path.size() == 1) {
543  return true;
544  }
545  if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) {
546  return false;
547  }
548  const char *modifier_name = ((SpreadsheetContextModifier *)context_path[1])->modifier_name;
549  const ModifierData *modifier = BKE_modifiers_findby_name(object, modifier_name);
550  if (modifier == nullptr) {
551  return false;
552  }
553  if (modifier->type != eModifierType_Nodes) {
554  return false;
555  }
556  bNodeTree *root_node_tree = ((NodesModifierData *)modifier)->node_group;
557  if (root_node_tree == nullptr) {
558  return false;
559  }
560  const Span<SpreadsheetContext *> node_context_path = context_path.as_span().drop_front(2);
561  if (node_context_path.is_empty()) {
562  return false;
563  }
564  bNodeTree *node_tree = root_node_tree;
565  for (const int i : node_context_path.index_range()) {
566  if (node_context_path[i]->type != SPREADSHEET_CONTEXT_NODE) {
567  return false;
568  }
569  const char *node_name = ((SpreadsheetContextNode *)node_context_path[i])->node_name;
570  bNode *node = nodeFindNodebyName(node_tree, node_name);
571  if (node == nullptr) {
572  return false;
573  }
574  if (node->type == GEO_NODE_VIEWER) {
575  if (i == node_context_path.index_range().last()) {
576  return true;
577  }
578  return false;
579  }
580  if (node->id != nullptr) {
581  if (GS(node->id->name) != ID_NT) {
582  return false;
583  }
584  node_tree = (bNodeTree *)node->id;
585  }
586  else {
587  return false;
588  }
589  }
590  return false;
591 }
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct ModifierData * BKE_modifiers_findby_name(const struct Object *ob, const char *name)
#define GEO_NODE_VIEWER
Definition: BKE_node.h:1413
struct bNode * nodeFindNodebyName(struct bNodeTree *ntree, const char *name)
Definition: node.cc:1992
General operations, lookup, etc. for blender objects.
struct ModifierData * BKE_object_active_modifier(const struct Object *ob)
struct bScreen * BKE_workspace_active_screen_get(const struct WorkSpaceInstanceHook *hook) GETTER_ATTRS
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
void BLI_hash_mm2a_init(BLI_HashMurmur2A *mm2, uint32_t seed)
Definition: hash_mm2a.c:61
void BLI_hash_mm2a_add(BLI_HashMurmur2A *mm2, const unsigned char *data, size_t len)
Definition: hash_mm2a.c:69
void BLI_hash_mm2a_add_int(BLI_HashMurmur2A *mm2, int data)
Definition: hash_mm2a.c:84
uint32_t BLI_hash_mm2a_end(BLI_HashMurmur2A *mm2)
Definition: hash_mm2a.c:89
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:354
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
Definition: BLI_listbase.h:344
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:42
unsigned char uchar
Definition: BLI_sys_types.h:70
#define UNUSED(x)
#define ELEM(...)
#define STREQ(a, b)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ ID_NT
Definition: DNA_ID_enums.h:68
@ eModifierFlag_Active
@ eModifierType_Nodes
#define NODE_DO_OUTPUT
#define NTREE_GEOMETRY
@ SCREENFULL
@ SCREENMAXIMIZED
@ SNODE_PIN
eSpaceSpreadsheet_ContextType
@ SPREADSHEET_CONTEXT_OBJECT
@ SPREADSHEET_CONTEXT_MODIFIER
@ SPREADSHEET_CONTEXT_NODE
@ SPACE_NODE
@ SPACE_SPREADSHEET
@ SPREADSHEET_OBJECT_EVAL_STATE_VIEWER_NODE
@ SPREADSHEET_FLAG_PINNED
void ED_area_tag_redraw(ScrArea *area)
Definition: area.c:729
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:25
constexpr int64_t last(const int64_t n=0) const
constexpr const T & last(const int64_t n=0) const
Definition: BLI_span.hh:313
constexpr int64_t size() const
Definition: BLI_span.hh:240
constexpr IndexRange index_range() const
Definition: BLI_span.hh:401
constexpr bool is_empty() const
Definition: BLI_span.hh:248
int64_t size() const
Definition: BLI_vector.hh:694
Span< T > as_span() const
Definition: BLI_vector.hh:325
bool is_empty() const
Definition: BLI_vector.hh:706
OperationNode * node
#define GS(x)
Definition: iris.c:225
static const char * modifier_name[LS_MODIFIER_NUM]
Definition: linestyle.c:763
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
static void area(int d1, int d2, int e1, int e2, float weights[2])
static int node_context(const bContext *C, const char *member, bContextDataResult *result)
Definition: space_node.cc:834
static SpreadsheetContextModifier * spreadsheet_context_modifier_new()
SpreadsheetContext * spreadsheet_context_copy(const SpreadsheetContext *old_context)
void spreadsheet_context_free(SpreadsheetContext *context)
static bool spreadsheet_context_update_tag(SpaceSpreadsheet *sspreadsheet)
static void spreadsheet_context_modifier_hash(const SpreadsheetContextModifier *context, BLI_HashMurmur2A *mm2)
static SpreadsheetContextModifier * spreadsheet_context_modifier_copy(const SpreadsheetContextModifier *src_context)
static SpreadsheetContextNode * spreadsheet_context_node_copy(const SpreadsheetContextNode *src_context)
static void spreadsheet_context_modifier_free(SpreadsheetContextModifier *context)
static void spreadsheet_context_node_hash(const SpreadsheetContextNode *context, BLI_HashMurmur2A *mm2)
static void spreadsheet_context_node_free(SpreadsheetContextNode *context)
static void spreadsheet_context_object_free(SpreadsheetContextObject *context)
SpreadsheetContext * spreadsheet_context_new(eSpaceSpreadsheet_ContextType type)
static void spreadsheet_context_hash(const SpreadsheetContext *context, BLI_HashMurmur2A *mm2)
static SpreadsheetContextObject * spreadsheet_context_object_new()
static SpreadsheetContextObject * spreadsheet_context_object_copy(const SpreadsheetContextObject *src_context)
static SpreadsheetContextNode * spreadsheet_context_node_new()
static void spreadsheet_context_object_hash(const SpreadsheetContextObject *context, BLI_HashMurmur2A *mm2)
void ED_spreadsheet_context_path_set_geometry_node(struct SpaceSpreadsheet *sspreadsheet, struct SpaceNode *snode, struct bNode *node)
uint64_t ED_spreadsheet_context_path_hash(const SpaceSpreadsheet *sspreadsheet)
bool ED_spreadsheet_context_path_update_tag(SpaceSpreadsheet *sspreadsheet)
bool ED_spreadsheet_context_path_is_active(const bContext *C, SpaceSpreadsheet *sspreadsheet)
static bScreen * find_screen_to_search_for_context(wmWindow *window, SpaceSpreadsheet *current_space)
SpreadsheetContext * ED_spreadsheet_context_new(int type)
void ED_spreadsheet_context_path_set_evaluated_object(SpaceSpreadsheet *sspreadsheet, Object *object)
void ED_spreadsheet_context_paths_set_geometry_node(Main *bmain, SpaceNode *snode, bNode *node)
void ED_spreadsheet_context_path_clear(struct SpaceSpreadsheet *sspreadsheet)
bool ED_spreadsheet_context_path_exists(Main *UNUSED(bmain), SpaceSpreadsheet *sspreadsheet)
void ED_spreadsheet_context_free(struct SpreadsheetContext *context)
void ED_spreadsheet_context_path_guess(const bContext *C, SpaceSpreadsheet *sspreadsheet)
unsigned __int64 uint64_t
Definition: stdint.h:90
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
ListBase wm
Definition: BKE_main.h:197
struct bNodeTree * node_group
ListBase modifiers
ListBase spacedata
bScreen * full
ListBase treepath
struct bNodeTree * edittree
struct ID * id
struct bNodeTree * nodetree
ListBase nodes
ListBase areabase
struct WorkSpaceInstanceHook * workspace_hook