Compare commits
8 Commits
arcpatch-D
...
temp-nodes
Author | SHA1 | Date | |
---|---|---|---|
51bc509d62 | |||
727b500465 | |||
65c13b0243 | |||
90f986cee4 | |||
a8327542c5 | |||
8b4052e063 | |||
2b43df378c | |||
65509a4a05 |
@@ -1865,7 +1865,8 @@ def km_node_editor(params):
|
||||
{"properties": [("replace", True)]}),
|
||||
op_menu("NODE_MT_add", {"type": 'A', "value": 'PRESS', "shift": True}),
|
||||
("node.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None),
|
||||
("node.duplicate_move_keep_inputs", {"type": 'D', "value": 'PRESS', "shift": True, "ctrl": True}, None),
|
||||
("node.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True, "ctrl": True},
|
||||
{"properties": [("NODE_OT_duplicate", [("keep_inputs", True)])]}),
|
||||
("node.parent_set", {"type": 'P', "value": 'PRESS', "ctrl": True}, None),
|
||||
("node.detach", {"type": 'P', "value": 'PRESS', "alt": True}, None),
|
||||
("node.join", {"type": 'J', "value": 'PRESS', "ctrl": True}, None),
|
||||
@@ -1910,6 +1911,12 @@ def km_node_editor(params):
|
||||
("node.translate_attach", {"type": 'G', "value": 'PRESS'}, None),
|
||||
("node.translate_attach", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None),
|
||||
("node.translate_attach", {"type": params.select_tweak, "value": 'ANY'}, None),
|
||||
("node.translate_attach", {"type": 'G', "value": 'PRESS', "alt": True},
|
||||
{"properties": [("TRANSFORM_OT_translate", [("node_unlink", True)])]}),
|
||||
("node.translate_attach", {"type": 'EVT_TWEAK_L', "value": 'ANY', "alt": True},
|
||||
{"properties": [("TRANSFORM_OT_translate", [("node_unlink", True)])]}),
|
||||
("node.translate_attach", {"type": params.select_tweak, "value": 'ANY', "alt": True},
|
||||
{"properties": [("TRANSFORM_OT_translate", [("node_unlink", True)])]}),
|
||||
("transform.translate", {"type": 'G', "value": 'PRESS'}, None),
|
||||
("transform.translate", {"type": 'EVT_TWEAK_L', "value": 'ANY'},
|
||||
{"properties": [("release_confirm", True)]}),
|
||||
@@ -1917,9 +1924,6 @@ def km_node_editor(params):
|
||||
{"properties": [("release_confirm", True)]}),
|
||||
("transform.rotate", {"type": 'R', "value": 'PRESS'}, None),
|
||||
("transform.resize", {"type": 'S', "value": 'PRESS'}, None),
|
||||
("node.move_detach_links", {"type": 'D', "value": 'PRESS', "alt": True}, None),
|
||||
("node.move_detach_links_release", {"type": params.action_tweak, "value": 'ANY', "alt": True}, None),
|
||||
("node.move_detach_links", {"type": params.select_tweak, "value": 'ANY', "alt": True}, None),
|
||||
("wm.context_toggle", {"type": 'TAB', "value": 'PRESS', "shift": True},
|
||||
{"properties": [("data_path", 'tool_settings.use_snap')]}),
|
||||
("wm.context_menu_enum", {"type": 'TAB', "value": 'PRESS', "shift": True, "ctrl": True},
|
||||
@@ -5182,6 +5186,8 @@ def km_transform_modal_map(_params):
|
||||
("AUTOIK_CHAIN_LEN_UP", {"type": 'WHEELDOWNMOUSE', "value": 'PRESS', "shift": True}, None),
|
||||
("AUTOIK_CHAIN_LEN_DOWN", {"type": 'WHEELUPMOUSE', "value": 'PRESS', "shift": True}, None),
|
||||
("INSERTOFS_TOGGLE_DIR", {"type": 'T', "value": 'PRESS'}, None),
|
||||
("NODE_UNLINK_ON", {"type": 'LEFT_ALT', "value": 'PRESS', "any": True}, None),
|
||||
("NODE_UNLINK_OFF", {"type": 'LEFT_ALT', "value": 'RELEASE', "any": True}, None),
|
||||
("AUTOCONSTRAIN", {"type": 'MIDDLEMOUSE', "value": 'ANY'}, None),
|
||||
("AUTOCONSTRAINPLANE", {"type": 'MIDDLEMOUSE', "value": 'ANY', "shift": True}, None),
|
||||
("PRECISION", {"type": 'LEFT_SHIFT', "value": 'ANY', "any": True}, None),
|
||||
|
@@ -139,7 +139,7 @@ class NodeAddOperator:
|
||||
|
||||
if self.use_transform and ('FINISHED' in result):
|
||||
# removes the node again if transform is canceled
|
||||
bpy.ops.node.translate_attach_remove_on_cancel('INVOKE_DEFAULT')
|
||||
bpy.ops.node.translate_attach('INVOKE_DEFAULT', TRANSFORM_OT_translate={"remove_on_cancel" : True})
|
||||
|
||||
return result
|
||||
|
||||
@@ -241,9 +241,8 @@ class NODE_OT_add_search(NodeAddOperator, Operator):
|
||||
self.create_node(context, item.nodetype)
|
||||
|
||||
if self.use_transform:
|
||||
bpy.ops.node.translate_attach_remove_on_cancel(
|
||||
'INVOKE_DEFAULT')
|
||||
|
||||
props = bpy.ops.node.translate_attach(
|
||||
'INVOKE_DEFAULT', TRANSFORM_OT_translate={"remove_on_cancel" : True})
|
||||
return {'FINISHED'}
|
||||
else:
|
||||
return {'CANCELLED'}
|
||||
|
@@ -2357,6 +2357,10 @@ bNodeLink *nodeAddLink(
|
||||
link->tonode = fromnode;
|
||||
link->tosock = fromsock;
|
||||
}
|
||||
else {
|
||||
/* Should never happen, incorrect socket in_out types. */
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
if (ntree) {
|
||||
ntree->update |= NTREE_UPDATE_LINKS;
|
||||
|
@@ -56,6 +56,18 @@ typedef enum {
|
||||
#define NODE_EDGE_PAN_MAX_SPEED 40 /* In UI units per second, slower than default. */
|
||||
#define NODE_EDGE_PAN_DELAY 1.0f
|
||||
|
||||
/* Result of the dissolve operation on node links.
|
||||
* Note: this data becomes invalid if nodes or links are removed from the tree.
|
||||
*/
|
||||
typedef struct NodeEditDissolveLinksData {
|
||||
/* Links that have been removed (not part of the tree any longer). */
|
||||
struct bNodeLink *removed_links;
|
||||
/* Links that have been added to replace old links. */
|
||||
struct bNodeLink **added_links;
|
||||
int tot_removed_links;
|
||||
int tot_added_links;
|
||||
} NodeEditDissolveLinksData;
|
||||
|
||||
/* space_node.c */
|
||||
|
||||
void ED_node_cursor_location_get(const struct SpaceNode *snode, float value[2]);
|
||||
@@ -98,8 +110,17 @@ void ED_node_sort(struct bNodeTree *ntree);
|
||||
float ED_node_grid_size(void);
|
||||
|
||||
/* node_relationships.c */
|
||||
void ED_node_link_intersect_test(struct ScrArea *area, int test);
|
||||
void ED_node_link_insert(struct Main *bmain, struct ScrArea *area);
|
||||
void ED_node_link_hilite_clear(struct ScrArea *area);
|
||||
void ED_node_link_hilite_intersected(struct ScrArea *area);
|
||||
void ED_node_link_hilite_insert(struct Main *bmain, struct ScrArea *area);
|
||||
|
||||
void ED_node_dissolve_links(struct Main *bmain,
|
||||
struct bNodeTree *ntree,
|
||||
struct NodeEditDissolveLinksData *data);
|
||||
void ED_node_dissolve_undo(struct Main *bmain,
|
||||
struct bNodeTree *ntree,
|
||||
const struct NodeEditDissolveLinksData *data);
|
||||
void ED_node_dissolve_free_data(struct NodeEditDissolveLinksData *data);
|
||||
|
||||
/* node_edit.c */
|
||||
void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo);
|
||||
|
@@ -137,6 +137,7 @@ int BIF_countTransformOrientation(const struct bContext *C);
|
||||
#define P_GPENCIL_EDIT (1 << 13)
|
||||
#define P_CURSOR_EDIT (1 << 14)
|
||||
#define P_CLNOR_INVALIDATE (1 << 15)
|
||||
#define P_NODES (1 << 16)
|
||||
/* For properties performed when confirming the transformation. */
|
||||
#define P_POST_TRANSFORM (1 << 19)
|
||||
|
||||
|
@@ -1876,9 +1876,10 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
|
||||
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
|
||||
|
||||
ED_node_dissolve_links(bmain, snode->edittree, NULL);
|
||||
|
||||
LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) {
|
||||
if (node->flag & SELECT) {
|
||||
nodeInternalRelink(snode->edittree, node);
|
||||
nodeRemoveNode(bmain, snode->edittree, node, true);
|
||||
}
|
||||
}
|
||||
|
@@ -148,16 +148,6 @@ void ED_operatormacros_node(void)
|
||||
WM_operatortype_macro_define(ot, "NODE_OT_attach");
|
||||
WM_operatortype_macro_define(ot, "NODE_OT_insert_offset");
|
||||
|
||||
/* NODE_OT_translate_attach with remove_on_canel set to true */
|
||||
ot = WM_operatortype_append_macro("NODE_OT_translate_attach_remove_on_cancel",
|
||||
"Move and Attach",
|
||||
"Move nodes and attach to frame",
|
||||
OPTYPE_UNDO | OPTYPE_REGISTER);
|
||||
mot = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
|
||||
RNA_boolean_set(mot->ptr, "remove_on_cancel", true);
|
||||
WM_operatortype_macro_define(ot, "NODE_OT_attach");
|
||||
WM_operatortype_macro_define(ot, "NODE_OT_insert_offset");
|
||||
|
||||
/* NOTE: Currently not in a default keymap or menu due to messy keymaps
|
||||
* and tricky invoke functionality.
|
||||
* Kept around in case users want to make own shortcuts.
|
||||
@@ -176,30 +166,6 @@ void ED_operatormacros_node(void)
|
||||
OPTYPE_UNDO | OPTYPE_REGISTER);
|
||||
WM_operatortype_macro_define(ot, "NODE_OT_duplicate");
|
||||
WM_operatortype_macro_define(ot, "NODE_OT_translate_attach");
|
||||
|
||||
/* modified operator call for duplicating with input links */
|
||||
ot = WM_operatortype_append_macro("NODE_OT_duplicate_move_keep_inputs",
|
||||
"Duplicate",
|
||||
"Duplicate selected nodes keeping input links and move them",
|
||||
OPTYPE_UNDO | OPTYPE_REGISTER);
|
||||
mot = WM_operatortype_macro_define(ot, "NODE_OT_duplicate");
|
||||
RNA_boolean_set(mot->ptr, "keep_inputs", true);
|
||||
WM_operatortype_macro_define(ot, "NODE_OT_translate_attach");
|
||||
|
||||
ot = WM_operatortype_append_macro("NODE_OT_move_detach_links",
|
||||
"Detach",
|
||||
"Move a node to detach links",
|
||||
OPTYPE_UNDO | OPTYPE_REGISTER);
|
||||
WM_operatortype_macro_define(ot, "NODE_OT_links_detach");
|
||||
WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
|
||||
WM_operatortype_macro_define(ot, "NODE_OT_insert_offset");
|
||||
|
||||
ot = WM_operatortype_append_macro("NODE_OT_move_detach_links_release",
|
||||
"Detach",
|
||||
"Move a node to detach links",
|
||||
OPTYPE_UNDO | OPTYPE_REGISTER);
|
||||
WM_operatortype_macro_define(ot, "NODE_OT_links_detach");
|
||||
WM_operatortype_macro_define(ot, "NODE_OT_translate_attach");
|
||||
}
|
||||
|
||||
void node_keymap(struct wmKeyConfig *keyconf)
|
||||
|
@@ -29,6 +29,10 @@
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_easing.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_multi_value_map.hh"
|
||||
#include "BLI_set.hh"
|
||||
#include "BLI_stack.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "BKE_anim_data.h"
|
||||
#include "BKE_context.h"
|
||||
@@ -1515,11 +1519,7 @@ static int detach_links_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
|
||||
ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
|
||||
|
||||
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
||||
if (node->flag & SELECT) {
|
||||
nodeInternalRelink(ntree, node);
|
||||
}
|
||||
}
|
||||
ED_node_dissolve_links(CTX_data_main(C), ntree, NULL);
|
||||
|
||||
ntreeUpdateTree(CTX_data_main(C), ntree);
|
||||
|
||||
@@ -1855,10 +1855,7 @@ void NODE_OT_detach(wmOperatorType *ot)
|
||||
* \{ */
|
||||
|
||||
/* prevent duplicate testing code below */
|
||||
static bool ed_node_link_conditions(ScrArea *area,
|
||||
bool test,
|
||||
SpaceNode **r_snode,
|
||||
bNode **r_select)
|
||||
static bool ed_node_link_conditions(ScrArea *area, SpaceNode **r_snode, bNode **r_select)
|
||||
{
|
||||
SpaceNode *snode = area ? (SpaceNode *)area->spacedata.first : nullptr;
|
||||
|
||||
@@ -1870,11 +1867,6 @@ static bool ed_node_link_conditions(ScrArea *area,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!test) {
|
||||
/* no need to look for a node */
|
||||
return true;
|
||||
}
|
||||
|
||||
bNode *node;
|
||||
bNode *select = nullptr;
|
||||
for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) {
|
||||
@@ -1912,12 +1904,25 @@ static bool ed_node_link_conditions(ScrArea *area,
|
||||
return true;
|
||||
}
|
||||
|
||||
/* test == 0, clear all intersect flags */
|
||||
void ED_node_link_intersect_test(ScrArea *area, int test)
|
||||
/* Clear NODE_LINKFLAG_HILITE flags. */
|
||||
void ED_node_link_hilite_clear(ScrArea *area)
|
||||
{
|
||||
if (area == nullptr || area->spacetype != SPACE_NODE) {
|
||||
return;
|
||||
}
|
||||
SpaceNode *snode = (SpaceNode *)area->spacedata.first;
|
||||
|
||||
LISTBASE_FOREACH (bNodeLink *, link, &snode->edittree->links) {
|
||||
link->flag &= ~NODE_LINKFLAG_HILITE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sets NODE_LINKFLAG_HILITE on all links intersected by selected nodes. */
|
||||
void ED_node_link_hilite_intersected(ScrArea *area)
|
||||
{
|
||||
bNode *select;
|
||||
SpaceNode *snode;
|
||||
if (!ed_node_link_conditions(area, test, &snode, &select)) {
|
||||
if (!ed_node_link_conditions(area, &snode, &select)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1926,10 +1931,6 @@ void ED_node_link_intersect_test(ScrArea *area, int test)
|
||||
link->flag &= ~NODE_LINKFLAG_HILITE;
|
||||
}
|
||||
|
||||
if (test == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
|
||||
|
||||
/* find link to select/highlight */
|
||||
@@ -2371,11 +2372,11 @@ void NODE_OT_insert_offset(wmOperatorType *ot)
|
||||
* \{ */
|
||||
|
||||
/* assumes link with NODE_LINKFLAG_HILITE set */
|
||||
void ED_node_link_insert(Main *bmain, ScrArea *area)
|
||||
void ED_node_link_hilite_insert(Main *bmain, ScrArea *area)
|
||||
{
|
||||
bNode *select;
|
||||
SpaceNode *snode;
|
||||
if (!ed_node_link_conditions(area, true, &snode, &select)) {
|
||||
if (!ed_node_link_conditions(area, &snode, &select)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2428,3 +2429,166 @@ void ED_node_link_insert(Main *bmain, ScrArea *area)
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Node Dissolve Links
|
||||
* \{ */
|
||||
|
||||
namespace blender {
|
||||
|
||||
typedef MultiValueMap<bNodeSocket *, bNodeLink *> NodeEditDissolveLinkMap;
|
||||
|
||||
NodeEditDissolveLinkMap node_dissolve_build_link_map(bNodeTree *ntree)
|
||||
{
|
||||
NodeEditDissolveLinkMap socket_links;
|
||||
|
||||
/* Map all links to a selected node. */
|
||||
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
|
||||
if (link->tonode->flag & NODE_SELECT) {
|
||||
socket_links.add(link->tosock, link);
|
||||
}
|
||||
}
|
||||
/* Map internal links that connect node inputs to outputs. */
|
||||
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
||||
if (node->flag & NODE_SELECT) {
|
||||
LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
|
||||
socket_links.add(link->tosock, link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return socket_links;
|
||||
}
|
||||
|
||||
Vector<bNodeLink *> node_dissolve_find_incoming_links(const NodeEditDissolveLinkMap &socket_links,
|
||||
bNodeLink *out_link)
|
||||
{
|
||||
Stack<bNodeLink *> link_stack;
|
||||
Set<bNodeSocket *> visited;
|
||||
Vector<bNodeLink *> result;
|
||||
|
||||
/* Depth-first search to find links that have no fromsock in the map. */
|
||||
link_stack.push(out_link);
|
||||
do {
|
||||
bNodeLink *link = link_stack.pop();
|
||||
if (visited.contains(link->fromsock)) {
|
||||
continue;
|
||||
}
|
||||
visited.add(link->fromsock);
|
||||
|
||||
const Span<bNodeLink *> in_links = socket_links.lookup(link->fromsock);
|
||||
if (in_links.is_empty()) {
|
||||
/* Place incoming links from unselected nodes in the result. */
|
||||
if (!(link->fromnode->flag & NODE_SELECT)) {
|
||||
/* Should only have actual tree links from unselected nodes, never internal links. */
|
||||
BLI_assert(link->fromsock->in_out == SOCK_OUT && link->tosock->in_out == SOCK_IN);
|
||||
result.append(link);
|
||||
}
|
||||
}
|
||||
else {
|
||||
link_stack.push_multiple(in_links);
|
||||
}
|
||||
} while (!link_stack.is_empty());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
|
||||
/* Replace links to and from selected nodes.
|
||||
* Appropriate direct connections are created to replace connections if possible.
|
||||
* Data about replaced links is returned and can be used to undo the dissolve.
|
||||
* Note: Dissolve data becomes invalid if nodes or links are removed from the tree.
|
||||
*/
|
||||
void ED_node_dissolve_links(Main *bmain, bNodeTree *ntree, NodeEditDissolveLinksData *data)
|
||||
{
|
||||
/* Links that are being removed, for output data. */
|
||||
blender::Vector<bNodeLink> removed_links;
|
||||
/* Replacement links that have been added, for output data. */
|
||||
blender::Vector<bNodeLink *> added_links;
|
||||
|
||||
/* Incoming links for sockets.
|
||||
* Most node systems only allow one incoming socket link,
|
||||
* but the map allows for more than one link if needed. */
|
||||
blender::NodeEditDissolveLinkMap socket_links = blender::node_dissolve_build_link_map(ntree);
|
||||
|
||||
/* Find outgoing links from the selected nodes and replace them. */
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
|
||||
const bool from_selected = link->fromnode->flag & NODE_SELECT;
|
||||
const bool to_selected = link->tonode->flag & NODE_SELECT;
|
||||
if (from_selected && !to_selected) {
|
||||
/* Find all incoming links connected to the outgoing link. */
|
||||
blender::Vector<bNodeLink *> in_links = blender::node_dissolve_find_incoming_links(
|
||||
socket_links, link);
|
||||
for (bNodeLink *in_link : in_links) {
|
||||
bNodeLink *replace_link = nodeAddLink(
|
||||
ntree, in_link->fromnode, in_link->fromsock, link->tonode, link->tosock);
|
||||
/* Remember for output. */
|
||||
if (data) {
|
||||
added_links.append(replace_link);
|
||||
}
|
||||
}
|
||||
|
||||
/* Remember for output. */
|
||||
if (data) {
|
||||
removed_links.append(*link);
|
||||
}
|
||||
/* This link has been replaced. */
|
||||
nodeRemLink(ntree, link);
|
||||
}
|
||||
}
|
||||
/* Find incoming links from the selected nodes and remove them.
|
||||
* Note: this must happen after all outgoing links have been replaced.
|
||||
*/
|
||||
LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
|
||||
const bool from_selected = link->fromnode->flag & NODE_SELECT;
|
||||
const bool to_selected = link->tonode->flag & NODE_SELECT;
|
||||
if (!from_selected && to_selected) {
|
||||
/* Remember for output. */
|
||||
if (data) {
|
||||
removed_links.append(*link);
|
||||
}
|
||||
/* This link has been replaced. */
|
||||
nodeRemLink(ntree, link);
|
||||
}
|
||||
}
|
||||
|
||||
if (data) {
|
||||
data->tot_removed_links = removed_links.size();
|
||||
data->tot_added_links = added_links.size();
|
||||
data->removed_links = (bNodeLink *)MEM_mallocN(sizeof(bNodeLink) * removed_links.size(),
|
||||
"removed links");
|
||||
memcpy(data->removed_links, removed_links.data(), sizeof(bNodeLink) * removed_links.size());
|
||||
data->added_links = (bNodeLink **)MEM_mallocN(sizeof(bNodeLink *) * added_links.size(),
|
||||
"removed links");
|
||||
memcpy(data->added_links, added_links.data(), sizeof(bNodeLink *) * added_links.size());
|
||||
}
|
||||
|
||||
ntreeUpdateTree(bmain, ntree);
|
||||
}
|
||||
|
||||
/* Restore links stored in the dissolve data. */
|
||||
void ED_node_dissolve_undo(Main *bmain, bNodeTree *ntree, const NodeEditDissolveLinksData *data)
|
||||
{
|
||||
for (bNodeLink *link : blender::Span<bNodeLink *>(data->added_links, data->tot_added_links)) {
|
||||
nodeRemLink(ntree, link);
|
||||
}
|
||||
for (const bNodeLink &link :
|
||||
blender::Span<bNodeLink>(data->removed_links, data->tot_removed_links)) {
|
||||
nodeAddLink(ntree, link.fromnode, link.fromsock, link.tonode, link.tosock);
|
||||
}
|
||||
|
||||
ntreeUpdateTree(bmain, ntree);
|
||||
}
|
||||
|
||||
/* Free node dissolve data. */
|
||||
void ED_node_dissolve_free_data(NodeEditDissolveLinksData *data)
|
||||
{
|
||||
if (data) {
|
||||
MEM_freeN(data->removed_links);
|
||||
MEM_freeN(data->added_links);
|
||||
MEM_freeN(data);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -625,7 +625,9 @@ static bool transform_modal_item_poll(const wmOperator *op, int value)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TFM_MODAL_INSERTOFS_TOGGLE_DIR: {
|
||||
case TFM_MODAL_INSERTOFS_TOGGLE_DIR:
|
||||
case TFM_MODAL_NODE_UNLINK_ON:
|
||||
case TFM_MODAL_NODE_UNLINK_OFF: {
|
||||
if (t->spacetype != SPACE_NODE) {
|
||||
return false;
|
||||
}
|
||||
@@ -696,6 +698,8 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
|
||||
{TFM_MODAL_AUTOCONSTRAINT, "AUTOCONSTRAIN", 0, "Automatic Constraint", ""},
|
||||
{TFM_MODAL_AUTOCONSTRAINTPLANE, "AUTOCONSTRAINPLANE", 0, "Automatic Constraint Plane", ""},
|
||||
{TFM_MODAL_PRECISION, "PRECISION", 0, "Precision Mode", ""},
|
||||
{TFM_MODAL_NODE_UNLINK_ON, "NODE_UNLINK_ON", 0, "Unlink nodes", ""},
|
||||
{TFM_MODAL_NODE_UNLINK_OFF, "NODE_UNLINK_OFF", 0, "Unlink nodes (Off)", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
@@ -1065,6 +1069,16 @@ int transformEvent(TransInfo *t, const wmEvent *event)
|
||||
t->redraw |= TREDRAW_SOFT;
|
||||
}
|
||||
break;
|
||||
case TFM_MODAL_NODE_UNLINK_ON:
|
||||
t->flag |= T_NODE_UNLINK;
|
||||
t->redraw |= TREDRAW_HARD;
|
||||
handled = true;
|
||||
break;
|
||||
case TFM_MODAL_NODE_UNLINK_OFF:
|
||||
t->flag &= ~T_NODE_UNLINK;
|
||||
t->redraw |= TREDRAW_HARD;
|
||||
handled = true;
|
||||
break;
|
||||
case TFM_MODAL_AUTOCONSTRAINT:
|
||||
case TFM_MODAL_AUTOCONSTRAINTPLANE:
|
||||
if ((t->flag & T_RELEASE_CONFIRM) && (event->prevval == KM_RELEASE) &&
|
||||
|
@@ -152,6 +152,9 @@ typedef enum {
|
||||
|
||||
/** No cursor wrapping on region bounds */
|
||||
T_NO_CURSOR_WRAP = 1 << 23,
|
||||
|
||||
/** Nodes detach from existing links and don't insert on intersected links. */
|
||||
T_NODE_UNLINK = 1 << 24,
|
||||
} eTFlag;
|
||||
|
||||
/** #TransInfo.modifiers */
|
||||
@@ -289,6 +292,10 @@ enum {
|
||||
TFM_MODAL_AUTOCONSTRAINTPLANE = 29,
|
||||
|
||||
TFM_MODAL_PRECISION = 30,
|
||||
|
||||
/** Node link intersect toggle. */
|
||||
TFM_MODAL_NODE_UNLINK_ON = 31,
|
||||
TFM_MODAL_NODE_UNLINK_OFF = 32,
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
@@ -50,6 +50,7 @@ typedef struct NodeTransCustomData {
|
||||
/* Initial rect of the view2d, used for computing offset during edge panning */
|
||||
rctf initial_v2d_cur;
|
||||
View2DEdgePanData edge_pan;
|
||||
NodeEditDissolveLinksData *dissolve_links_data;
|
||||
} NodeTransCustomData;
|
||||
|
||||
/* transcribe given node into TransData2D for Transforming */
|
||||
@@ -174,9 +175,9 @@ void createTransNodeData(TransInfo *t)
|
||||
|
||||
void flushTransNodes(TransInfo *t)
|
||||
{
|
||||
const float dpi_fac = UI_DPI_FAC;
|
||||
|
||||
struct Main *bmain = CTX_data_main(t->context);
|
||||
NodeTransCustomData *customdata = (NodeTransCustomData *)t->custom.type.data;
|
||||
const float dpi_fac = UI_DPI_FAC;
|
||||
|
||||
if (t->mode == TFM_TRANSLATION) {
|
||||
/* Edge panning functions expect window coordinates, mval is relative to region */
|
||||
@@ -222,9 +223,22 @@ void flushTransNodes(TransInfo *t)
|
||||
node->locy = loc[1];
|
||||
}
|
||||
|
||||
/* handle intersection with noodles */
|
||||
if (tc->data_len == 1) {
|
||||
ED_node_link_intersect_test(t->area, 1);
|
||||
/* Handle intersection with links. */
|
||||
if (t->flag & T_NODE_UNLINK) {
|
||||
ED_node_link_hilite_clear(t->area);
|
||||
|
||||
if (customdata->dissolve_links_data == NULL) {
|
||||
/* Unlink transformed nodes. */
|
||||
SpaceNode *snode = t->area->spacedata.first;
|
||||
bNodeTree *ntree = snode->edittree;
|
||||
|
||||
customdata->dissolve_links_data = MEM_callocN(sizeof(NodeEditDissolveLinksData),
|
||||
"node link dissolve data");
|
||||
ED_node_dissolve_links(bmain, ntree, customdata->dissolve_links_data);
|
||||
}
|
||||
}
|
||||
else if (tc->data_len == 1) {
|
||||
ED_node_link_hilite_intersected(t->area);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,29 +252,38 @@ void flushTransNodes(TransInfo *t)
|
||||
void special_aftertrans_update__node(bContext *C, TransInfo *t)
|
||||
{
|
||||
struct Main *bmain = CTX_data_main(C);
|
||||
NodeTransCustomData *customdata = (NodeTransCustomData *)t->custom.type.data;
|
||||
const bool canceled = (t->state == TRANS_CANCEL);
|
||||
|
||||
SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
|
||||
if (canceled && t->remove_on_cancel) {
|
||||
/* remove selected nodes on cancel */
|
||||
bNodeTree *ntree = snode->edittree;
|
||||
if (ntree) {
|
||||
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
|
||||
if (node->flag & NODE_SELECT) {
|
||||
nodeRemoveNode(bmain, ntree, node, true);
|
||||
bNodeTree *ntree = snode->edittree;
|
||||
|
||||
if (canceled) {
|
||||
if (t->remove_on_cancel) {
|
||||
/* remove selected nodes on cancel */
|
||||
if (ntree) {
|
||||
LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) {
|
||||
if (node->flag & NODE_SELECT) {
|
||||
nodeRemoveNode(bmain, ntree, node, true);
|
||||
}
|
||||
}
|
||||
ntreeUpdateTree(bmain, ntree);
|
||||
}
|
||||
ntreeUpdateTree(bmain, ntree);
|
||||
}
|
||||
else if (customdata->dissolve_links_data) {
|
||||
ED_node_dissolve_undo(bmain, ntree, customdata->dissolve_links_data);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ED_node_post_apply_transform(C, snode->edittree);
|
||||
|
||||
if (!(t->flag & T_NODE_UNLINK)) {
|
||||
ED_node_link_hilite_insert(bmain, t->area);
|
||||
}
|
||||
}
|
||||
|
||||
if (!canceled) {
|
||||
ED_node_post_apply_transform(C, snode->edittree);
|
||||
ED_node_link_insert(bmain, t->area);
|
||||
}
|
||||
|
||||
/* clear link line */
|
||||
ED_node_link_intersect_test(t->area, 0);
|
||||
ED_node_dissolve_free_data(customdata->dissolve_links_data);
|
||||
ED_node_link_hilite_clear(t->area);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -634,6 +634,15 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
|
||||
t->flag |= T_OVERRIDE_CENTER;
|
||||
}
|
||||
|
||||
if (t->spacetype == SPACE_NODE) {
|
||||
if (op && (prop = RNA_struct_find_property(op->ptr, "node_unlink")) &&
|
||||
RNA_property_is_set(op->ptr, prop)) {
|
||||
if (RNA_property_boolean_get(op->ptr, prop)) {
|
||||
t->flag |= T_NODE_UNLINK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setTransformViewMatrices(t);
|
||||
initNumInput(&t->num);
|
||||
}
|
||||
|
@@ -692,6 +692,14 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
|
||||
ot->srna, "correct_uv", true, "Correct UVs", "Correct UV coordinates when transforming");
|
||||
}
|
||||
|
||||
if (flags & P_NODES) {
|
||||
RNA_def_boolean(ot->srna,
|
||||
"node_unlink",
|
||||
false,
|
||||
"Unlink Nodes",
|
||||
"Detach nodes from links and don't insert on intersected links");
|
||||
}
|
||||
|
||||
if (flags & P_CENTER) {
|
||||
/* For gizmos that define their own center. */
|
||||
prop = RNA_def_property(ot->srna, "center_override", PROP_FLOAT, PROP_XYZ);
|
||||
@@ -745,7 +753,8 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
|
||||
|
||||
Transform_Properties(ot,
|
||||
P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP |
|
||||
P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT | P_POST_TRANSFORM);
|
||||
P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT | P_NODES |
|
||||
P_POST_TRANSFORM);
|
||||
}
|
||||
|
||||
static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
|
||||
|
Reference in New Issue
Block a user