WIP: Compositor Viewer shortcuts prototype #105268

Draft
Habib Gahbiche wants to merge 1 commits from zazizizou/blender-addons:com-wrangler-viewer-shortcuts into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
2 changed files with 139 additions and 0 deletions

View File

@ -20,6 +20,7 @@ from mathutils import Vector
from os import path
from glob import glob
from copy import copy
import json
from itertools import chain
from .interface import NWConnectionListInputs, NWConnectionListOutputs
@ -486,6 +487,54 @@ class NWAddAttrNode(Operator, NWBase):
return {'FINISHED'}
class NWFastPreview(Operator):
bl_idname = "node.nw_fast_preview"
bl_label = "Fast Preview"
bl_description = "Preview favorite nodes by pressing 1, 2, 3, 4 and 5"
bl_options = {'REGISTER', 'UNDO'}
# Workaround: simulating a dict with json.loads() and json.dumps()
Review

You can store the dict directly here, I don’t think you need to bother serializing to a property.

You can store the dict directly here, I don’t think you need to bother serializing to a property.
node_preview_map : StringProperty(name="")
update_map : BoolProperty(default=False)
viewer_index : IntProperty()
@classmethod
def poll(self, context):
return bpy.ops.node.link_viewer.poll()
def execute(self, context):
nodes, _ = get_nodes_links(context)
if self.node_preview_map != '':
temp_dict = json.loads(self.node_preview_map)
else:
temp_dict = {}
selected_nodes = context.selected_nodes
if self.update_map:
if len(selected_nodes) > 0:
n1 = selected_nodes[0]
temp_dict[self.viewer_index] = n1.name
self.node_preview_map = json.dumps(temp_dict)
bpy.ops.node.link_viewer()
Review

With a slight modification of NWPreviewNode, you could use this to make it work in shader trees as well:

                if context.space_data.tree_type in {'CompositorNodeTree', 'GeometryNodeTree'}:
                    bpy.ops.node.link_viewer()
                elif context.space_data.tree_type == 'ShaderNodeTree':
                    bpy.ops.node.nw_preview_node()

@@ -764,6 +764,8 @@ class NWPreviewNode(Operator, NWBase):
         if 'FINISHED' not in select_node:  # only run if mouse click is on a node
             return {'CANCELLED'}
 
+    def execute(self, context):
+        space = context.space_data
         base_node_tree = space.node_tree
         active_tree = context.space_data.edit_tree
         path = context.space_data.path
With a slight modification of `NWPreviewNode`, you could use this to make it work in shader trees as well: ```python if context.space_data.tree_type in {'CompositorNodeTree', 'GeometryNodeTree'}: bpy.ops.node.link_viewer() elif context.space_data.tree_type == 'ShaderNodeTree': bpy.ops.node.nw_preview_node() ``` --- ```diff @@ -764,6 +764,8 @@ class NWPreviewNode(Operator, NWBase): if 'FINISHED' not in select_node: # only run if mouse click is on a node return {'CANCELLED'} + def execute(self, context): + space = context.space_data base_node_tree = space.node_tree active_tree = context.space_data.edit_tree path = context.space_data.path ```
self.report({'INFO'}, "Set node %s to shortcut %i" % (n1.name, self.viewer_index))
else:
self.report({'ERROR'}, "No previews to set. Reason: No nodes selected.")
else:
if str(self.viewer_index) in temp_dict:
if temp_dict[str(self.viewer_index)] in nodes:
n = nodes[temp_dict[str(self.viewer_index)]]
n.select = True
nodes.active = n
bpy.ops.node.link_viewer()
n.select = False
return {'FINISHED'}
class NWPreviewNode(Operator, NWBase):
bl_idname = "node.nw_preview_node"
bl_label = "Preview Node"
@ -2592,6 +2641,63 @@ class NWAddMultipleImages(Operator, NWBase, ImportHelper):
return {'FINISHED'}
class NWViewerFocus(bpy.types.Operator):
Review

I think this was added back by mistake?

I think this was added back by mistake?
"""Set the viewer tile center to the mouse position"""
bl_idname = "node.nw_viewer_focus"
bl_label = "Viewer Focus"
x: bpy.props.IntProperty()
y: bpy.props.IntProperty()
@classmethod
def poll(cls, context):
return (nw_check(cls, context)
and nw_check_space_type(cls, context, {'CompositorNodeTree'}))
def execute(self, context):
return {'FINISHED'}
def invoke(self, context, event):
render = context.scene.render
space = context.space_data
percent = render.resolution_percentage * 0.01
nodes, links = get_nodes_links(context)
viewers = [n for n in nodes if n.type == 'VIEWER']
if viewers:
mlocx = event.mouse_region_x
mlocy = event.mouse_region_y
select_node = bpy.ops.node.select(location=(mlocx, mlocy), extend=False)
if 'FINISHED' not in select_node: # only run if we're not clicking on a node
region_x = context.region.width
region_y = context.region.height
region_center_x = context.region.width / 2
region_center_y = context.region.height / 2
bd_x = render.resolution_x * percent * space.backdrop_zoom
bd_y = render.resolution_y * percent * space.backdrop_zoom
backdrop_center_x = (bd_x / 2) - space.backdrop_offset[0]
backdrop_center_y = (bd_y / 2) - space.backdrop_offset[1]
margin_x = region_center_x - backdrop_center_x
margin_y = region_center_y - backdrop_center_y
abs_mouse_x = (mlocx - margin_x) / bd_x
abs_mouse_y = (mlocy - margin_y) / bd_y
for node in viewers:
node.center_x = abs_mouse_x
node.center_y = abs_mouse_y
else:
return {'PASS_THROUGH'}
return self.execute(context)
class NWSaveViewer(bpy.types.Operator, ExportHelper):
"""Save the current viewer node to an image file"""
bl_idname = "node.nw_save_viewer"
@ -2759,6 +2865,7 @@ classes = (
NWSwapLinks,
NWResetBG,
NWAddAttrNode,
NWFastPreview,
NWPreviewNode,
NWFrameSelected,
NWReloadImages,
@ -2781,6 +2888,7 @@ classes = (
NWCallInputsMenu,
NWAddSequence,
NWAddMultipleImages,
NWViewerFocus,
NWSaveViewer,
NWResetNodes,
)

View File

@ -338,6 +338,35 @@ kmi_defs = (
False, (('run_in_geometry_nodes', False),), "Preview node output"),
(operators.NWPreviewNode.bl_idname, 'LEFTMOUSE', 'PRESS', False, True,
True, (('run_in_geometry_nodes', True),), "Preview node output"),
# Fast Preview
(operators.NWFastPreview.bl_idname, 'ONE', 'PRESS', False, False, False,
(('viewer_index', 1), ('update_map', False)), "Fast Preview"),
(operators.NWFastPreview.bl_idname, 'ONE', 'PRESS', True, False, False,
(('viewer_index', 1), ('update_map', True)), "Fast Preview"),
(operators.NWFastPreview.bl_idname, 'TWO', 'PRESS', False, False, False,
(('viewer_index', 2), ('update_map', False)), "Fast Preview"),
(operators.NWFastPreview.bl_idname, 'TWO', 'PRESS', True, False, False,
(('viewer_index', 2), ('update_map', True)), "Fast Preview"),
(operators.NWFastPreview.bl_idname, 'THREE', 'PRESS', False, False, False,
(('viewer_index', 3), ('update_map', False)), "Fast Preview"),
(operators.NWFastPreview.bl_idname, 'THREE', 'PRESS', True, False, False,
(('viewer_index', 3), ('update_map', True)), "Fast Preview"),
(operators.NWFastPreview.bl_idname, 'FOUR', 'PRESS', False, False, False,
(('viewer_index', 4), ('update_map', False)), "Fast Preview"),
(operators.NWFastPreview.bl_idname, 'FOUR', 'PRESS', True, False, False,
(('viewer_index', 4), ('update_map', True)), "Fast Preview"),
(operators.NWFastPreview.bl_idname, 'FIVE', 'PRESS', False, False, False,
(('viewer_index', 5), ('update_map', False)), "Fast Preview"),
(operators.NWFastPreview.bl_idname, 'FIVE', 'PRESS', True, False, False,
(('viewer_index', 5), ('update_map', True)), "Fast Preview"),
# Reload Images
(operators.NWReloadImages.bl_idname, 'R', 'PRESS', False, False, True, None, "Reload images"),
# Lazy Mix
@ -347,6 +376,8 @@ kmi_defs = (
# Lazy Connect with Menu
(operators.NWLazyConnect.bl_idname, 'RIGHTMOUSE', 'PRESS', False,
True, True, (('with_menu', True),), "Lazy Connect with Socket Menu"),
# Viewer Tile Center
(operators.NWViewerFocus.bl_idname, 'LEFTMOUSE', 'DOUBLE_CLICK', False, False, False, None, "Set Viewers Tile Center"),
# Align Nodes
(operators.NWAlignNodes.bl_idname, 'EQUAL', 'PRESS', False, True,
False, None, "Align selected nodes neatly in a row/column"),