Spreadsheet: breadcrumbs and node pinning
This introduces a context path to the spreadsheet editor, which contains information about what data is shown in the spreadsheet. The context path (breadcrumbs) can reference a specific node in a node group hierarchy. During object evaluation, the geometry nodes modifier checks what data is currently requested by visible spreadsheets and stores the corresponding geometry sets separately for later access. The context path can be updated by the user explicitely, by clicking on the new icon in the header of nodes. Under some circumstances, the context path is updated automatically based on Blender's context. This patch also consolidates the "Node" and "Final" object evaluation mode to just "Evaluated". Based on the current context path, either the final geometry set of an object will be displayed, or the data at a specific node. The new preview icon in geometry nodes now behaves more like a toggle. It can be clicked again to clear the context path in an open spreadsheet editor. Previously, only an object could be pinned in the spreadsheet editor. Now it is possible to pin the entire context path. That allows two different spreadsheets to display geometry data from two different nodes. The breadcrumbs in the spreadsheet header can be collapsed by clicking on the arrow icons. It's not ideal but works well for now. This might be changed again, if we get a data set region on the left. Differential Revision: https://developer.blender.org/D10931
This commit is contained in:
@@ -306,6 +306,62 @@ class NODE_OT_tree_path_parent(Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class NODE_OT_active_preview_toggle(Operator):
|
||||
'''Toggle active preview state of node'''
|
||||
bl_idname = "node.active_preview_toggle"
|
||||
bl_label = "Toggle Active Preview"
|
||||
bl_options = {'REGISTER', 'UNDO'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
space = context.space_data
|
||||
if space.type != 'NODE_EDITOR':
|
||||
return False
|
||||
if space.edit_tree is None:
|
||||
return False
|
||||
if space.edit_tree.nodes.active is None:
|
||||
return False
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
node_editor = context.space_data
|
||||
ntree = node_editor.edit_tree
|
||||
active_node = ntree.nodes.active
|
||||
|
||||
if active_node.active_preview:
|
||||
self.disable_preview(context, ntree, active_node)
|
||||
else:
|
||||
self.enable_preview(context, node_editor, ntree, active_node)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def enable_preview(self, context, node_editor, ntree, active_node):
|
||||
spreadsheets = self.find_unpinned_spreadsheets(context)
|
||||
|
||||
for spreadsheet in spreadsheets:
|
||||
spreadsheet.set_geometry_node_context(node_editor, active_node)
|
||||
|
||||
for node in ntree.nodes:
|
||||
node.active_preview = False
|
||||
active_node.active_preview = True
|
||||
|
||||
def disable_preview(self, context, ntree, active_node):
|
||||
spreadsheets = self.find_unpinned_spreadsheets(context)
|
||||
for spreadsheet in spreadsheets:
|
||||
spreadsheet.context_path.clear()
|
||||
|
||||
active_node.active_preview = False
|
||||
|
||||
def find_unpinned_spreadsheets(self, context):
|
||||
spreadsheets = []
|
||||
for window in context.window_manager.windows:
|
||||
for area in window.screen.areas:
|
||||
space = area.spaces.active
|
||||
if space.type == 'SPREADSHEET' and not space.is_pinned:
|
||||
spreadsheets.append(space)
|
||||
return spreadsheets
|
||||
|
||||
|
||||
classes = (
|
||||
NodeSetting,
|
||||
|
||||
@@ -314,4 +370,5 @@ classes = (
|
||||
NODE_OT_add_search,
|
||||
NODE_OT_collapse_hide_unused_toggle,
|
||||
NODE_OT_tree_path_parent,
|
||||
NODE_OT_active_preview_toggle,
|
||||
)
|
||||
|
||||
@@ -34,13 +34,45 @@ class SPREADSHEET_OT_toggle_pin(Operator):
|
||||
def execute(self, context):
|
||||
space = context.space_data
|
||||
|
||||
if space.pinned_id:
|
||||
space.pinned_id = None
|
||||
if space.is_pinned:
|
||||
self.unpin(context)
|
||||
else:
|
||||
space.pinned_id = context.active_object
|
||||
|
||||
self.pin(context)
|
||||
return {'FINISHED'}
|
||||
|
||||
def pin(self, context):
|
||||
space = context.space_data
|
||||
space.is_pinned = True
|
||||
|
||||
def unpin(self, context):
|
||||
space = context.space_data
|
||||
space.is_pinned = False
|
||||
|
||||
space.context_path.clear()
|
||||
|
||||
# Try to find a node with an active preview in any open editor.
|
||||
if space.object_eval_state == 'EVALUATED':
|
||||
node_editors = self.find_geometry_node_editors(context)
|
||||
for node_editor in node_editors:
|
||||
ntree = node_editor.edit_tree
|
||||
for node in ntree.nodes:
|
||||
if node.active_preview:
|
||||
space.set_geometry_node_context(node_editor, node)
|
||||
return
|
||||
|
||||
def find_geometry_node_editors(self, context):
|
||||
editors = []
|
||||
for window in context.window_manager.windows:
|
||||
for area in window.screen.areas:
|
||||
space = area.spaces.active
|
||||
if space.type != 'NODE_EDITOR':
|
||||
continue
|
||||
if space.edit_tree is None:
|
||||
continue
|
||||
if space.edit_tree.type == 'GEOMETRY':
|
||||
editors.append(space)
|
||||
return editors
|
||||
|
||||
|
||||
classes = (
|
||||
SPREADSHEET_OT_toggle_pin,
|
||||
|
||||
@@ -28,8 +28,17 @@ class SPREADSHEET_HT_header(bpy.types.Header):
|
||||
|
||||
layout.template_header()
|
||||
|
||||
pinned_id = space.pinned_id
|
||||
used_id = pinned_id if pinned_id else context.active_object
|
||||
if len(space.context_path) == 0:
|
||||
self.draw_without_context_path(layout)
|
||||
return
|
||||
root_context = space.context_path[0]
|
||||
if root_context.type != 'OBJECT':
|
||||
self.draw_without_context_path(layout)
|
||||
return
|
||||
obj = root_context.object
|
||||
if obj is None:
|
||||
self.draw_without_context_path(layout)
|
||||
return
|
||||
|
||||
layout.prop(space, "object_eval_state", text="")
|
||||
if space.object_eval_state != 'ORIGINAL':
|
||||
@@ -37,16 +46,61 @@ class SPREADSHEET_HT_header(bpy.types.Header):
|
||||
if space.geometry_component_type != 'INSTANCES':
|
||||
layout.prop(space, "attribute_domain", text="")
|
||||
|
||||
if used_id:
|
||||
layout.label(text=used_id.name, icon='OBJECT_DATA')
|
||||
context_path = space.context_path
|
||||
if space.object_eval_state == 'ORIGINAL':
|
||||
# Only show first context.
|
||||
context_path = context_path[:1]
|
||||
if space.display_context_path_collapsed:
|
||||
self.draw_collapsed_context_path(context, layout, context_path)
|
||||
else:
|
||||
self.draw_full_context_path(context, layout, context_path)
|
||||
|
||||
layout.operator("spreadsheet.toggle_pin", text="", icon='PINNED' if pinned_id else 'UNPINNED', emboss=False)
|
||||
pin_icon = 'PINNED' if space.is_pinned else 'UNPINNED'
|
||||
layout.operator("spreadsheet.toggle_pin", text="", icon=pin_icon, emboss=False)
|
||||
|
||||
layout.separator_spacer()
|
||||
|
||||
if isinstance(used_id, bpy.types.Object) and used_id.mode == 'EDIT':
|
||||
if isinstance(obj, bpy.types.Object) and obj.mode == 'EDIT':
|
||||
layout.prop(space, "show_only_selected", text="Selected Only")
|
||||
|
||||
def draw_without_context_path(self, layout):
|
||||
layout.label(text="No active context")
|
||||
|
||||
def draw_full_context_path(self, context, layout, context_path):
|
||||
space = context.space_data
|
||||
row = layout.row()
|
||||
for ctx in context_path[:-1]:
|
||||
subrow = row.row(align=True)
|
||||
self.draw_spreadsheet_context(subrow, ctx)
|
||||
self.draw_spreadsheet_context_path_icon(subrow, space)
|
||||
|
||||
self.draw_spreadsheet_context(row, context_path[-1])
|
||||
|
||||
def draw_collapsed_context_path(self, context, layout, context_path):
|
||||
space = context.space_data
|
||||
row = layout.row(align=True)
|
||||
self.draw_spreadsheet_context(row, context_path[0])
|
||||
if len(context_path) == 1:
|
||||
return
|
||||
self.draw_spreadsheet_context_path_icon(row, space)
|
||||
if len(context_path) > 2:
|
||||
self.draw_spreadsheet_context_path_icon(row, space, icon='DOT')
|
||||
self.draw_spreadsheet_context_path_icon(row, space)
|
||||
self.draw_spreadsheet_context(row, context_path[-1])
|
||||
|
||||
def draw_spreadsheet_context(self, layout, ctx):
|
||||
if ctx.type == 'OBJECT':
|
||||
if ctx.object is None:
|
||||
layout.label(text="<no object>", icon='OBJECT_DATA')
|
||||
else:
|
||||
layout.label(text=ctx.object.name, icon='OBJECT_DATA')
|
||||
elif ctx.type == 'MODIFIER':
|
||||
layout.label(text=ctx.modifier_name, icon='MODIFIER')
|
||||
elif ctx.type == 'NODE':
|
||||
layout.label(text=ctx.node_name, icon='NODE')
|
||||
|
||||
def draw_spreadsheet_context_path_icon(self, layout, space, icon='RIGHTARROW_THIN'):
|
||||
layout.prop(space, "display_context_path_collapsed", icon_only=True, emboss=False, icon=icon)
|
||||
|
||||
classes = (
|
||||
SPREADSHEET_HT_header,
|
||||
|
||||
@@ -70,7 +70,9 @@ void BKE_object_free_curve_cache(struct Object *ob);
|
||||
void BKE_object_free_derived_caches(struct Object *ob);
|
||||
void BKE_object_free_caches(struct Object *object);
|
||||
|
||||
void BKE_object_set_preview_geometry_set(struct Object *ob, struct GeometrySet *geometry_set);
|
||||
void BKE_object_preview_geometry_set_add(struct Object *ob,
|
||||
const uint64_t key,
|
||||
struct GeometrySet *geometry_set);
|
||||
|
||||
void BKE_object_modifier_hook_reset(struct Object *ob, struct HookModifierData *hmd);
|
||||
void BKE_object_modifier_gpencil_hook_reset(struct Object *ob,
|
||||
|
||||
@@ -1761,9 +1761,9 @@ void BKE_object_free_derived_caches(Object *ob)
|
||||
BKE_geometry_set_free(ob->runtime.geometry_set_eval);
|
||||
ob->runtime.geometry_set_eval = NULL;
|
||||
}
|
||||
if (ob->runtime.geometry_set_preview != NULL) {
|
||||
BKE_geometry_set_free(ob->runtime.geometry_set_preview);
|
||||
ob->runtime.geometry_set_preview = NULL;
|
||||
if (ob->runtime.geometry_set_previews != NULL) {
|
||||
BLI_ghash_free(ob->runtime.geometry_set_previews, NULL, (GHashValFreeFP)BKE_geometry_set_free);
|
||||
ob->runtime.geometry_set_previews = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1816,14 +1816,20 @@ void BKE_object_free_caches(Object *object)
|
||||
}
|
||||
|
||||
/* Can be called from multiple threads. */
|
||||
void BKE_object_set_preview_geometry_set(Object *ob, struct GeometrySet *geometry_set)
|
||||
void BKE_object_preview_geometry_set_add(Object *ob,
|
||||
const uint64_t key,
|
||||
struct GeometrySet *geometry_set)
|
||||
{
|
||||
static ThreadMutex mutex = BLI_MUTEX_INITIALIZER;
|
||||
BLI_mutex_lock(&mutex);
|
||||
if (ob->runtime.geometry_set_preview != NULL) {
|
||||
BKE_geometry_set_free(ob->runtime.geometry_set_preview);
|
||||
if (ob->runtime.geometry_set_previews == NULL) {
|
||||
ob->runtime.geometry_set_previews = BLI_ghash_int_new(__func__);
|
||||
}
|
||||
ob->runtime.geometry_set_preview = geometry_set;
|
||||
BLI_ghash_reinsert(ob->runtime.geometry_set_previews,
|
||||
POINTER_FROM_UINT(key),
|
||||
geometry_set,
|
||||
NULL,
|
||||
(GHashValFreeFP)BKE_geometry_set_free);
|
||||
BLI_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
|
||||
@@ -227,7 +227,12 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area
|
||||
case SPACE_SPREADSHEET: {
|
||||
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
|
||||
|
||||
BKE_LIB_FOREACHID_PROCESS_ID(data, sspreadsheet->pinned_id, IDWALK_CB_NOP);
|
||||
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
|
||||
if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
|
||||
BKE_LIB_FOREACHID_PROCESS(
|
||||
data, ((SpreadsheetContextObject *)context)->object, IDWALK_CB_NOP);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1357,6 +1362,27 @@ static void write_area(BlendWriter *writer, ScrArea *area)
|
||||
BLO_write_struct(writer, SpreadsheetColumnID, column->id);
|
||||
BLO_write_string(writer, column->id->name);
|
||||
}
|
||||
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
|
||||
switch (context->type) {
|
||||
case SPREADSHEET_CONTEXT_OBJECT: {
|
||||
SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
|
||||
BLO_write_struct(writer, SpreadsheetContextObject, object_context);
|
||||
break;
|
||||
}
|
||||
case SPREADSHEET_CONTEXT_MODIFIER: {
|
||||
SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context;
|
||||
BLO_write_struct(writer, SpreadsheetContextModifier, modifier_context);
|
||||
BLO_write_string(writer, modifier_context->modifier_name);
|
||||
break;
|
||||
}
|
||||
case SPREADSHEET_CONTEXT_NODE: {
|
||||
SpreadsheetContextNode *node_context = (SpreadsheetContextNode *)context;
|
||||
BLO_write_struct(writer, SpreadsheetContextNode, node_context);
|
||||
BLO_write_string(writer, node_context->node_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1715,6 +1741,25 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
|
||||
BLO_read_data_address(reader, &column->id);
|
||||
BLO_read_data_address(reader, &column->id->name);
|
||||
}
|
||||
|
||||
BLO_read_list(reader, &sspreadsheet->context_path);
|
||||
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
|
||||
switch (context->type) {
|
||||
case SPREADSHEET_CONTEXT_NODE: {
|
||||
SpreadsheetContextNode *node_context = (SpreadsheetContextNode *)context;
|
||||
BLO_read_data_address(reader, &node_context->node_name);
|
||||
break;
|
||||
}
|
||||
case SPREADSHEET_CONTEXT_MODIFIER: {
|
||||
SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context;
|
||||
BLO_read_data_address(reader, &modifier_context->modifier_name);
|
||||
break;
|
||||
}
|
||||
case SPREADSHEET_CONTEXT_OBJECT: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1931,7 +1976,12 @@ void BKE_screen_area_blend_read_lib(BlendLibReader *reader, ID *parent_id, ScrAr
|
||||
}
|
||||
case SPACE_SPREADSHEET: {
|
||||
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
|
||||
BLO_read_id_address(reader, parent_id->lib, &sspreadsheet->pinned_id);
|
||||
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
|
||||
if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
|
||||
BLO_read_id_address(
|
||||
reader, parent_id->lib, &((SpreadsheetContextObject *)context)->object);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -73,6 +73,12 @@ template<typename Key, typename Value> class MultiValueMap {
|
||||
vector.append(std::forward<ForwardValue>(value));
|
||||
}
|
||||
|
||||
void add_non_duplicates(const Key &key, const Value &value)
|
||||
{
|
||||
Vector<Value> &vector = map_.lookup_or_add_default_as(key);
|
||||
vector.append_non_duplicates(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all given values to the key.
|
||||
*/
|
||||
|
||||
@@ -3010,8 +3010,13 @@ static void lib_link_workspace_layout_restore(struct IDNameLib_Map *id_map,
|
||||
else if (sl->spacetype == SPACE_SPREADSHEET) {
|
||||
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
|
||||
|
||||
sspreadsheet->pinned_id = restore_pointer_by_name(
|
||||
id_map, sspreadsheet->pinned_id, USER_IGNORE);
|
||||
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
|
||||
if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
|
||||
SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
|
||||
object_context->object = restore_pointer_by_name(
|
||||
id_map, (ID *)object_context->object, USER_IGNORE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2054,5 +2054,19 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Consolidate node and final evaluation modes. */
|
||||
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
|
||||
if (sl->spacetype == SPACE_SPREADSHEET) {
|
||||
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
|
||||
if (sspreadsheet->object_eval_state == 2) {
|
||||
sspreadsheet->object_eval_state = SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
43
source/blender/editors/include/ED_spreadsheet.h
Normal file
43
source/blender/editors/include/ED_spreadsheet.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct SpreadsheetContext;
|
||||
struct SpaceSpreadsheet;
|
||||
struct SpaceNode;
|
||||
struct ID;
|
||||
struct bNode;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct SpreadsheetContext *ED_spreadsheet_context_new(int type);
|
||||
void ED_spreadsheet_context_free(struct SpreadsheetContext *context);
|
||||
void ED_spreadsheet_context_path_clear(struct SpaceSpreadsheet *sspreadsheet);
|
||||
void ED_spreadsheet_context_path_update_tag(struct SpaceSpreadsheet *sspreadsheet);
|
||||
uint64_t ED_spreadsheet_context_path_hash(struct SpaceSpreadsheet *sspreadsheet);
|
||||
|
||||
struct ID *ED_spreadsheet_get_current_id(struct SpaceSpreadsheet *sspreadsheet);
|
||||
|
||||
void ED_spreadsheet_set_geometry_node_context(struct SpaceSpreadsheet *sspreadsheet,
|
||||
struct SpaceNode *snode,
|
||||
struct bNode *node);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1422,7 +1422,7 @@ static void node_draw_basis(const bContext *C,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
"Show this node's geometry output in the spreadsheet in Node mode");
|
||||
"Show this node's geometry output in the spreadsheet");
|
||||
UI_but_func_set(but, node_toggle_button_cb, node, (void *)"NODE_OT_active_preview_toggle");
|
||||
UI_block_emboss_set(node->block, UI_EMBOSS);
|
||||
}
|
||||
|
||||
@@ -1694,55 +1694,6 @@ void NODE_OT_hide_socket_toggle(wmOperatorType *ot)
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
static void disable_active_preview_on_all_nodes(bNodeTree *ntree)
|
||||
{
|
||||
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
||||
node->flag &= ~NODE_ACTIVE_PREVIEW;
|
||||
}
|
||||
}
|
||||
|
||||
static int node_active_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
{
|
||||
SpaceNode *snode = CTX_wm_space_node(C);
|
||||
Main *bmain = CTX_data_main(C);
|
||||
bNodeTree *ntree = snode->edittree;
|
||||
disable_active_preview_on_all_nodes(ntree);
|
||||
bNode *active_node = nodeGetActive(ntree);
|
||||
active_node->flag |= NODE_ACTIVE_PREVIEW;
|
||||
|
||||
/* Tag for update, so that dependent objects are reevaluated. This is necessary when a
|
||||
* spreadsheet editor displays data from a node. */
|
||||
LISTBASE_FOREACH (wmWindow *, window, &((wmWindowManager *)bmain->wm.first)->windows) {
|
||||
bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
if (area->spacetype == SPACE_SPREADSHEET) {
|
||||
SpaceSpreadsheet *sspreadsheet = area->spacedata.first;
|
||||
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_NODE) {
|
||||
DEG_id_tag_update(&ntree->id, ID_RECALC_COPY_ON_WRITE);
|
||||
ED_area_tag_redraw(area);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void NODE_OT_active_preview_toggle(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Toggle Active Preview";
|
||||
ot->description = "Toggle active preview state of node";
|
||||
ot->idname = "NODE_OT_active_preview_toggle";
|
||||
|
||||
/* callbacks */
|
||||
ot->exec = node_active_preview_toggle_exec;
|
||||
ot->poll = ED_operator_node_active;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
/* ****************** Mute operator *********************** */
|
||||
|
||||
static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
|
||||
@@ -57,7 +57,6 @@ void node_operatortypes(void)
|
||||
WM_operatortype_append(NODE_OT_preview_toggle);
|
||||
WM_operatortype_append(NODE_OT_options_toggle);
|
||||
WM_operatortype_append(NODE_OT_hide_socket_toggle);
|
||||
WM_operatortype_append(NODE_OT_active_preview_toggle);
|
||||
WM_operatortype_append(NODE_OT_node_copy_color);
|
||||
|
||||
WM_operatortype_append(NODE_OT_duplicate);
|
||||
|
||||
@@ -33,6 +33,7 @@ set(INC
|
||||
|
||||
set(SRC
|
||||
space_spreadsheet.cc
|
||||
spreadsheet_breadcrumb.cc
|
||||
spreadsheet_column.cc
|
||||
spreadsheet_data_source.cc
|
||||
spreadsheet_data_source_geometry.cc
|
||||
@@ -40,6 +41,7 @@ set(SRC
|
||||
spreadsheet_layout.cc
|
||||
spreadsheet_ops.cc
|
||||
|
||||
spreadsheet_breadcrumb.hh
|
||||
spreadsheet_cell_value.hh
|
||||
spreadsheet_column.hh
|
||||
spreadsheet_column_values.hh
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "ED_screen.h"
|
||||
#include "ED_space_api.h"
|
||||
#include "ED_spreadsheet.h"
|
||||
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
@@ -44,6 +45,7 @@
|
||||
|
||||
#include "spreadsheet_intern.hh"
|
||||
|
||||
#include "spreadsheet_breadcrumb.hh"
|
||||
#include "spreadsheet_data_source_geometry.hh"
|
||||
#include "spreadsheet_intern.hh"
|
||||
#include "spreadsheet_layout.hh"
|
||||
@@ -91,6 +93,9 @@ static void spreadsheet_free(SpaceLink *sl)
|
||||
LISTBASE_FOREACH_MUTABLE (SpreadsheetColumn *, column, &sspreadsheet->columns) {
|
||||
spreadsheet_column_free(column);
|
||||
}
|
||||
LISTBASE_FOREACH_MUTABLE (SpreadsheetContext *, context, &sspreadsheet->context_path) {
|
||||
spreadsheet_context_free(context);
|
||||
}
|
||||
}
|
||||
|
||||
static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area)
|
||||
@@ -100,10 +105,6 @@ static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area)
|
||||
sspreadsheet->runtime = (SpaceSpreadsheet_Runtime *)MEM_callocN(
|
||||
sizeof(SpaceSpreadsheet_Runtime), __func__);
|
||||
}
|
||||
LISTBASE_FOREACH_MUTABLE (SpreadsheetColumn *, column, &sspreadsheet->columns) {
|
||||
spreadsheet_column_free(column);
|
||||
}
|
||||
BLI_listbase_clear(&sspreadsheet->columns);
|
||||
}
|
||||
|
||||
static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
|
||||
@@ -118,6 +119,12 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl)
|
||||
BLI_addtail(&sspreadsheet_new->columns, new_column);
|
||||
}
|
||||
|
||||
BLI_listbase_clear(&sspreadsheet_new->context_path);
|
||||
LISTBASE_FOREACH_MUTABLE (SpreadsheetContext *, src_context, &sspreadsheet_old->context_path) {
|
||||
SpreadsheetContext *new_context = spreadsheet_context_copy(src_context);
|
||||
BLI_addtail(&sspreadsheet_new->context_path, new_context);
|
||||
}
|
||||
|
||||
return (SpaceLink *)sspreadsheet_new;
|
||||
}
|
||||
|
||||
@@ -125,6 +132,24 @@ static void spreadsheet_keymap(wmKeyConfig *UNUSED(keyconf))
|
||||
{
|
||||
}
|
||||
|
||||
static void spreadsheet_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
|
||||
{
|
||||
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)slink;
|
||||
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
|
||||
if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
|
||||
SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
|
||||
if ((ID *)object_context->object == old_id) {
|
||||
if (new_id && GS(new_id->name) == ID_OB) {
|
||||
object_context->object = (Object *)new_id;
|
||||
}
|
||||
else {
|
||||
object_context->object = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region)
|
||||
{
|
||||
region->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM;
|
||||
@@ -139,20 +164,90 @@ static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region)
|
||||
WM_event_add_keymap_handler(®ion->handlers, keymap);
|
||||
}
|
||||
|
||||
static ID *get_used_id(const bContext *C)
|
||||
ID *ED_spreadsheet_get_current_id(struct SpaceSpreadsheet *sspreadsheet)
|
||||
{
|
||||
if (BLI_listbase_is_empty(&sspreadsheet->context_path)) {
|
||||
return nullptr;
|
||||
}
|
||||
SpreadsheetContext *root_context = (SpreadsheetContext *)sspreadsheet->context_path.first;
|
||||
if (root_context->type != SPREADSHEET_CONTEXT_OBJECT) {
|
||||
return nullptr;
|
||||
}
|
||||
SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)root_context;
|
||||
return (ID *)object_context->object;
|
||||
}
|
||||
|
||||
/* Check if the pinned context still exists. If it doesn't try to find a new context. */
|
||||
static void update_pinned_context_path_if_outdated(const bContext *C)
|
||||
{
|
||||
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
|
||||
if (sspreadsheet->pinned_id != nullptr) {
|
||||
return sspreadsheet->pinned_id;
|
||||
|
||||
/* Currently, this only checks if the object has been deleted. In the future we can have a more
|
||||
* sophisticated check for the entire context (including modifier and nodes). */
|
||||
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
|
||||
if (context->type == SPREADSHEET_CONTEXT_OBJECT) {
|
||||
SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context;
|
||||
if (object_context->object == nullptr) {
|
||||
ED_spreadsheet_context_path_clear(sspreadsheet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (BLI_listbase_is_empty(&sspreadsheet->context_path)) {
|
||||
Object *active_object = CTX_data_active_object(C);
|
||||
return (ID *)active_object;
|
||||
if (active_object != nullptr) {
|
||||
SpreadsheetContext *new_context = spreadsheet_context_new(SPREADSHEET_CONTEXT_OBJECT);
|
||||
((SpreadsheetContextObject *)new_context)->object = active_object;
|
||||
BLI_addtail(&sspreadsheet->context_path, new_context);
|
||||
}
|
||||
}
|
||||
|
||||
if (BLI_listbase_is_empty(&sspreadsheet->context_path)) {
|
||||
/* Don't pin empty context_path, that could be annoying. */
|
||||
sspreadsheet->flag &= ~SPREADSHEET_FLAG_PINNED;
|
||||
}
|
||||
}
|
||||
|
||||
static void update_context_path_from_context(const bContext *C)
|
||||
{
|
||||
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
|
||||
Object *active_object = CTX_data_active_object(C);
|
||||
if (active_object == nullptr) {
|
||||
ED_spreadsheet_context_path_clear(sspreadsheet);
|
||||
return;
|
||||
}
|
||||
if (!BLI_listbase_is_empty(&sspreadsheet->context_path)) {
|
||||
SpreadsheetContext *root_context = (SpreadsheetContext *)sspreadsheet->context_path.first;
|
||||
if (root_context->type == SPREADSHEET_CONTEXT_OBJECT) {
|
||||
SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)root_context;
|
||||
if (object_context->object != active_object) {
|
||||
ED_spreadsheet_context_path_clear(sspreadsheet);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (BLI_listbase_is_empty(&sspreadsheet->context_path)) {
|
||||
SpreadsheetContext *new_context = spreadsheet_context_new(SPREADSHEET_CONTEXT_OBJECT);
|
||||
((SpreadsheetContextObject *)new_context)->object = active_object;
|
||||
BLI_addtail(&sspreadsheet->context_path, new_context);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_context_path(const bContext *C)
|
||||
{
|
||||
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
|
||||
if (sspreadsheet->flag & SPREADSHEET_FLAG_PINNED) {
|
||||
update_pinned_context_path_if_outdated(C);
|
||||
}
|
||||
else {
|
||||
update_context_path_from_context(C);
|
||||
}
|
||||
}
|
||||
|
||||
static std::unique_ptr<DataSource> get_data_source(const bContext *C)
|
||||
{
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
ID *used_id = get_used_id(C);
|
||||
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
|
||||
ID *used_id = ED_spreadsheet_get_current_id(sspreadsheet);
|
||||
if (used_id == nullptr) {
|
||||
return {};
|
||||
}
|
||||
@@ -227,6 +322,7 @@ static void update_visible_columns(ListBase &columns, DataSource &data_source)
|
||||
static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
|
||||
{
|
||||
SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C);
|
||||
update_context_path(C);
|
||||
|
||||
std::unique_ptr<DataSource> data_source = get_data_source(C);
|
||||
if (!data_source) {
|
||||
@@ -317,6 +413,7 @@ static void spreadsheet_header_region_init(wmWindowManager *UNUSED(wm), ARegion
|
||||
|
||||
static void spreadsheet_header_region_draw(const bContext *C, ARegion *region)
|
||||
{
|
||||
update_context_path(C);
|
||||
ED_region_header(C, region);
|
||||
}
|
||||
|
||||
@@ -422,6 +519,7 @@ void ED_spacetype_spreadsheet(void)
|
||||
st->duplicate = spreadsheet_duplicate;
|
||||
st->operatortypes = spreadsheet_operatortypes;
|
||||
st->keymap = spreadsheet_keymap;
|
||||
st->id_remap = spreadsheet_id_remap;
|
||||
|
||||
/* regions: main window */
|
||||
art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet region");
|
||||
|
||||
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_hash.h"
|
||||
#include "BLI_hash.hh"
|
||||
#include "BLI_hash_mm2a.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "ED_spreadsheet.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "spreadsheet_breadcrumb.hh"
|
||||
|
||||
namespace blender::ed::spreadsheet {
|
||||
|
||||
static SpreadsheetContextObject *spreadsheet_context_object_new()
|
||||
{
|
||||
SpreadsheetContextObject *context = (SpreadsheetContextObject *)MEM_callocN(
|
||||
sizeof(SpreadsheetContextObject), __func__);
|
||||
context->base.type = SPREADSHEET_CONTEXT_OBJECT;
|
||||
return context;
|
||||
}
|
||||
|
||||
static SpreadsheetContextObject *spreadsheet_context_object_copy(
|
||||
const SpreadsheetContextObject *src_context)
|
||||
{
|
||||
SpreadsheetContextObject *new_context = spreadsheet_context_object_new();
|
||||
new_context->object = src_context->object;
|
||||
return new_context;
|
||||
}
|
||||
|
||||
static void spreadsheet_context_object_hash(const SpreadsheetContextObject *context,
|
||||
BLI_HashMurmur2A *mm2)
|
||||
{
|
||||
BLI_hash_mm2a_add(mm2, (const uchar *)&context->object, sizeof(Object *));
|
||||
}
|
||||
|
||||
static void spreadsheet_context_object_free(SpreadsheetContextObject *context)
|
||||
{
|
||||
MEM_freeN(context);
|
||||
}
|
||||
|
||||
static SpreadsheetContextModifier *spreadsheet_context_modifier_new()
|
||||
{
|
||||
SpreadsheetContextModifier *context = (SpreadsheetContextModifier *)MEM_callocN(
|
||||
sizeof(SpreadsheetContextModifier), __func__);
|
||||
context->base.type = SPREADSHEET_CONTEXT_MODIFIER;
|
||||
return context;
|
||||
}
|
||||
|
||||
static SpreadsheetContextModifier *spreadsheet_context_modifier_copy(
|
||||
const SpreadsheetContextModifier *src_context)
|
||||
{
|
||||
SpreadsheetContextModifier *new_context = spreadsheet_context_modifier_new();
|
||||
if (src_context->modifier_name) {
|
||||
new_context->modifier_name = BLI_strdup(src_context->modifier_name);
|
||||
}
|
||||
return new_context;
|
||||
}
|
||||
|
||||
static void spreadsheet_context_modifier_hash(const SpreadsheetContextModifier *context,
|
||||
BLI_HashMurmur2A *mm2)
|
||||
{
|
||||
if (context->modifier_name) {
|
||||
BLI_hash_mm2a_add(mm2, (const uchar *)context->modifier_name, strlen(context->modifier_name));
|
||||
}
|
||||
}
|
||||
|
||||
static void spreadsheet_context_modifier_free(SpreadsheetContextModifier *context)
|
||||
{
|
||||
if (context->modifier_name) {
|
||||
MEM_freeN(context->modifier_name);
|
||||
}
|
||||
MEM_freeN(context);
|
||||
}
|
||||
|
||||
static SpreadsheetContextNode *spreadsheet_context_node_new()
|
||||
{
|
||||
SpreadsheetContextNode *context = (SpreadsheetContextNode *)MEM_callocN(
|
||||
sizeof(SpreadsheetContextNode), __func__);
|
||||
context->base.type = SPREADSHEET_CONTEXT_NODE;
|
||||
return context;
|
||||
}
|
||||
|
||||
static SpreadsheetContextNode *spreadsheet_context_node_copy(
|
||||
const SpreadsheetContextNode *src_context)
|
||||
{
|
||||
SpreadsheetContextNode *new_context = spreadsheet_context_node_new();
|
||||
if (src_context->node_name) {
|
||||
new_context->node_name = BLI_strdup(src_context->node_name);
|
||||
}
|
||||
return new_context;
|
||||
}
|
||||
|
||||
static void spreadsheet_context_node_hash(const SpreadsheetContextNode *context,
|
||||
BLI_HashMurmur2A *mm2)
|
||||
{
|
||||
if (context->node_name) {
|
||||
BLI_hash_mm2a_add(mm2, (const uchar *)context->node_name, strlen(context->node_name));
|
||||
}
|
||||
}
|
||||
|
||||
static void spreadsheet_context_node_free(SpreadsheetContextNode *context)
|
||||
{
|
||||
if (context->node_name) {
|
||||
MEM_freeN(context->node_name);
|
||||
}
|
||||
MEM_freeN(context);
|
||||
}
|
||||
|
||||
SpreadsheetContext *spreadsheet_context_new(eSpaceSpreadsheet_ContextType type)
|
||||
{
|
||||
switch (type) {
|
||||
case SPREADSHEET_CONTEXT_OBJECT: {
|
||||
return (SpreadsheetContext *)spreadsheet_context_object_new();
|
||||
}
|
||||
case SPREADSHEET_CONTEXT_MODIFIER: {
|
||||
return (SpreadsheetContext *)spreadsheet_context_modifier_new();
|
||||
}
|
||||
case SPREADSHEET_CONTEXT_NODE: {
|
||||
return (SpreadsheetContext *)spreadsheet_context_node_new();
|
||||
}
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SpreadsheetContext *spreadsheet_context_copy(const SpreadsheetContext *old_context)
|
||||
{
|
||||
switch (old_context->type) {
|
||||
case SPREADSHEET_CONTEXT_OBJECT: {
|
||||
return (SpreadsheetContext *)spreadsheet_context_object_copy(
|
||||
(const SpreadsheetContextObject *)old_context);
|
||||
}
|
||||
case SPREADSHEET_CONTEXT_MODIFIER: {
|
||||
return (SpreadsheetContext *)spreadsheet_context_modifier_copy(
|
||||
(const SpreadsheetContextModifier *)old_context);
|
||||
}
|
||||
case SPREADSHEET_CONTEXT_NODE: {
|
||||
return (SpreadsheetContext *)spreadsheet_context_node_copy(
|
||||
(const SpreadsheetContextNode *)old_context);
|
||||
}
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void spreadsheet_context_hash(const SpreadsheetContext *context, BLI_HashMurmur2A *mm2)
|
||||
{
|
||||
BLI_hash_mm2a_add_int(mm2, context->type);
|
||||
switch (context->type) {
|
||||
case SPREADSHEET_CONTEXT_OBJECT: {
|
||||
spreadsheet_context_object_hash((const SpreadsheetContextObject *)context, mm2);
|
||||
break;
|
||||
}
|
||||
case SPREADSHEET_CONTEXT_MODIFIER: {
|
||||
spreadsheet_context_modifier_hash((const SpreadsheetContextModifier *)context, mm2);
|
||||
break;
|
||||
}
|
||||
case SPREADSHEET_CONTEXT_NODE: {
|
||||
spreadsheet_context_node_hash((const SpreadsheetContextNode *)context, mm2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spreadsheet_context_free(SpreadsheetContext *context)
|
||||
{
|
||||
switch (context->type) {
|
||||
case SPREADSHEET_CONTEXT_OBJECT: {
|
||||
return spreadsheet_context_object_free((SpreadsheetContextObject *)context);
|
||||
}
|
||||
case SPREADSHEET_CONTEXT_MODIFIER: {
|
||||
return spreadsheet_context_modifier_free((SpreadsheetContextModifier *)context);
|
||||
}
|
||||
case SPREADSHEET_CONTEXT_NODE: {
|
||||
return spreadsheet_context_node_free((SpreadsheetContextNode *)context);
|
||||
}
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag any data relevant to the spreadsheet's context for recalculation in order to collect
|
||||
* information to display in the editor, which may be cached during evaluation.
|
||||
*/
|
||||
static void spreadsheet_context_update_tag(SpaceSpreadsheet *sspreadsheet)
|
||||
{
|
||||
using namespace blender;
|
||||
Vector<const SpreadsheetContext *> context_path = sspreadsheet->context_path;
|
||||
if (context_path.is_empty()) {
|
||||
return;
|
||||
}
|
||||
if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
|
||||
return;
|
||||
}
|
||||
SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context_path[0];
|
||||
Object *object = object_context->object;
|
||||
if (object == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (context_path.size() == 1) {
|
||||
/* No need to reevaluate, when the final or original object is viewed. */
|
||||
return;
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
|
||||
}
|
||||
|
||||
} // namespace blender::ed::spreadsheet
|
||||
|
||||
SpreadsheetContext *ED_spreadsheet_context_new(int type)
|
||||
{
|
||||
return blender::ed::spreadsheet::spreadsheet_context_new((eSpaceSpreadsheet_ContextType)type);
|
||||
}
|
||||
|
||||
void ED_spreadsheet_context_free(struct SpreadsheetContext *context)
|
||||
{
|
||||
blender::ed::spreadsheet::spreadsheet_context_free(context);
|
||||
}
|
||||
|
||||
void ED_spreadsheet_context_path_clear(struct SpaceSpreadsheet *sspreadsheet)
|
||||
{
|
||||
LISTBASE_FOREACH_MUTABLE (SpreadsheetContext *, context, &sspreadsheet->context_path) {
|
||||
ED_spreadsheet_context_free(context);
|
||||
}
|
||||
BLI_listbase_clear(&sspreadsheet->context_path);
|
||||
}
|
||||
|
||||
void ED_spreadsheet_context_path_update_tag(SpaceSpreadsheet *sspreadsheet)
|
||||
{
|
||||
blender::ed::spreadsheet::spreadsheet_context_update_tag(sspreadsheet);
|
||||
}
|
||||
|
||||
uint64_t ED_spreadsheet_context_path_hash(SpaceSpreadsheet *sspreadsheet)
|
||||
{
|
||||
BLI_HashMurmur2A mm2;
|
||||
BLI_hash_mm2a_init(&mm2, 1234);
|
||||
LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) {
|
||||
blender::ed::spreadsheet::spreadsheet_context_hash(context, &mm2);
|
||||
}
|
||||
return BLI_hash_mm2a_end(&mm2);
|
||||
}
|
||||
|
||||
void ED_spreadsheet_set_geometry_node_context(struct SpaceSpreadsheet *sspreadsheet,
|
||||
struct SpaceNode *snode,
|
||||
struct bNode *node)
|
||||
{
|
||||
using namespace blender::ed::spreadsheet;
|
||||
ED_spreadsheet_context_path_clear(sspreadsheet);
|
||||
|
||||
Object *object = (Object *)snode->id;
|
||||
ModifierData *modifier = BKE_object_active_modifier(object);
|
||||
|
||||
{
|
||||
SpreadsheetContextObject *context = spreadsheet_context_object_new();
|
||||
context->object = object;
|
||||
BLI_addtail(&sspreadsheet->context_path, context);
|
||||
}
|
||||
{
|
||||
SpreadsheetContextModifier *context = spreadsheet_context_modifier_new();
|
||||
context->modifier_name = BLI_strdup(modifier->name);
|
||||
BLI_addtail(&sspreadsheet->context_path, context);
|
||||
}
|
||||
{
|
||||
int i;
|
||||
LISTBASE_FOREACH_INDEX (bNodeTreePath *, path, &snode->treepath, i) {
|
||||
if (i == 0) {
|
||||
continue;
|
||||
}
|
||||
SpreadsheetContextNode *context = spreadsheet_context_node_new();
|
||||
context->node_name = BLI_strdup(path->node_name);
|
||||
BLI_addtail(&sspreadsheet->context_path, context);
|
||||
}
|
||||
}
|
||||
{
|
||||
SpreadsheetContextNode *context = spreadsheet_context_node_new();
|
||||
context->node_name = BLI_strdup(node->name);
|
||||
BLI_addtail(&sspreadsheet->context_path, context);
|
||||
}
|
||||
|
||||
sspreadsheet->object_eval_state = SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
namespace blender::ed::spreadsheet {
|
||||
|
||||
SpreadsheetContext *spreadsheet_context_new(eSpaceSpreadsheet_ContextType type);
|
||||
SpreadsheetContext *spreadsheet_context_copy(const SpreadsheetContext *old_context);
|
||||
void spreadsheet_context_free(SpreadsheetContext *context);
|
||||
|
||||
} // namespace blender::ed::spreadsheet
|
||||
@@ -29,6 +29,8 @@
|
||||
|
||||
#include "DEG_depsgraph_query.h"
|
||||
|
||||
#include "ED_spreadsheet.h"
|
||||
|
||||
#include "bmesh.h"
|
||||
|
||||
#include "spreadsheet_data_source_geometry.hh"
|
||||
@@ -396,7 +398,7 @@ static GeometrySet get_display_geometry_set(SpaceSpreadsheet *sspreadsheet,
|
||||
pointcloud_component.replace(pointcloud, GeometryOwnershipType::ReadOnly);
|
||||
}
|
||||
}
|
||||
else {
|
||||
else if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED) {
|
||||
if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) {
|
||||
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false);
|
||||
if (mesh == nullptr) {
|
||||
@@ -408,16 +410,23 @@ static GeometrySet get_display_geometry_set(SpaceSpreadsheet *sspreadsheet,
|
||||
mesh_component.copy_vertex_group_names_from_object(*object_eval);
|
||||
}
|
||||
else {
|
||||
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_NODE) {
|
||||
if (object_eval->runtime.geometry_set_preview != nullptr) {
|
||||
geometry_set = *object_eval->runtime.geometry_set_preview;
|
||||
}
|
||||
}
|
||||
else if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_FINAL) {
|
||||
if (BLI_listbase_count(&sspreadsheet->context_path) == 1) {
|
||||
/* Use final evaluated object. */
|
||||
if (object_eval->runtime.geometry_set_eval != nullptr) {
|
||||
geometry_set = *object_eval->runtime.geometry_set_eval;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (object_eval->runtime.geometry_set_previews != nullptr) {
|
||||
GHash *ghash = (GHash *)object_eval->runtime.geometry_set_previews;
|
||||
const uint64_t key = ED_spreadsheet_context_path_hash(sspreadsheet);
|
||||
GeometrySet *geometry_set_preview = (GeometrySet *)BLI_ghash_lookup_default(
|
||||
ghash, POINTER_FROM_UINT(key), nullptr);
|
||||
if (geometry_set_preview != nullptr) {
|
||||
geometry_set = *geometry_set_preview;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return geometry_set;
|
||||
|
||||
@@ -86,6 +86,7 @@ set(SRC
|
||||
../include/ED_sequencer.h
|
||||
../include/ED_sound.h
|
||||
../include/ED_space_api.h
|
||||
../include/ED_spreadsheet.h
|
||||
../include/ED_text.h
|
||||
../include/ED_time_scrub_ui.h
|
||||
../include/ED_transform.h
|
||||
|
||||
@@ -169,9 +169,10 @@ typedef struct Object_Runtime {
|
||||
struct GeometrySet *geometry_set_eval;
|
||||
|
||||
/**
|
||||
* Data from this geometry set is previewed in the spreadsheet editor.
|
||||
* A GHash that contains geometry sets for intermediate stages of evaluation. The keys are just a
|
||||
* hash and are not owned by the map. The geometry sets are owned.
|
||||
*/
|
||||
struct GeometrySet *geometry_set_preview;
|
||||
void *geometry_set_previews;
|
||||
|
||||
/**
|
||||
* Mesh structure created during object evaluation.
|
||||
|
||||
@@ -1870,6 +1870,32 @@ typedef struct SpreadsheetColumn {
|
||||
SpreadsheetColumnID *id;
|
||||
} SpreadsheetColumn;
|
||||
|
||||
/**
|
||||
* An item in SpaceSpreadsheet.context_path.
|
||||
* This is a bases struct for the structs below.
|
||||
*/
|
||||
typedef struct SpreadsheetContext {
|
||||
struct SpreadsheetContext *next, *prev;
|
||||
/* eSpaceSpreadsheet_ContextType. */
|
||||
int type;
|
||||
char _pad[4];
|
||||
} SpreadsheetContext;
|
||||
|
||||
typedef struct SpreadsheetContextObject {
|
||||
SpreadsheetContext base;
|
||||
struct Object *object;
|
||||
} SpreadsheetContextObject;
|
||||
|
||||
typedef struct SpreadsheetContextModifier {
|
||||
SpreadsheetContext base;
|
||||
char *modifier_name;
|
||||
} SpreadsheetContextModifier;
|
||||
|
||||
typedef struct SpreadsheetContextNode {
|
||||
SpreadsheetContext base;
|
||||
char *node_name;
|
||||
} SpreadsheetContextNode;
|
||||
|
||||
typedef struct SpaceSpreadsheet {
|
||||
SpaceLink *next, *prev;
|
||||
/** Storage of regions for inactive spaces. */
|
||||
@@ -1882,7 +1908,13 @@ typedef struct SpaceSpreadsheet {
|
||||
/* List of #SpreadsheetColumn. */
|
||||
ListBase columns;
|
||||
|
||||
struct ID *pinned_id;
|
||||
/**
|
||||
* List of #SpreadsheetContext.
|
||||
* This is a path to the data that is displayed in the spreadsheet.
|
||||
* It can be set explicitely by an action of the user (e.g. clicking the preview icon in a
|
||||
* geometry node) or it can be derived from context automatically based on some heuristic.
|
||||
*/
|
||||
ListBase context_path;
|
||||
|
||||
/* eSpaceSpreadsheet_FilterFlag. */
|
||||
uint8_t filter_flag;
|
||||
@@ -1894,21 +1926,32 @@ typedef struct SpaceSpreadsheet {
|
||||
/* eSpaceSpreadsheet_ObjectContext. */
|
||||
uint8_t object_eval_state;
|
||||
|
||||
char _pad1[4];
|
||||
/* eSpaceSpreadsheet_Flag. */
|
||||
uint32_t flag;
|
||||
|
||||
SpaceSpreadsheet_Runtime *runtime;
|
||||
} SpaceSpreadsheet;
|
||||
|
||||
typedef enum eSpaceSpreadsheet_Flag {
|
||||
SPREADSHEET_FLAG_PINNED = (1 << 0),
|
||||
SPREADSHEET_FLAG_CONTEXT_PATH_COLLAPSED = (1 << 1),
|
||||
} eSpaceSpreadsheet_Flag;
|
||||
|
||||
typedef enum eSpaceSpreadsheet_FilterFlag {
|
||||
SPREADSHEET_FILTER_SELECTED_ONLY = (1 << 0),
|
||||
} eSpaceSpreadsheet_FilterFlag;
|
||||
|
||||
typedef enum eSpaceSpreadsheet_ObjectEvalState {
|
||||
SPREADSHEET_OBJECT_EVAL_STATE_FINAL = 0,
|
||||
SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED = 0,
|
||||
SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL = 1,
|
||||
SPREADSHEET_OBJECT_EVAL_STATE_NODE = 2,
|
||||
} eSpaceSpreadsheet_Context;
|
||||
|
||||
typedef enum eSpaceSpreadsheet_ContextType {
|
||||
SPREADSHEET_CONTEXT_OBJECT = 0,
|
||||
SPREADSHEET_CONTEXT_MODIFIER = 1,
|
||||
SPREADSHEET_CONTEXT_NODE = 2,
|
||||
} eSpaceSpreadsheet_ContextType;
|
||||
|
||||
/**
|
||||
* We can't just use UI_UNIT_X, because it does not take `widget.points` into account, which
|
||||
* modifies the width of text as well.
|
||||
|
||||
@@ -614,6 +614,10 @@ extern StructRNA RNA_Spline;
|
||||
extern StructRNA RNA_SplineIKConstraint;
|
||||
extern StructRNA RNA_SplinePoint;
|
||||
extern StructRNA RNA_SpotLight;
|
||||
extern StructRNA RNA_SpreadsheetContext;
|
||||
extern StructRNA RNA_SpreadsheetContextObject;
|
||||
extern StructRNA RNA_SpreadsheetContextModifier;
|
||||
extern StructRNA RNA_SpreadsheetContextNode;
|
||||
extern StructRNA RNA_Stereo3dDisplay;
|
||||
extern StructRNA RNA_StretchToConstraint;
|
||||
extern StructRNA RNA_StringAttribute;
|
||||
|
||||
@@ -10829,6 +10829,12 @@ static void rna_def_node(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Show Texture", "Display node in viewport textured shading mode");
|
||||
RNA_def_property_update(prop, 0, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "active_preview", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", NODE_ACTIVE_PREVIEW);
|
||||
RNA_def_property_ui_text(prop, "Active Preview", "Node is previewed in other editor");
|
||||
RNA_def_property_flag(prop, PROP_NO_DEG_UPDATE);
|
||||
RNA_def_property_update(prop, NC_NODE, NULL);
|
||||
|
||||
/* generic property update function */
|
||||
func = RNA_def_function(srna, "socket_value_update", "rna_Node_socket_value_update");
|
||||
RNA_def_function_ui_description(func, "Update after property changes");
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "BKE_node.h"
|
||||
#include "BKE_studiolight.h"
|
||||
|
||||
#include "ED_spreadsheet.h"
|
||||
#include "ED_text.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
@@ -3037,14 +3038,6 @@ static void rna_SpaceFileBrowser_browse_mode_update(Main *UNUSED(bmain),
|
||||
ED_area_tag_refresh(area);
|
||||
}
|
||||
|
||||
static void rna_SpaceSpreadsheet_pinned_id_set(PointerRNA *ptr,
|
||||
PointerRNA value,
|
||||
struct ReportList *UNUSED(reports))
|
||||
{
|
||||
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)ptr->data;
|
||||
sspreadsheet->pinned_id = value.data;
|
||||
}
|
||||
|
||||
static void rna_SpaceSpreadsheet_geometry_component_type_update(Main *UNUSED(bmain),
|
||||
Scene *UNUSED(scene),
|
||||
PointerRNA *ptr)
|
||||
@@ -3055,7 +3048,7 @@ static void rna_SpaceSpreadsheet_geometry_component_type_update(Main *UNUSED(bma
|
||||
}
|
||||
}
|
||||
|
||||
const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *C,
|
||||
const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *UNUSED(C),
|
||||
PointerRNA *ptr,
|
||||
PropertyRNA *UNUSED(prop),
|
||||
bool *r_free)
|
||||
@@ -3063,11 +3056,10 @@ const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *C,
|
||||
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)ptr->data;
|
||||
GeometryComponentType component_type = sspreadsheet->geometry_component_type;
|
||||
if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) {
|
||||
Object *active_object = CTX_data_active_object(C);
|
||||
Object *used_object = (sspreadsheet->pinned_id && GS(sspreadsheet->pinned_id->name) == ID_OB) ?
|
||||
(Object *)sspreadsheet->pinned_id :
|
||||
active_object;
|
||||
if (used_object != NULL) {
|
||||
ID *used_id = ED_spreadsheet_get_current_id(sspreadsheet);
|
||||
if (used_id != NULL) {
|
||||
if (GS(used_id->name) == ID_OB) {
|
||||
Object *used_object = (Object *)used_id;
|
||||
if (used_object->type == OB_POINTCLOUD) {
|
||||
component_type = GEO_COMPONENT_TYPE_POINT_CLOUD;
|
||||
}
|
||||
@@ -3076,6 +3068,7 @@ const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *C,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static EnumPropertyItem mesh_vertex_domain_item = {
|
||||
ATTR_DOMAIN_POINT, "POINT", 0, "Vertex", "Attribute per point/vertex"};
|
||||
@@ -3111,6 +3104,61 @@ const EnumPropertyItem *rna_SpaceSpreadsheet_attribute_domain_itemf(bContext *C,
|
||||
return item_array;
|
||||
}
|
||||
|
||||
static SpreadsheetContext *rna_SpaceSpreadsheet_context_path_append(SpaceSpreadsheet *sspreadsheet,
|
||||
int type)
|
||||
{
|
||||
SpreadsheetContext *context = ED_spreadsheet_context_new(type);
|
||||
BLI_addtail(&sspreadsheet->context_path, context);
|
||||
ED_spreadsheet_context_path_update_tag(sspreadsheet);
|
||||
WM_main_add_notifier(NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
|
||||
return context;
|
||||
}
|
||||
|
||||
static void rna_SpaceSpreadsheet_context_path_clear(SpaceSpreadsheet *sspreadsheet)
|
||||
{
|
||||
ED_spreadsheet_context_path_clear(sspreadsheet);
|
||||
ED_spreadsheet_context_path_update_tag(sspreadsheet);
|
||||
WM_main_add_notifier(NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
|
||||
}
|
||||
|
||||
static StructRNA *rna_spreadsheet_context_refine(PointerRNA *ptr)
|
||||
{
|
||||
SpreadsheetContext *context = ptr->data;
|
||||
switch (context->type) {
|
||||
case SPREADSHEET_CONTEXT_OBJECT:
|
||||
return &RNA_SpreadsheetContextObject;
|
||||
case SPREADSHEET_CONTEXT_MODIFIER:
|
||||
return &RNA_SpreadsheetContextModifier;
|
||||
case SPREADSHEET_CONTEXT_NODE:
|
||||
return &RNA_SpreadsheetContextNode;
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rna_spreadsheet_context_update(Main *UNUSED(bmain),
|
||||
Scene *UNUSED(scene),
|
||||
PointerRNA *ptr)
|
||||
{
|
||||
bScreen *screen = (bScreen *)ptr->owner_id;
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
SpaceLink *sl = area->spacedata.first;
|
||||
if (sl->spacetype == SPACE_SPREADSHEET) {
|
||||
SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl;
|
||||
ED_spreadsheet_context_path_update_tag(sspreadsheet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_spreadsheet_set_geometry_node_context(SpaceSpreadsheet *sspreadsheet,
|
||||
SpaceNode *snode,
|
||||
bNode *node)
|
||||
{
|
||||
ED_spreadsheet_set_geometry_node_context(sspreadsheet, snode, node);
|
||||
ED_spreadsheet_context_path_update_tag(sspreadsheet);
|
||||
WM_main_add_notifier(NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static const EnumPropertyItem dt_uv_items[] = {
|
||||
@@ -7338,10 +7386,93 @@ static void rna_def_space_clip(BlenderRNA *brna)
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
|
||||
}
|
||||
|
||||
static const EnumPropertyItem spreadsheet_context_type_items[] = {
|
||||
{SPREADSHEET_CONTEXT_OBJECT, "OBJECT", ICON_NONE, "Object", ""},
|
||||
{SPREADSHEET_CONTEXT_MODIFIER, "MODIFIER", ICON_NONE, "Modifier", ""},
|
||||
{SPREADSHEET_CONTEXT_NODE, "NODE", ICON_NONE, "Node", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static void rna_def_space_spreadsheet_context(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "SpreadsheetContext", NULL);
|
||||
RNA_def_struct_ui_text(srna, "Spreadsheet Context", "Element of spreadsheet context path");
|
||||
RNA_def_struct_refine_func(srna, "rna_spreadsheet_context_refine");
|
||||
|
||||
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, spreadsheet_context_type_items);
|
||||
RNA_def_property_ui_text(prop, "Type", "Type of the context");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
}
|
||||
|
||||
static void rna_def_space_spreadsheet_context_object(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "SpreadsheetContextObject", "SpreadsheetContext");
|
||||
|
||||
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Object");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, "rna_spreadsheet_context_update");
|
||||
}
|
||||
|
||||
static void rna_def_space_spreadsheet_context_modifier(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "SpreadsheetContextModifier", "SpreadsheetContext");
|
||||
|
||||
prop = RNA_def_property(srna, "modifier_name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Modifier Name", "");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, "rna_spreadsheet_context_update");
|
||||
}
|
||||
|
||||
static void rna_def_space_spreadsheet_context_node(BlenderRNA *brna)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *prop;
|
||||
|
||||
srna = RNA_def_struct(brna, "SpreadsheetContextNode", "SpreadsheetContext");
|
||||
|
||||
prop = RNA_def_property(srna, "node_name", PROP_STRING, PROP_NONE);
|
||||
RNA_def_property_ui_text(prop, "Node Name", "");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, "rna_spreadsheet_context_update");
|
||||
}
|
||||
|
||||
static void rna_def_space_spreadsheet_context_path(BlenderRNA *brna, PropertyRNA *cprop)
|
||||
{
|
||||
StructRNA *srna;
|
||||
PropertyRNA *parm;
|
||||
FunctionRNA *func;
|
||||
|
||||
RNA_def_property_srna(cprop, "SpreadsheetContextPath");
|
||||
srna = RNA_def_struct(brna, "SpreadsheetContextPath", NULL);
|
||||
RNA_def_struct_sdna(srna, "SpaceSpreadsheet");
|
||||
|
||||
func = RNA_def_function(srna, "append", "rna_SpaceSpreadsheet_context_path_append");
|
||||
RNA_def_function_ui_description(func, "Append a context path element");
|
||||
parm = RNA_def_property(func, "type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
RNA_def_property_enum_items(parm, spreadsheet_context_type_items);
|
||||
parm = RNA_def_pointer(
|
||||
func, "context", "SpreadsheetContext", "", "Newly created context path element");
|
||||
RNA_def_function_return(func, parm);
|
||||
|
||||
func = RNA_def_function(srna, "clear", "rna_SpaceSpreadsheet_context_path_clear");
|
||||
RNA_def_function_ui_description(func, "Clear entire context path");
|
||||
}
|
||||
|
||||
static void rna_def_space_spreadsheet(BlenderRNA *brna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
PropertyRNA *prop, *parm;
|
||||
StructRNA *srna;
|
||||
FunctionRNA *func;
|
||||
|
||||
static const EnumPropertyItem geometry_component_type_items[] = {
|
||||
{GEO_COMPONENT_TYPE_MESH,
|
||||
@@ -7363,35 +7494,44 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
|
||||
};
|
||||
|
||||
static const EnumPropertyItem object_eval_state_items[] = {
|
||||
{SPREADSHEET_OBJECT_EVAL_STATE_FINAL,
|
||||
"FINAL",
|
||||
{SPREADSHEET_OBJECT_EVAL_STATE_EVALUATED,
|
||||
"EVALUATED",
|
||||
ICON_NONE,
|
||||
"Final",
|
||||
"Use data from object with all modifiers applied"},
|
||||
"Evaluated",
|
||||
"Use data from fully or partially evaluated object"},
|
||||
{SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL,
|
||||
"ORIGINAL",
|
||||
ICON_NONE,
|
||||
"Original",
|
||||
"Use data from original object without any modifiers applied"},
|
||||
{SPREADSHEET_OBJECT_EVAL_STATE_NODE,
|
||||
"NODE",
|
||||
ICON_NONE,
|
||||
"Node",
|
||||
"Use data from the first geometry output of the node tagged for preview"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
rna_def_space_spreadsheet_context(brna);
|
||||
rna_def_space_spreadsheet_context_object(brna);
|
||||
rna_def_space_spreadsheet_context_modifier(brna);
|
||||
rna_def_space_spreadsheet_context_node(brna);
|
||||
|
||||
srna = RNA_def_struct(brna, "SpaceSpreadsheet", "Space");
|
||||
RNA_def_struct_ui_text(srna, "Space Spreadsheet", "Spreadsheet space data");
|
||||
|
||||
rna_def_space_generic_show_region_toggles(srna, (1 << RGN_TYPE_FOOTER));
|
||||
|
||||
prop = RNA_def_property(srna, "pinned_id", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_pointer_funcs(prop, NULL, "rna_SpaceSpreadsheet_pinned_id_set", NULL, NULL);
|
||||
RNA_def_property_ui_text(prop, "Pinned ID", "Data-block whose values are displayed");
|
||||
prop = RNA_def_property(srna, "is_pinned", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_FLAG_PINNED);
|
||||
RNA_def_property_ui_text(prop, "Is Pinned", "Context path is pinned");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "display_context_path_collapsed", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", SPREADSHEET_FLAG_CONTEXT_PATH_COLLAPSED);
|
||||
RNA_def_property_ui_text(prop, "Display Context Path Collapsed", "");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "context_path", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "SpreadsheetContext");
|
||||
RNA_def_property_ui_text(prop, "Context Path", "Context path to the data being displayed");
|
||||
rna_def_space_spreadsheet_context_path(brna, prop);
|
||||
|
||||
prop = RNA_def_property(srna, "show_only_selected", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "filter_flag", SPREADSHEET_FILTER_SELECTED_ONLY);
|
||||
RNA_def_property_ui_text(
|
||||
@@ -7416,6 +7556,16 @@ static void rna_def_space_spreadsheet(BlenderRNA *brna)
|
||||
RNA_def_property_enum_items(prop, object_eval_state_items);
|
||||
RNA_def_property_ui_text(prop, "Object Evaluation State", "");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SPREADSHEET, NULL);
|
||||
|
||||
func = RNA_def_function(
|
||||
srna, "set_geometry_node_context", "rna_spreadsheet_set_geometry_node_context");
|
||||
RNA_def_function_ui_description(
|
||||
func, "Update context_path to point to a specific node in a node editor");
|
||||
parm = RNA_def_pointer(
|
||||
func, "node_editor", "SpaceNodeEditor", "", "Editor to take the context from");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
parm = RNA_def_pointer(func, "node", "Node", "", "");
|
||||
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
|
||||
}
|
||||
|
||||
void RNA_def_space(BlenderRNA *brna)
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "BLI_float3.hh"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_multi_value_map.hh"
|
||||
#include "BLI_set.hh"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_utildefines.h"
|
||||
@@ -76,6 +77,8 @@
|
||||
#include "MOD_nodes.h"
|
||||
#include "MOD_ui_common.h"
|
||||
|
||||
#include "ED_spreadsheet.h"
|
||||
|
||||
#include "NOD_derived_node_tree.hh"
|
||||
#include "NOD_geometry.h"
|
||||
#include "NOD_geometry_exec.hh"
|
||||
@@ -1101,108 +1104,129 @@ static void reset_tree_ui_storage(Span<const blender::nodes::NodeTreeRef *> tree
|
||||
}
|
||||
}
|
||||
|
||||
static const DTreeContext *find_derived_tree_context_that_matches_tree_path(
|
||||
const SpaceNode &snode, const DerivedNodeTree &tree)
|
||||
static Vector<SpaceSpreadsheet *> find_spreadsheet_editors(Main *bmain)
|
||||
{
|
||||
const DTreeContext &root_context = tree.root_context();
|
||||
bNodeTree *root_tree_eval = root_context.tree().btree();
|
||||
bNodeTree *root_tree_orig = (bNodeTree *)DEG_get_original_id(&root_tree_eval->id);
|
||||
if (snode.nodetree != root_tree_orig) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const DTreeContext *current_context = &root_context;
|
||||
bool is_first = true;
|
||||
LISTBASE_FOREACH (const bNodeTreePath *, path, &snode.treepath) {
|
||||
if (is_first) {
|
||||
is_first = false;
|
||||
continue;
|
||||
}
|
||||
StringRef parent_node_name = path->node_name;
|
||||
const NodeTreeRef &tree_ref = current_context->tree();
|
||||
const NodeRef *parent_node_ref = nullptr;
|
||||
for (const NodeRef *node_ref : tree_ref.nodes()) {
|
||||
if (node_ref->name() == parent_node_name) {
|
||||
parent_node_ref = node_ref;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parent_node_ref == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
current_context = current_context->child_context(*parent_node_ref);
|
||||
if (current_context == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return current_context;
|
||||
}
|
||||
|
||||
static DNode find_active_preview_node_in_node_editor(const SpaceNode &snode,
|
||||
const DerivedNodeTree &tree)
|
||||
{
|
||||
const DTreeContext *context = find_derived_tree_context_that_matches_tree_path(snode, tree);
|
||||
if (context == nullptr) {
|
||||
return {};
|
||||
}
|
||||
const NodeTreeRef &tree_ref = context->tree();
|
||||
for (const NodeRef *node_ref : tree_ref.nodes()) {
|
||||
if (node_ref->bnode()->flag & NODE_ACTIVE_PREVIEW) {
|
||||
return {context, node_ref};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static DNode find_active_preview_node_in_all_node_editors(Depsgraph *depsgraph,
|
||||
const DerivedNodeTree &tree)
|
||||
{
|
||||
Main *bmain = DEG_get_bmain(depsgraph);
|
||||
Vector<SpaceSpreadsheet *> spreadsheets;
|
||||
wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
|
||||
LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
|
||||
bScreen *screen = BKE_workspace_active_screen_get(window->workspace_hook);
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
SpaceLink *sl = (SpaceLink *)area->spacedata.first;
|
||||
if (sl->spacetype != SPACE_NODE) {
|
||||
continue;
|
||||
}
|
||||
SpaceNode *snode = (SpaceNode *)sl;
|
||||
DNode preview_node = find_active_preview_node_in_node_editor(*snode, tree);
|
||||
if (!preview_node) {
|
||||
continue;
|
||||
}
|
||||
return preview_node;
|
||||
if (sl->spacetype == SPACE_SPREADSHEET) {
|
||||
spreadsheets.append((SpaceSpreadsheet *)sl);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
return spreadsheets;
|
||||
}
|
||||
|
||||
static DSocket find_preview_socket_in_all_node_editors(Depsgraph *depsgraph,
|
||||
const DerivedNodeTree &tree)
|
||||
using PreviewSocketMap = blender::MultiValueMap<DSocket, uint64_t>;
|
||||
|
||||
static DSocket try_find_preview_socket_in_node(const DNode node)
|
||||
{
|
||||
DNode preview_node = find_active_preview_node_in_all_node_editors(depsgraph, tree);
|
||||
if (!preview_node) {
|
||||
return {};
|
||||
}
|
||||
for (const SocketRef *socket : preview_node->outputs()) {
|
||||
for (const SocketRef *socket : node->outputs()) {
|
||||
if (socket->bsocket()->type == SOCK_GEOMETRY) {
|
||||
return {preview_node.context(), socket};
|
||||
return {node.context(), socket};
|
||||
}
|
||||
}
|
||||
for (const SocketRef *socket : preview_node->inputs()) {
|
||||
for (const SocketRef *socket : node->inputs()) {
|
||||
if (socket->bsocket()->type == SOCK_GEOMETRY &&
|
||||
(socket->bsocket()->flag & SOCK_MULTI_INPUT) == 0) {
|
||||
return {preview_node.context(), socket};
|
||||
return {node.context(), socket};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static void log_preview_socket_value(const Span<GPointer> values, Object *object)
|
||||
static DSocket try_get_socket_to_preview_for_spreadsheet(SpaceSpreadsheet *sspreadsheet,
|
||||
NodesModifierData *nmd,
|
||||
const ModifierEvalContext *ctx,
|
||||
const DerivedNodeTree &tree)
|
||||
{
|
||||
Vector<SpreadsheetContext *> context_path = sspreadsheet->context_path;
|
||||
if (context_path.size() < 3) {
|
||||
return {};
|
||||
}
|
||||
if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
|
||||
return {};
|
||||
}
|
||||
if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) {
|
||||
return {};
|
||||
}
|
||||
SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context_path[0];
|
||||
if (object_context->object != DEG_get_original_object(ctx->object)) {
|
||||
return {};
|
||||
}
|
||||
SpreadsheetContextModifier *modifier_context = (SpreadsheetContextModifier *)context_path[1];
|
||||
if (StringRef(modifier_context->modifier_name) != nmd->modifier.name) {
|
||||
return {};
|
||||
}
|
||||
for (SpreadsheetContext *context : context_path.as_span().drop_front(2)) {
|
||||
if (context->type != SPREADSHEET_CONTEXT_NODE) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Span<SpreadsheetContextNode *> nested_group_contexts =
|
||||
context_path.as_span().drop_front(2).drop_back(1).cast<SpreadsheetContextNode *>();
|
||||
SpreadsheetContextNode *last_context = (SpreadsheetContextNode *)context_path.last();
|
||||
|
||||
const DTreeContext *context = &tree.root_context();
|
||||
for (SpreadsheetContextNode *node_context : nested_group_contexts) {
|
||||
const NodeTreeRef &tree_ref = context->tree();
|
||||
const NodeRef *found_node = nullptr;
|
||||
for (const NodeRef *node_ref : tree_ref.nodes()) {
|
||||
if (node_ref->name() == node_context->node_name) {
|
||||
found_node = node_ref;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found_node == nullptr) {
|
||||
return {};
|
||||
}
|
||||
context = context->child_context(*found_node);
|
||||
if (context == nullptr) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
const NodeTreeRef &tree_ref = context->tree();
|
||||
for (const NodeRef *node_ref : tree_ref.nodes()) {
|
||||
if (node_ref->name() == last_context->node_name) {
|
||||
return try_find_preview_socket_in_node({context, node_ref});
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static void find_sockets_to_preview(NodesModifierData *nmd,
|
||||
const ModifierEvalContext *ctx,
|
||||
const DerivedNodeTree &tree,
|
||||
PreviewSocketMap &r_sockets_to_preview)
|
||||
{
|
||||
Main *bmain = DEG_get_bmain(ctx->depsgraph);
|
||||
|
||||
/* Based on every visible spreadsheet context path, get a list of sockets that need to have their
|
||||
* intermediate geometries cached for display. */
|
||||
Vector<SpaceSpreadsheet *> spreadsheets = find_spreadsheet_editors(bmain);
|
||||
for (SpaceSpreadsheet *sspreadsheet : spreadsheets) {
|
||||
const DSocket socket = try_get_socket_to_preview_for_spreadsheet(sspreadsheet, nmd, ctx, tree);
|
||||
if (socket) {
|
||||
const uint64_t key = ED_spreadsheet_context_path_hash(sspreadsheet);
|
||||
r_sockets_to_preview.add_non_duplicates(socket, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void log_preview_socket_value(const Span<GPointer> values,
|
||||
Object *object,
|
||||
Span<uint64_t> keys)
|
||||
{
|
||||
GeometrySet geometry_set = *(const GeometrySet *)values[0].get();
|
||||
geometry_set.ensure_owns_direct_data();
|
||||
BKE_object_set_preview_geometry_set(object, new GeometrySet(std::move(geometry_set)));
|
||||
for (uint64_t key : keys) {
|
||||
BKE_object_preview_geometry_set_add(object, key, new GeometrySet(geometry_set));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1260,11 +1284,16 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree,
|
||||
Vector<DInputSocket> group_outputs;
|
||||
group_outputs.append({root_context, &socket_to_compute});
|
||||
|
||||
const DSocket preview_socket = find_preview_socket_in_all_node_editors(ctx->depsgraph, tree);
|
||||
PreviewSocketMap preview_sockets;
|
||||
find_sockets_to_preview(nmd, ctx, tree, preview_sockets);
|
||||
|
||||
auto log_socket_value = [&](const DSocket socket, const Span<GPointer> values) {
|
||||
if (socket == preview_socket && nmd->modifier.flag & eModifierFlag_Active) {
|
||||
log_preview_socket_value(values, ctx->object);
|
||||
if (!DEG_is_active(ctx->depsgraph)) {
|
||||
return;
|
||||
}
|
||||
Span<uint64_t> keys = preview_sockets.lookup(socket);
|
||||
if (!keys.is_empty()) {
|
||||
log_preview_socket_value(values, ctx->object, keys);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user