Skip to content

Commit

Permalink
Fixed layout issues with Qt and tweaked a bunch more stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
Sean Leavey committed Dec 26, 2014
1 parent 8a00eee commit f21bfc2
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 133 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.pyc
*.*~
87 changes: 49 additions & 38 deletions Optivis/Gui/CanvasObjects.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,20 @@ def draw(self, *args, **kwargs):
class CanvasComponent(CanvasObject):
__metaclass__ = abc.ABCMeta

def __init__(self, component, size, azimuth=0, position=None):
def __init__(self, component, azimuth=0, position=None):
if not isinstance(component, Optivis.BenchObjects.Component):
raise Exception('Specified component is not of type Optivis.BenchObjects.Component')

if position is None:
# No position defined, so create a default one.
position = Optivis.Coordinates(0, 0)

self.component = component
self.size = size
self.azimuth = azimuth
self.position = position

super(CanvasComponent, self).__init__()

@property
def size(self):
return self.__size

@size.setter
def size(self, size):
self.__size = size

@property
def position(self):
return self.__position
Expand Down Expand Up @@ -97,35 +89,47 @@ class QtCanvasComponent(CanvasComponent):
def __init__(self, *args, **kwargs):
super(QtCanvasComponent, self).__init__(*args, **kwargs)

def draw(self, scene):
def draw(self, scene):
# Create full system path from filename and SVG directory.
path = os.path.join(self.component.svgDir, self.component.filename)

# Create graphical representation of SVG image at path.
svgItem = PyQt4.QtSvg.QGraphicsSvgItem(path)
svgItem.setPos(self.position.x + self.component.size.x / 2, self.position.y + self.component.size.y / 2)
#svgItem.setPos(self.position.x, self.position.y)
svgItem.setTransformOriginPoint(self.component.size.x / 2, self.component.size.y / 2)

transform = PyQt4.QtGui.QTransform()
transform.rotate(self.azimuth)
# Set position of top-left corner.
# self.position.{x, y} are relative to the centre of the component, so we need to compensate for this.
svgItem.setPos(self.position.x - self.component.size.x / 2, self.position.y - self.component.size.y / 2)

# rotate about the centre
svgItem.setTransform(transform)
# Rotate clockwise.
# Qt rotates with respect to the component's origin, i.e. top left, so to rotate around the centre we need to translate it before and after rotating it.
svgItem.translate(self.component.size.x / 2, self.component.size.y / 2)
svgItem.rotate(self.azimuth)
svgItem.translate(-self.component.size.x / 2, -self.component.size.y / 2)

scene.addItem(svgItem)

class CanvasLink(CanvasObject):
__metaclass__ = abc.ABCMeta

def __init__(self, link, start, end, startMarker=True, endMarker=True, startMarkerRadius=3, endMarkerRadius=2, startMarkerOutline="red", endMarkerOutline="blue"):
def __init__(self, link, start, end, startMarker=True, endMarker=True, startMarkerRadius=3, endMarkerRadius=2, startMarkerColor="red", endMarkerColor="blue"):

if start is None:
# No start position defined, so create a default one.
start = Optivis.Coordinates(0, 0)

if end is None:
# No end position defined, so create a default one.
end = Optivis.Coordinates(0, 0)

self.link = link
self.start = start
self.end = end
self.startMarker = startMarker
self.endMarker = endMarker
self.startMarkerRadius = startMarkerRadius
self.endMarkerRadius = endMarkerRadius
self.startMarkerOutline = startMarkerOutline
self.endMarkerOutline = endMarkerOutline
self.startMarkerColor = startMarkerColor
self.endMarkerColor = endMarkerColor

super(CanvasLink, self).__init__()

Expand Down Expand Up @@ -203,22 +207,22 @@ def endMarkerRadius(self, endMarkerRadius):
self.__endMarkerRadius = endMarkerRadius

@property
def startMarkerOutline(self):
return self.__startMarkerOutline
def startMarkerColor(self):
return self.__startMarkerColor

@startMarkerOutline.setter
def startMarkerOutline(self, startMarkerOutline):
self.__startMarkerOutline = startMarkerOutline
@startMarkerColor.setter
def startMarkerColor(self, startMarkerColor):
self.__startMarkerColor = startMarkerColor

@property
def endMarkerOutline(self):
return self.__endMarkerOutline
def endMarkerColor(self):
return self.__endMarkerColor

@endMarkerOutline.setter
def endMarkerOutline(self, endMarkerOutline):
self.__endMarkerOutline = endMarkerOutline
@endMarkerColor.setter
def endMarkerColor(self, endMarkerColor):
self.__endMarkerColor = endMarkerColor

class QtCanvasLink(CanvasLink):
class QtCanvasLink(CanvasLink):
def __init__(self, *args, **kwargs):
super(QtCanvasLink, self).__init__(*args, **kwargs)

Expand All @@ -227,13 +231,20 @@ def draw(self, scene):
line = PyQt4.QtGui.QGraphicsLineItem(self.start.x, self.start.y, self.end.x, self.end.y)
line.setPen(pen)

# add line to graphics scene
scene.addItem(line)

# add markers if necessary
#if self.startMarker:
#painter.setPen(PyQt4.QtGui.QPen(PyQt4.QtCore.Qt.red, 1, PyQt4.QtCore.Qt.SolidLine))
#painter.drawEllipse(int(self.start.x - self.startMarkerRadius), int(self.start.y - self.startMarkerRadius), int(self.start.x + self.startMarkerRadius), int(self.start.y + self.startMarkerRadius))
if self.startMarker:
circle = PyQt4.QtGui.QGraphicsEllipseItem(self.start.x - self.startMarkerRadius, self.start.y - self.startMarkerRadius, self.startMarkerRadius * 2, self.startMarkerRadius * 2)
pen = PyQt4.QtGui.QPen(self.startMarkerColor, 1, PyQt4.QtCore.Qt.SolidLine)
circle.setPen(pen)

scene.addItem(circle)

if self.endMarker:
circle = PyQt4.QtGui.QGraphicsEllipseItem(self.end.x - self.endMarkerRadius, self.end.y - self.endMarkerRadius, self.endMarkerRadius * 2, self.endMarkerRadius * 2)
pen = PyQt4.QtGui.QPen(self.endMarkerColor, 1, PyQt4.QtCore.Qt.SolidLine)
circle.setPen(pen)

#if self.endMarker:
#painter.setPen(PyQt4.QtGui.QPen(PyQt4.QtCore.Qt.blue, 2, PyQt4.QtCore.Qt.SolidLine))
#painter.drawEllipse(int(self.end.x - self.endMarkerRadius), int(self.end.y - self.endMarkerRadius), int(self.end.x + self.endMarkerRadius), int(self.end.y + self.endMarkerRadius))
scene.addItem(circle)
66 changes: 30 additions & 36 deletions Optivis/Gui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,26 @@
import PyQt4.QtGui

import Optivis
from Optivis.BenchObjects import *
from CanvasObjects import *
from Optivis.Nodes import *
import Optivis.Layout
import CanvasObjects

class AbstractGui(object):
__metaclass__ = abc.ABCMeta

def __init__(self, bench, size=None, azimuth=0, zoom=1.0, startMarker=False, endMarker=False, startMarkerRadius=4, endMarkerRadius=2, startMarkerOutline="red", endMarkerOutline="blue"):
def __init__(self, bench, size=None, azimuth=0, zoom=1.0, startMarker=False, endMarker=False, startMarkerRadius=5, endMarkerRadius=3, startMarkerColor=None, endMarkerColor=None):
if not isinstance(bench, Optivis.Bench):
raise Exception('Specified bench is not of type Optivis.Bench')

title = "Optivis - {0}".format(bench.title)

if size is None:
size = Optivis.Coordinates(500, 500)

if startMarkerColor is None:
startMarkerColor = PyQt4.QtCore.Qt.red

if endMarkerColor is None:
endMarkerColor = PyQt4.QtCore.Qt.blue

self.bench = bench
self.size = size
Expand All @@ -34,8 +38,8 @@ def __init__(self, bench, size=None, azimuth=0, zoom=1.0, startMarker=False, end
self.endMarker = endMarker
self.startMarkerRadius = startMarkerRadius
self.endMarkerRadius = endMarkerRadius
self.startMarkerOutline = startMarkerOutline
self.endMarkerOutline = endMarkerOutline
self.startMarkerColor = startMarkerColor
self.endMarkerColor = endMarkerColor

return

Expand Down Expand Up @@ -111,20 +115,20 @@ def endMarkerRadius(self, endMarkerRadius):
self.__endMarkerRadius = endMarkerRadius

@property
def startMarkerOutline(self):
return self.__startMarkerOutline
def startMarkerColor(self):
return self.__startMarkerColor

@startMarkerOutline.setter
def startMarkerOutline(self, startMarkerOutline):
self.__startMarkerOutline = startMarkerOutline
@startMarkerColor.setter
def startMarkerColor(self, startMarkerColor):
self.__startMarkerColor = startMarkerColor

@property
def endMarkerOutline(self):
return self.__endMarkerOutline
def endMarkerColor(self):
return self.__endMarkerColor

@endMarkerOutline.setter
def endMarkerOutline(self, endMarkerOutline):
self.__endMarkerOutline = endMarkerOutline
@endMarkerColor.setter
def endMarkerColor(self, endMarkerColor):
self.__endMarkerColor = endMarkerColor

class Qt(AbstractGui):
application = None
Expand All @@ -149,18 +153,9 @@ def initialise(self):
self.view.resize(self.size.x, self.size.y)
self.view.scale(self.zoom, self.zoom)

# set title
#self.master.title(self.title)

# make root menu
#menuBar = Tkinter.Menu(self.master)

# make and add file menu
#fileMenu = Tkinter.Menu(menuBar, tearoff=0)
#fileMenu.add_command(label="Exit", command=self.quit)
#menuBar.add_cascade(label="File", menu=fileMenu)
# set window title
self.view.setWindowTitle(self.title)

#self.master.config(menu=menuBar)
return

def quit(self):
Expand All @@ -172,25 +167,23 @@ def createCanvasObjectLists(self):
canvasLinks = []

for component in self.bench.components:
size = component.size * self.zoom

# add component to list of canvas components
# azimuth of component is set to global azimuth - but in reality all but the first component will have its azimuth overridden based
# on input/output node alignment
canvasComponents.append(QtCanvasComponent(component=component, size=size, azimuth=self.azimuth, position=self.size / 2))
# Add component to list of canvas components.
# All but the first component's azimuth will be overridden by the layout manager.
canvasComponents.append(CanvasObjects.QtCanvasComponent(component=component, azimuth=self.azimuth, position=None))

for link in self.bench.links:
canvasLinks.append(QtCanvasLink(link=link, start=Optivis.Coordinates(0, 0), end=Optivis.Coordinates(0, 0), startMarker=self.startMarker, endMarker=self.endMarker, startMarkerRadius=self.startMarkerRadius, endMarkerRadius=self.endMarkerRadius, startMarkerOutline=self.startMarkerOutline, endMarkerOutline=self.endMarkerOutline))
# Add link to list of canvas links.
canvasLinks.append(CanvasObjects.QtCanvasLink(link=link, start=None, end=None, startMarker=self.startMarker, endMarker=self.endMarker, startMarkerRadius=self.startMarkerRadius, endMarkerRadius=self.endMarkerRadius, startMarkerColor=self.startMarkerColor, endMarkerColor=self.endMarkerColor))

return (canvasComponents, canvasLinks)

def show(self):
# get bench objects as separate lists of components and links
(canvasComponents, canvasLinks) = self.createCanvasObjectLists()

# instantiate layout manager and arrange objects
layout = Optivis.Layout.SimpleLayout(self, canvasComponents, canvasLinks)

layout.arrange()
layout.centre()

# draw objects
for canvasLink in canvasLinks:
Expand All @@ -199,6 +192,7 @@ def show(self):
for canvasComponent in canvasComponents:
canvasComponent.draw(self.scene)

# show on screen
self.view.show()

sys.exit(self.application.exec_())
49 changes: 9 additions & 40 deletions Optivis/Layout/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import abc

import Optivis
import Optivis.BenchObjects
import Optivis.Gui

class AbstractLayout(object):
Expand All @@ -18,8 +18,8 @@ def arrange(self):
return

def getCanvasComponent(self, component):
if not isinstance(component, Optivis.Component):
raise Exception('Specified component is not of type Component')
if not isinstance(component, Optivis.BenchObjects.Component):
raise Exception('Specified component is not of type Optivis.BenchObjects.Component')

for thisCanvasComponent in self.canvasComponents:
if thisCanvasComponent.component == component:
Expand All @@ -28,8 +28,8 @@ def getCanvasComponent(self, component):
raise Exception('Cannot find specified canvas component in list!')

def getCanvasLink(self, link):
if not isinstance(link, Optivis.Link):
raise Exception('Specified link is not of type Link')
if not isinstance(link, Optivis.BenchObjects.Link):
raise Exception('Specified link is not of type Optivis.BenchObjects.Link')

for thisCanvasLink in self.canvasLinks:
if thisCanvasLink.link == link:
Expand Down Expand Up @@ -86,16 +86,16 @@ def arrange(self):
inputAzimuth = outputAzimuth

# node positions relative to components' centers
outputNodeRelativePosition = link.outputNode.position * canvasComponent1.size
inputNodeRelativePosition = link.inputNode.position * canvasComponent2.size
outputNodeRelativePosition = link.outputNode.position * canvasComponent1.component.size
inputNodeRelativePosition = link.inputNode.position * canvasComponent2.component.size

# coordinates of output node for rotated component
outputNodeRelativeRotatedPosition = outputNodeRelativePosition.rotate(canvasComponent1.azimuth)

# combined output node and component position
outputNodeAbsolutePosition = canvasComponent1.position.translate(outputNodeRelativeRotatedPosition)

# create link end position (unrotated)
# create link end position
linkEndPosition = Optivis.Coordinates(link.length, 0).rotate(outputAzimuth)

# coordinates of input node for rotated component input node
Expand Down Expand Up @@ -136,35 +136,4 @@ def arrange(self):

# add components to list of components
# FIXME: don't add same component twice
linkedComponents.append(link.inputNode.component)

def centre(self):
# min and max positions
minPos = Optivis.Coordinates(float('inf'), float('inf'))
maxPos = Optivis.Coordinates(float('-inf'), float('-inf'))

for canvasComponent in self.canvasComponents:
(thisMinPos, thisMaxPos) = canvasComponent.getBoundingBox()

if thisMinPos.x < minPos.x: minPos.x = thisMinPos.x
if thisMinPos.y < minPos.y: minPos.y = thisMinPos.y

if thisMaxPos.x > maxPos.x: maxPos.x = thisMaxPos.x
if thisMaxPos.y > maxPos.y: maxPos.y = thisMaxPos.y

# work out size from min and max
size = maxPos - minPos

# centre coordinates of group
groupCentre = maxPos - size / 2

# correction factor to middle of screen
correction = self.gui.size / 2 - groupCentre

# loop over all objects, applying a translation
for canvasComponent in self.canvasComponents:
canvasComponent.position = canvasComponent.position.translate(correction)

for canvasLink in self.canvasLinks:
canvasLink.start = canvasLink.start.translate(correction)
canvasLink.end = canvasLink.end.translate(correction)
linkedComponents.append(link.inputNode.component)
Loading

0 comments on commit f21bfc2

Please sign in to comment.