Skip to content

Commit

Permalink
New while loop. Convex hull stuff moved to own class, to be inherited…
Browse files Browse the repository at this point in the history
… by nodes.
  • Loading branch information
ilgar committed Aug 17, 2019
1 parent 94fc7d9 commit 172569e
Show file tree
Hide file tree
Showing 15 changed files with 376 additions and 128 deletions.
12 changes: 8 additions & 4 deletions PyFlow/Packages/PyFlowBase/Factories/UINodeFactory.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,17 @@
from PyFlow.Packages.PyFlowBase.Nodes.makeAnyDict import makeAnyDict

from PyFlow.Packages.PyFlowBase.Nodes.forLoopBegin import forLoopBegin
from PyFlow.Packages.PyFlowBase.Nodes.whileLoopBegin import whileLoopBegin

from PyFlow.Packages.PyFlowBase.Nodes.imageDisplay import imageDisplay
from PyFlow.Packages.PyFlowBase.UI.UIQimageDisplay import UIQimageDisplay
from PyFlow.Packages.PyFlowBase.UI.UIImageDisplayNode import UIImageDisplayNode

from PyFlow.Packages.PyFlowBase.UI.UISwitchOnStringNode import UISwitchOnString
from PyFlow.Packages.PyFlowBase.UI.UIGetVarNode import UIGetVarNode
from PyFlow.Packages.PyFlowBase.UI.UISetVarNode import UISetVarNode
from PyFlow.Packages.PyFlowBase.UI.UISequenceNode import UISequenceNode
from PyFlow.Packages.PyFlowBase.UI.UICommentNode import UICommentNode
from PyFlow.Packages.PyFlowBase.UI.UIstickyNote import UIstickyNote
from PyFlow.Packages.PyFlowBase.UI.UIStickyNote import UIStickyNote
from PyFlow.Packages.PyFlowBase.UI.UIRerouteNode import UIRerouteNode
from PyFlow.Packages.PyFlowBase.UI.UIRerouteNodeSmall import UIRerouteNodeSmall
from PyFlow.Packages.PyFlowBase.UI.UIPythonNode import UIPythonNode
Expand All @@ -61,6 +62,7 @@
from PyFlow.Packages.PyFlowBase.UI.UIConvertToNode import UIConvertToNode
from PyFlow.Packages.PyFlowBase.UI.UIMakeDictNode import UIMakeDictNode
from PyFlow.Packages.PyFlowBase.UI.UIForLoopBeginNode import UIForLoopBeginNode
from PyFlow.Packages.PyFlowBase.UI.UIWhileLoopBeginNode import UIWhileLoopBeginNode

from PyFlow.UI.Canvas.UINodeBase import UINodeBase

Expand All @@ -77,7 +79,7 @@ def createUINode(raw_instance):
if isinstance(raw_instance, commentNode):
return UICommentNode(raw_instance)
if isinstance(raw_instance, stickyNote):
return UIstickyNote(raw_instance)
return UIStickyNote(raw_instance)
if isinstance(raw_instance, reroute) or isinstance(raw_instance, rerouteExecs):
return UIRerouteNodeSmall(raw_instance)
if isinstance(raw_instance, graphInputs):
Expand All @@ -101,7 +103,9 @@ def createUINode(raw_instance):
if isinstance(raw_instance, colorRamp):
return UIColorRamp(raw_instance)
if isinstance(raw_instance, imageDisplay):
return UIQimageDisplay(raw_instance)
return UIImageDisplayNode(raw_instance)
if isinstance(raw_instance,forLoopBegin):
return UIForLoopBeginNode(raw_instance)
if isinstance(raw_instance,whileLoopBegin):
return UIWhileLoopBeginNode(raw_instance)
return UINodeBase(raw_instance)
6 changes: 3 additions & 3 deletions PyFlow/Packages/PyFlowBase/Nodes/forLoopEnd.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
from PyFlow.Packages.PyFlowBase.Nodes import FLOW_CONTROL_COLOR


class forLoopEnd(NodeBase):
class loopEnd(NodeBase):
def __init__(self, name):
super(forLoopEnd, self).__init__(name)
super(loopEnd, self).__init__(name)
self.inExec = self.createInputPin(DEFAULT_IN_EXEC_NAME, 'ExecPin', None, self.compute)
self.loopBeginNode = self.createInputPin('Paired block', 'StringPin')
self.loopBeginNode.setInputWidgetVariant("ObjectPathWIdget")
Expand Down Expand Up @@ -62,4 +62,4 @@ def compute(self, *args, **kwargs):
node.setError(err)
self.setError(err)
else:
self.setError("{} not found".format(self.loopBeginNode.getData()))
self.setError("Pair {} not found".format(self.loopBeginNode.getData()))
65 changes: 65 additions & 0 deletions PyFlow/Packages/PyFlowBase/Nodes/loopEnd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
## Copyright 2015-2019 Ilgar Lunin, Pedro Cabrera

## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at

## http://www.apache.org/licenses/LICENSE-2.0

## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.


from PyFlow.Core.Common import *
from PyFlow.Core.PathsRegistry import PathsRegistry
from PyFlow.Core.NodeBase import NodePinsSuggestionsHelper
from PyFlow.Core import NodeBase
from PyFlow.Packages.PyFlowBase.Nodes import FLOW_CONTROL_COLOR


class loopEnd(NodeBase):
def __init__(self, name):
super(loopEnd, self).__init__(name)
self.inExec = self.createInputPin(DEFAULT_IN_EXEC_NAME, 'ExecPin', None, self.compute)
self.loopBeginNode = self.createInputPin('Paired block', 'StringPin')
self.loopBeginNode.setInputWidgetVariant("ObjectPathWIdget")
self.completed = self.createOutputPin('Completed', 'ExecPin')
self.headerColor = FLOW_CONTROL_COLOR

@staticmethod
def pinTypeHints():
helper = NodePinsSuggestionsHelper()
helper.addInputDataType('ExecPin')
helper.addInputDataType('StringPin')
helper.addInputStruct(PinStructure.Single)
return helper

@staticmethod
def category():
return 'FlowControl'

@staticmethod
def keywords():
return ['iter', 'end']

@staticmethod
def description():
return 'For loop end block'

def compute(self, *args, **kwargs):
node = PathsRegistry().getEntity(self.loopBeginNode.getData())
if node is not None:
if node.graph() == self.graph():
if node.loopEndNode.getData() != self.path():
self.setError("Invalid pair")
return
node.onNext()
else:
err = "block ends in different graphs"
node.setError(err)
self.setError(err)
else:
self.setError("Pair {} not found".format(self.loopBeginNode.getData()))
85 changes: 85 additions & 0 deletions PyFlow/Packages/PyFlowBase/Nodes/whileLoopBegin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
## Copyright 2015-2019 Ilgar Lunin, Pedro Cabrera

## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at

## http://www.apache.org/licenses/LICENSE-2.0

## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.


from PyFlow.Core import NodeBase
from PyFlow.Core.PathsRegistry import PathsRegistry
from PyFlow.Core.NodeBase import NodePinsSuggestionsHelper
from PyFlow.Core.Common import *
from PyFlow.Packages.PyFlowBase.Nodes import FLOW_CONTROL_COLOR


class whileLoopBegin(NodeBase):
def __init__(self, name):
super(whileLoopBegin, self).__init__(name)
self.lastCondition = False
self.inExec = self.createInputPin('inExec', 'ExecPin', None, self.compute)
self.condition = self.createInputPin('Condition', 'BoolPin')
self.loopEndNode = self.createInputPin('Paired block', 'StringPin')
self.loopEndNode.setInputWidgetVariant("ObjectPathWIdget")

self.loopBody = self.createOutputPin('LoopBody', 'ExecPin')
self.headerColor = FLOW_CONTROL_COLOR

@staticmethod
def pinTypeHints():
helper = NodePinsSuggestionsHelper()
helper.addInputDataType('ExecPin')
helper.addInputDataType('BoolPin')
helper.addOutputDataType('ExecPin')
helper.addInputStruct(PinStructure.Single)
helper.addOutputStruct(PinStructure.Single)
return helper

@staticmethod
def category():
return 'FlowControl'

@staticmethod
def keywords():
return ['iter']

@staticmethod
def description():
return 'While loop begin block'

def onNext(self, *args, **kwargs):
currentCondition = self.condition.getData()
if currentCondition:
self.loopBody.call(*args, **kwargs)
if self.lastCondition is True and currentCondition is False:
endNodePath = self.loopEndNode.getData()
loopEndNode = PathsRegistry().getEntity(endNodePath)
loopEndNode.completed.call()
self.lastCondition = False
return
self.lastCondition = currentCondition

def compute(self, *args, **kwargs):
endNodePath = self.loopEndNode.getData()
loopEndNode = PathsRegistry().getEntity(endNodePath)
if loopEndNode is not None:
if loopEndNode.loopBeginNode.getData() != self.path():
self.setError("Invalid pair")
return
if self.graph() is not loopEndNode.graph():
err = "block ends in different graphs"
self.setError(err)
loopEndNode.setError(err)
return
else:
self.setError("Pair {} not found".format(endNodePath))
return

self.onNext(*args, **kwargs)
17 changes: 0 additions & 17 deletions PyFlow/Packages/PyFlowBase/UI/UICommentNode.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,23 +242,6 @@ def translate(self, x, y):
super(UICommentNode, self).translate(x, y)

def paint(self, painter, option, widget):
"""CONVEX HULL TEST
path = []
self.poly = None
for i in self.owningNodes:
relPos = self.mapFromScene(i.scenePos())
relSize = QtCore.QPointF(i.getNodeWidth(),i.geometry().height())
path.append((relPos.x(),relPos.y()))
path.append((relPos.x()+relSize.x(),relPos.y()))
path.append((relPos.x()+relSize.x(),relPos.y()+relSize.y()))
path.append((relPos.x(),relPos.y()+relSize.y()))
if len(path) >= 3:
c = convex_hull(path)
self.poly = QtGui.QPolygonF()
for i in c:
self.poly.append(QtCore.QPointF(i[0], i[1]))
"""
NodePainter.asCommentNode(self, painter, option, widget)

def updateColor(self, color):
Expand Down
90 changes: 11 additions & 79 deletions PyFlow/Packages/PyFlowBase/UI/UIForLoopBeginNode.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,53 +12,23 @@
## See the License for the specific language governing permissions and
## limitations under the License.

import uuid
from Qt import QtGui
from Qt import QtCore
from Qt.QtWidgets import *
from PyFlow.Core.Common import *
from PyFlow.Core.NodeBase import NodeBase
from PyFlow.UI.Utils.stylesheet import Colors
from PyFlow.UI.Canvas.Painters import NodePainter
from PyFlow.UI.Canvas.UINodeBase import UINodeBase
from PyFlow.Core.Common import *
from PyFlow.Core.PathsRegistry import PathsRegistry
from Qt import QtGui
from Qt import QtCore
from PyFlow.UI.Utils.ConvexHull import convex_hull
import uuid
from Qt.QtWidgets import *
from PyFlow.UI.Canvas.IConvexHullBackDrop import IConvexHullBackDrop


class backDrop(QGraphicsWidget):
def __init__(self, parent):
super(backDrop, self).__init__()
self.parent = parent
self.rect = QtCore.QRectF()

def boundingRect(self):
try:
return QtCore.QRectF(QtCore.QPointF(self.parent.left - 5, self.parent.top + 5), QtCore.QPointF(self.parent.right + 5, self.parent.down - 5))
except:
return QtCore.QRectF(0, 0, 0, 0)

def paint(self, painter, option, widget):
roundRectPath = QtGui.QPainterPath()
self.parent.computeHull()
if self.parent.poly:
path = QtGui.QPainterPath()
path.addPolygon(self.parent.poly)
color = QtGui.QColor(self.parent.headColorOverride)
color.setAlpha(50)
pen = QtGui.QPen(self.parent.headColorOverride, 0.5)
painter.setPen(pen)
painter.fillPath(path, color)
painter.drawPath(path)


class UIForLoopBeginNode(UINodeBase):
class UIForLoopBeginNode(UINodeBase, IConvexHullBackDrop):
def __init__(self, raw_node):
super(UIForLoopBeginNode, self).__init__(raw_node)
IConvexHullBackDrop.__init__(self)
self.headColorOverride = Colors.Orange
self.poly = None
self.owningLoopBeginNode = self
self.owningNodes = []
self.backDrop = backDrop(self)

def postCreate(self, jsonTemplate=None):
super(UIForLoopBeginNode, self).postCreate(jsonTemplate)
Expand All @@ -67,11 +37,12 @@ def postCreate(self, jsonTemplate=None):
self.backDrop.update()

def eventDropOnCanvas(self):
# TODO: try to simplify this with Canvas.spawnNode
nodeTemplate = NodeBase.jsonTemplate()
nodeTemplate['package'] = "PyFlowBase"
nodeTemplate['lib'] = ""
nodeTemplate['type'] = "forLoopEnd"
nodeTemplate['name'] = self.canvasRef( ).graphManager.getUniqNodeName("forLoopEnd")
nodeTemplate['type'] = "loopEnd"
nodeTemplate['name'] = self.canvasRef().graphManager.getUniqNodeName("loopEnd")
nodeTemplate['x'] = self.scenePos().x() + self.geometry().width() + 30
nodeTemplate['y'] = self.scenePos().y()
nodeTemplate['uuid'] = str(uuid.uuid4())
Expand All @@ -80,45 +51,6 @@ def eventDropOnCanvas(self):
endNode.getPinSG("Paired block").setData(self.path())
self.canvasRef().connectPins(self.getPinSG("LoopBody"), endNode.getPinSG(DEFAULT_IN_EXEC_NAME))

def computeHull(self):
loopEndNode = PathsRegistry().getEntity(self.getPinSG("Paired block").getData())
if loopEndNode is None:
self.poly = QtGui.QPolygonF()
return
p = [self]
if loopEndNode.__class__.__name__ == "forLoopEnd" and loopEndNode.getWrapper() is not None:
p.append(loopEndNode.getWrapper())
else:
self.poly = QtGui.QPolygonF()
return

p += self.getBetwenLoopNodes(self)

path = []
self.left = 0
self.top = 0
self.right = 0
self.down = 0
for i in p:
relPos = i.scenePos()
self.left = min(self.left, relPos.x())
self.top = max(self.top, relPos.y())
self.right = max(self.right, relPos.x())
self.down = min(self.down, relPos.y())
relSize = QtCore.QPointF(i.getNodeWidth(), i.geometry().height())
path.append((relPos.x() - 5, relPos.y() - 5))
path.append((relPos.x() + relSize.x() + 5, relPos.y() - 5))
path.append((relPos.x() + relSize.x() + 5, relPos.y() + relSize.y() + 5))
path.append((relPos.x() - 5, relPos.y() + relSize.y() + 5))

if len(path) >= 3:
self.convex_hull = convex_hull(path)
self.poly = QtGui.QPolygonF()
for i in self.convex_hull:
self.poly.append(QtCore.QPointF(i[0], i[1]))
self.poly.append(QtCore.QPointF(
self.convex_hull[0][0], self.convex_hull[0][1]))

def paint(self, painter, option, widget):
self.computeHull()
self.backDrop.update()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
from Qt.QtWidgets import QLabel


class UIQimageDisplay(UINodeBase):
class UIImageDisplayNode(UINodeBase):
def __init__(self, raw_node):
super(UIQimageDisplay, self).__init__(raw_node)
super(UIImageDisplayNode, self).__init__(raw_node)
self.resizable = True
self.Imagelabel = QLabel("test3")
self.pixmap = QtGui.QPixmap(RESOURCES_DIR + "/wizard-cat.png")
Expand All @@ -35,7 +35,7 @@ def onLoadImage(self, imagePath):

def paint(self, painter, option, widget):
self.updateSize()
super(UIQimageDisplay, self).paint(painter, option, widget)
super(UIImageDisplayNode, self).paint(painter, option, widget)

def updateSize(self):
scaledPixmap = self.pixmap.scaledToWidth(
Expand Down
Loading

0 comments on commit 172569e

Please sign in to comment.