'''
ScissorTool v1.0 by Jorrit Schulte
Add this to menu.py:
import ScissorTool
'''
try:
from PySide.QtGui import *
from PySide.QtCore import *
except ImportError:
from PySide2.QtWidgets import *
from PySide2.QtCore import *
from PySide2.QtGui import *
import nuke, threading, platform, time
from pyautogui import click
shortcut = 'z'
#switch that keeps the ui from reopening
canOpen = True
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def ccw(A,B,C):
return (C.y-A.y)*(B.x-A.x) > (B.y-A.y)*(C.x-A.x)
def intersect(A,B,C,D):
return ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D)
def DAGMousePos():
click()
for node in nuke.selectedNodes():
node.setSelected(False)
offset = nuke.toNode('preferences')['dot_node_scale'].value()*6
dot = nuke.createNode("Dot", inpanel=False)
coord = Point(dot.xpos()+offset, dot.ypos()+offset)
nuke.delete(dot)
return coord
class Panel(QWidget):
finished = Signal()
def __init__(self):
super(Panel, self).__init__()
#find active screen
screen = QApplication.desktop().screenNumber(QApplication.desktop().cursor().pos())
screenSize = QDesktopWidget().screenGeometry(screen)
self.screenPos = QDesktopWidget().screenGeometry(screen).topLeft()
#set window size
self.resize(screenSize.width(),screenSize.height())
self.move(self.screenPos.x(), self.screenPos.y())
#make window transparent
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.setAttribute(Qt.WA_NoSystemBackground)
self.setAttribute(Qt.WA_TranslucentBackground)
if platform.system() not in ['Darwin','Windows'] and nuke.NUKE_VERSION_MAJOR < 11:
self.setAttribute(Qt.WA_PaintOnScreen)
#initialise cursor position
self.start = QCursor().pos() - self.screenPos
self.mouse_position = self.start
#set timer for cursor polling
self.timer = QTimer(self)
self.timer.timeout.connect(self.pollCursor)
self.timer.start()
#install focus deactivation
self.installEventFilter(self)
#find initial DAG position, then open UI
self.finished.connect(self.show)
thread = threading.Thread(target=self.run)
thread.daemon = True
thread.start()
def run(self):
global parent
#sleep a tiny amount to let the group context kick in
time.sleep(0.001)
with parent:
self.a = DAGMousePos()
self.finished.emit()
#keeps the ui from reopening
def keyPressEvent(self,event):
if event.isAutoRepeat():
return
def keyReleaseEvent(self,event):
if event.isAutoRepeat():
return
if event.text() == shortcut:
self.closeWidget()
return
#focus deactivation
def eventFilter(self, object, event):
if event.type() in [QEvent.WindowDeactivate, QEvent.FocusOut] and not canOpen:
self.closeWidget()
return True
return False
#polling of the cursor
def pollCursor(self):
self.mouse_position = QCursor().pos() - self.screenPos
self.update()
#create the line
def paintEvent(self, QPaintEvent):
super(Panel, self).paintEvent(QPaintEvent)
painter = QPainter(self)
pen = QPen(QColor(200,0,0))
pen.setWidth(2)
pen.setStyle(Qt.DotLine)
painter.setPen(pen)
painter.setRenderHint(QPainter.Antialiasing)
line = QLine(self.start, self.mouse_position)
painter.drawLine(line)
def cut(self):
global parent
with parent:
undo = nuke.Undo()
undo.begin("Scissor Tool")
#define starting point and get end point scissor line
a = self.a
b = DAGMousePos()
#find all connections
for nodeA in nuke.allNodes():
connections = nodeA.dependencies(nuke.INPUTS)
if len(connections) > 0:
c = Point(nodeA.xpos()+(nodeA.screenWidth()/2),nodeA.ypos()+(nodeA.screenHeight()/2))
for nodeB in connections:
d = Point(nodeB.xpos()+(nodeB.screenWidth()/2),nodeB.ypos()+(nodeB.screenHeight()/2))
#check for intersection with scissor line
if intersect(a,b,c,d):
for i in range(nodeA.inputs()):
#disconnect if current input is connected to other node
if nodeA.input(i) is nodeB:
nodeA.setInput(i, None)
undo.end()
def closeWidget(self):
global canOpen
canOpen = True
#stop the polling timer
self.timer.stop()
#close widget
self.close()
#run intersect code
thread = threading.Thread(target=self.cut)
thread.daemon = True
thread.start()
return
def run():
global canOpen
if canOpen:
#create dot to find group context
contextDot = nuke.createNode("Dot", inpanel=False)
fnn = contextDot.fullName().split('.')
groupName = 'root.'
for i in range(len(fnn)-1):
groupName += fnn[i] + '.'
#get parent
global parent
if groupName != 'root.':
parent = nuke.toNode(groupName[:-1])
else:
parent = nuke.root()
#initialize panel
run.panel = Panel()
#turns off canOpen so the ui doesnt reopen
canOpen = False
#delete dot again
nuke.delete(contextDot)
menubar = nuke.menu('Nuke')
menubar.addCommand('@;Scissor tool', run , shortcut)