summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsumit2020-05-28 15:31:26 +0530
committersumit2020-05-28 15:31:26 +0530
commit6ef014e0aa5d320f2c392c5e784b4eeba373aebf (patch)
tree8ac6aa2448715216adcce11e0ed6ee219bdadd6a
parent70a89b9ddca1e0abc9f802b9cda1d483dd59a4e1 (diff)
parentac63205a7d02185f4a917db74bf0964691bf20ea (diff)
downloadChemical-PFD-6ef014e0aa5d320f2c392c5e784b4eeba373aebf.tar.gz
Chemical-PFD-6ef014e0aa5d320f2c392c5e784b4eeba373aebf.tar.bz2
Chemical-PFD-6ef014e0aa5d320f2c392c5e784b4eeba373aebf.zip
Merge remote-tracking branch 'upstream/master'
-rw-r--r--.gitignore2
-rw-r--r--src/main/python/main.py24
-rw-r--r--src/main/python/shapes/__init__.py6
-rw-r--r--src/main/python/utils/app.py10
-rw-r--r--src/main/python/utils/data.py321
-rw-r--r--src/main/python/utils/dialogs.py4
-rw-r--r--src/main/python/utils/fileWindow.py6
-rw-r--r--src/main/python/utils/funcs.py5
-rw-r--r--src/main/python/utils/graphics.py48
-rw-r--r--src/main/python/utils/toolbar.py35
-rw-r--r--src/main/python/utils/undo.py61
-rw-r--r--src/main/resources/base/config/items.json902
-rw-r--r--src/main/resources/base/config/paperSizes.json32
-rw-r--r--src/main/resources/base/svg/ellipse.svg8
14 files changed, 1087 insertions, 377 deletions
diff --git a/.gitignore b/.gitignore
index 7ac10bd..8ad00c3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,4 @@ src/main/python/experimental/*
*.pfd
.vscode
.vscode/*.json
-.idea/
+src/main/resources/base/toolbar/*.png
diff --git a/src/main/python/main.py b/src/main/python/main.py
index db34119..3ebb2b9 100644
--- a/src/main/python/main.py
+++ b/src/main/python/main.py
@@ -13,6 +13,7 @@ from utils.fileWindow import fileWindow
from utils.data import ppiList, sheetDimensionList
from utils import dialogs
from utils.toolbar import toolbar
+from utils.app import app
import shapes
@@ -34,8 +35,10 @@ class appWindow(QMainWindow):
self.menuFile.addAction("Save", self.saveProject)
self.menuEdit = titleMenu.addMenu('Edit')
- self.undo = self.menuEdit.addAction("Undo")
- self.redo = self.menuEdit.addAction("Redo")
+ self.undo = self.menuEdit.addAction("Undo", lambda x=self: x.activeScene.painter.undoAction.trigger())
+ self.redo = self.menuEdit.addAction("Redo", lambda x=self: x.activeScene.painter.redoAction.trigger())
+
+ self.menuEdit.addAction("Show Undo Stack", lambda x=self: x.activeScene.painter.createUndoView(self) )
self.menuGenerate = titleMenu.addMenu('Generate') #Generate menu
self.menuGenerate.addAction("Image", self.saveImage)
@@ -54,14 +57,14 @@ class appWindow(QMainWindow):
self.mdi.setDocumentMode(False)
#declare main window layout
- # self.mainWidget.setLayout(mainLayout)
self.setCentralWidget(self.mdi)
self.resize(1280, 720) #set collapse dim
self.mdi.subWindowActivated.connect(self.tabSwitched)
def updateMenuBar(self):
- self.undo.setAction(self.activeScene.painter.undoAction)
- self.redo.setAction(self.activeScene.painter.redoAction)
+ # used to update menu bar undo-redo buttons to current scene
+ self.undo.triggered.connect(self.activeScene.painter.undoAction.trigger())
+ self.redo.triggered.connect(self.activeScene.painter.redoAction.trigger())
def createToolbar(self):
#place holder for toolbar with fixed width, layout may change
@@ -75,10 +78,11 @@ class appWindow(QMainWindow):
def toolButtonClicked(self, object):
currentDiagram = self.mdi.currentSubWindow().tabber.currentWidget().painter
if currentDiagram:
- graphic = getattr(shapes, object['object'])(*object['args'])
- graphic.setPen(QPen(Qt.black, 2))
- graphic.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable)
+ graphic = getattr(shapes, object['object'])(*map(lambda x: int(x) if x.isdigit() else x, object['args']))
+ # graphic.setPen(QPen(Qt.black, 2))
+ # graphic.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable)
currentDiagram.addItemPlus(graphic)
+ graphic.setPos(20, 20)
def newProject(self):
#call to create a new file inside mdi area
@@ -93,7 +97,6 @@ class appWindow(QMainWindow):
if self.count > 1: #switch to tab view if needed
self.mdi.setViewMode(QMdiArea.TabbedView)
project.show()
- project.tabber.currentWidget().painter.createUndoView(self)
def openProject(self):
#show the open file dialog to open a saved file, then unpickle it.
@@ -203,8 +206,7 @@ class appWindow(QMainWindow):
#donot delete, to manage undo redo
-if __name__ == '__main__':
- app = ApplicationContext() # 1. Instantiate ApplicationContext
+if __name__ == '__main__': # 1. Instantiate ApplicationContext
main = appWindow()
main.show()
exit_code = app.app.exec_() # 2. Invoke appctxt.app.exec_()
diff --git a/src/main/python/shapes/__init__.py b/src/main/python/shapes/__init__.py
index a5a98f2..af92a6a 100644
--- a/src/main/python/shapes/__init__.py
+++ b/src/main/python/shapes/__init__.py
@@ -1,2 +1,4 @@
-from . import *
-from PyQt5.QtWidgets import * \ No newline at end of file
+from .shapes import *
+# from .line import *
+from PyQt5.QtWidgets import *
+dir() \ No newline at end of file
diff --git a/src/main/python/utils/app.py b/src/main/python/utils/app.py
new file mode 100644
index 0000000..4540a43
--- /dev/null
+++ b/src/main/python/utils/app.py
@@ -0,0 +1,10 @@
+"""
+Declare fbs application so that it can be imported in other modules.
+"""
+
+from fbs_runtime.application_context.PyQt5 import ApplicationContext
+app = ApplicationContext()
+
+def fileImporter(file):
+ # Helper function to fetch files from src/main/resources
+ return app.get_resource(file)
diff --git a/src/main/python/utils/data.py b/src/main/python/utils/data.py
index 593cb1b..2053ff4 100644
--- a/src/main/python/utils/data.py
+++ b/src/main/python/utils/data.py
@@ -1,311 +1,18 @@
-paperSizes = {
- "A0": {
- "72": [2384, 3370],
- "96": [3179, 4494],
- "150": [4967, 7022],
- "300": [9933, 14043]
- },
- "A1": {
- "72": [1684, 2384],
- "96": [2245, 3179],
- "150": [3508, 4967],
- "300": [7016, 9933]
- },
- "A2": {
- "72": [1191, 1684],
- "96": [1587, 2245],
- "150": [2480, 3508],
- "300": [4960, 7016]
- },
- "A3": {
- "72": [842, 1191],
- "96": [1123, 1587],
- "150": [1754, 2480],
- "300": [3508, 4960]
- },
- "A4": {
- "72": [595, 842],
- "96": [794, 1123],
- "150": [1240, 1754],
- "300": [2480, 3508]
- }
-}
+"""
+Imports data from json configs, so that they can be imported from this module.
+"""
-sheetDimensionList = [f'A{i}' for i in range(5)]
+from json import load
+from .app import fileImporter
-ppiList = ["72", "96", "150", "300"]
+paperSizes = load(open(fileImporter("config/paperSizes.json")))
+
+sheetDimensionList = list(paperSizes.keys())
+
+ppiList = list(paperSizes[sheetDimensionList[0]].keys())
+
+toolbarItems = load(open(fileImporter("config/items.json")))
+
+defaultToolbarItems = toolbarItems.keys()
-toolbarItems = {
- 'Ellipse': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse2': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse3': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse4': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse5': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse6': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse7': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse8': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse9': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse11': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse12': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse13': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse14': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse15': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse16': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse17': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse18': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse19': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse20': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse21': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse22': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse23': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse24': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse25': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse26': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse27': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse28': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse29': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse30': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse31': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse32': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse33': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse34': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse35': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse36': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse37': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse38': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse39': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse40': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse41': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse42': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse43': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse44': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse45': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
- 'Ellipse46': {
- 'name': 'Ellipse',
- 'icon': 'ellipse.png',
- 'object': 'QGraphicsEllipseItem',
- 'args': [20, 20, 300, 300]
- },
-}
-defaultToolbarItems = toolbarItems.keys() \ No newline at end of file
diff --git a/src/main/python/utils/dialogs.py b/src/main/python/utils/dialogs.py
index 3791599..fa3b5f1 100644
--- a/src/main/python/utils/dialogs.py
+++ b/src/main/python/utils/dialogs.py
@@ -1,4 +1,4 @@
-from PyQt5.QtWidgets import QDialog, QPushButton, QFormLayout, QComboBox, QLabel, QMessageBox, QDialogButtonBox
+from PyQt5.QtWidgets import QDialog, QPushButton, QFormLayout, QComboBox, QLabel, QMessageBox, QDialogButtonBox, QHBoxLayout
from .data import sheetDimensionList, ppiList
class paperDims(QDialog):
@@ -104,7 +104,7 @@ def saveEvent(parent = None):
def showUndoDialog(undoView, parent):
dialogBox = QDialog(parent)
dialogBox.resize(400, 400)
- layout = QFormLayout(dialogBox)
+ layout = QHBoxLayout(dialogBox)
layout.addWidget(undoView)
dialogBox.setWindowTitle("Undo Stack")
dialogBox.show() \ No newline at end of file
diff --git a/src/main/python/utils/fileWindow.py b/src/main/python/utils/fileWindow.py
index 8f2fd32..ebe509b 100644
--- a/src/main/python/utils/fileWindow.py
+++ b/src/main/python/utils/fileWindow.py
@@ -10,6 +10,7 @@ from . import dialogs
from .graphics import customView
from .canvas import canvas
from .tabs import customTabWidget
+from .undo import resizeCommand
class fileWindow(QMdiSubWindow):
@@ -125,10 +126,7 @@ class fileWindow(QMdiSubWindow):
currentTab = self.tabber.currentWidget()
result = dialogs.paperDims(self, currentTab._canvasSize, currentTab._ppi, currentTab.objectName()).exec_()
if result is not None:
- currentTab.canvasSize, currentTab.ppi = result
- return self.resizeHandler()
- else:
- return None
+ currentTab.painter.undoStack.push(resizeCommand(result, currentTab, self))
def sideViewToggle(self):
#Function checks if current side view tab is set, and toggles view as required
diff --git a/src/main/python/utils/funcs.py b/src/main/python/utils/funcs.py
deleted file mode 100644
index 7796ece..0000000
--- a/src/main/python/utils/funcs.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from itertools import zip_longest
-
-def grouper(n, iterable, fillvalue=None):
- args = [iter(iterable)] * n
- return zip_longest(fillvalue=fillvalue, *args) \ No newline at end of file
diff --git a/src/main/python/utils/graphics.py b/src/main/python/utils/graphics.py
index 62c62f7..a997a30 100644
--- a/src/main/python/utils/graphics.py
+++ b/src/main/python/utils/graphics.py
@@ -20,6 +20,7 @@ class customView(QGraphicsView):
self.setDragMode(True) #sets pannable using mouse
self.setAcceptDrops(True) #sets ability to accept drops
if scene:
+ #create necessary undo redo actions to accept keyboard shortcuts
self.addAction(scene.undoAction)
self.addAction(scene.redoAction)
self.addAction(scene.deleteAction)
@@ -43,10 +44,12 @@ class customView(QGraphicsView):
#defines item drop, fetches text, creates corresponding QGraphicItem and adds it to scene
if QDropEvent.mimeData().hasText():
#QDropEvent.mimeData().text() defines intended drop item, the pos values define position
- graphic = getattr(shapes, QDropEvent.mimeData().text())(QDropEvent.pos().x()-150, QDropEvent.pos().y()-150, 300, 300)
- graphic.setPen(QPen(Qt.black, 2))
- graphic.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable)
- self.scene().addItemPlus(graphic)
+ obj = QDropEvent.mimeData().text().split('/')
+ graphic = getattr(shapes, obj[0])(*map(lambda x: int(x) if x.isdigit() else x, obj[1:]))
+ # graphic.setPen(QPen(Qt.black, 2))
+ # graphic.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable)
+ self.scene().addItemPlus(graphic)
+ graphic.setPos(QDropEvent.pos().x(), QDropEvent.pos().y())
QDropEvent.acceptProposedAction()
def wheelEvent(self, QWheelEvent):
@@ -78,17 +81,16 @@ class customView(QGraphicsView):
class customScene(QGraphicsScene):
"""
- re-implement QGraphicsScene for future functionality
- hint: QUndoFramework
+ Extends QGraphicsScene with undo-redo functionality
"""
def __init__(self, *args, parent=None):
super(customScene, self).__init__(*args, parent=parent)
- self.undoStack = QUndoStack(self)
- self.createActions()
-
+ self.undoStack = QUndoStack(self) #Used to store undo-redo moves
+ self.createActions() #creates necessary actions that need to be called for undo-redo
def createActions(self):
+ # helper function to create delete, undo and redo shortcuts
self.deleteAction = QAction("Delete Item", self)
self.deleteAction.setShortcut(Qt.Key_Delete)
self.deleteAction.triggered.connect(self.deleteItem)
@@ -99,38 +101,40 @@ class customScene(QGraphicsScene):
self.redoAction.setShortcut(QKeySequence.Redo)
def createUndoView(self, parent):
+ # creates an undo stack view for current QGraphicsScene
undoView = QUndoView(self.undoStack, parent)
- # undoView.resize(400, 400)
- # undoView.show()
- # undoView.setAttribute(Qt.WA_QuitOnClose, False)
showUndoDialog(undoView, parent)
def deleteItem(self):
+ # (slot) used to delete all selected items, and add undo action for each of them
if self.selectedItems():
for item in self.selectedItems():
self.undoStack.push(deleteCommand(item, self))
def itemMoved(self, movedItem, lastPos):
+ #item move event, checks if item is moved
self.undoStack.push(moveCommand(movedItem, lastPos))
def addItemPlus(self, item):
- # returnVal = self.addItem(item)
+ # extended add item method, so that a corresponding undo action is also pushed
self.undoStack.push(addCommand(item, self))
- # return returnVal
-
+
def mousePressEvent(self, event):
- bdsp = event.buttonDownScenePos(Qt.LeftButton)
- point = QPointF(bdsp.x(), bdsp.y())
- itemList = self.items(point)
- self.movingItem = itemList[0] if itemList else None
+ # overloaded mouse press event to check if an item was moved
+ bdsp = event.buttonDownScenePos(Qt.LeftButton) #get click pos
+ point = QPointF(bdsp.x(), bdsp.y()) #create a Qpoint from click pos
+ itemList = self.items(point) #get items at said point
+ self.movingItem = itemList[0] if itemList else None #set first item in list as moving item
if self.movingItem and event.button() == Qt.LeftButton:
- self.oldPos = self.movingItem.pos()
- self.clearSelection()
+ self.oldPos = self.movingItem.pos() #if left click is held, then store old pos
+ self.clearSelection() #clears selected items
return super(customScene, self).mousePressEvent(event)
def mouseReleaseEvent(self, event):
+ # overloaded mouse release event to check if an item was moved
if self.movingItem and event.button() == Qt.LeftButton:
if self.oldPos != self.movingItem.pos():
+ #if item pos had changed, when mouse was realeased, emit itemMoved signal
self.itemMoved(self.movingItem, self.oldPos)
- self.movingItem = None
+ self.movingItem = None #clear movingitem reference
return super(customScene, self).mouseReleaseEvent(event)
diff --git a/src/main/python/utils/toolbar.py b/src/main/python/utils/toolbar.py
index ec3b6a8..af6feae 100644
--- a/src/main/python/utils/toolbar.py
+++ b/src/main/python/utils/toolbar.py
@@ -2,14 +2,14 @@ from fbs_runtime.application_context.PyQt5 import ApplicationContext
from PyQt5.QtCore import QSize, Qt, pyqtSignal, QMimeData
from PyQt5.QtGui import QIcon, QDrag
from PyQt5.QtWidgets import (QBoxLayout, QDockWidget, QGridLayout, QLineEdit,
- QScrollArea, QToolButton, QWidget, QApplication)
+ QScrollArea, QToolButton, QWidget, QApplication, QStyle)
from re import search, IGNORECASE
from .data import toolbarItems
-from .funcs import grouper
+from .app import fileImporter
from .layout import flowLayout
-resourceManager = ApplicationContext() #Used to load images, mainly toolbar icons
+# resourceManager = ApplicationContext() #Used to load images, mainly toolbar icons
class toolbar(QDockWidget):
"""
@@ -38,13 +38,15 @@ class toolbar(QDockWidget):
#create a scrollable area to house all buttons
self.diagArea = QScrollArea(self)
- self.layout.addWidget(self.diagArea)
+ self.diagArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
+ self.diagArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
+ self.diagArea.setWidgetResizable(True)
+ self.layout.addWidget(self.diagArea, stretch=1)
self.diagAreaWidget = QWidget(self.diagArea) #inner widget for scroll area
#custom layout for inner widget
self.diagAreaLayout = flowLayout(self.diagAreaWidget)
- # self.diagArea.setWidget() #set inner widget to scroll area
- self.setWidget(self.widget) #set main widget to dockwidget
+ self.setWidget(self.widget) #set main widget to dockwidget
def clearLayout(self):
# used to clear all items from toolbar, by parenting it to the toolbar instead
@@ -59,6 +61,7 @@ class toolbar(QDockWidget):
self.clearLayout() #clears layout
for item in list:
self.diagAreaLayout.addWidget(self.toolbarButtonDict[item])
+ self.resize()
def searchQuery(self):
# shorten toolbaritems list with search items
@@ -74,12 +77,14 @@ class toolbar(QDockWidget):
# called when main window resizes, overloading resizeEvent caused issues.
parent = self.parentWidget() #used to get parent dimensions
self.layout.setDirection(QBoxLayout.TopToBottom) # here so that a horizontal toolbar can be implemented later
- self.setFixedWidth(.12*parent.width()) #12% of parent width
- self.setFixedHeight(self.height()) #span available height
- width = .12*parent.width() #12% of parent width
- self.diagAreaWidget.setFixedWidth(width) #set inner widget width
+ # self.setFixedHeight(self.height()) #span available height
+ width = self.width() - QApplication.style().pixelMetric(QStyle.PM_ScrollBarExtent)
# the following line, sets the required height for the current width, so that blank space doesnt occur
- self.diagAreaWidget.setFixedHeight(self.diagAreaLayout.heightForWidth(width))
+ self.diagAreaWidget.setMinimumHeight(self.diagAreaLayout.heightForWidth(width))
+ self.setMinimumWidth(.17*parent.width()) #12% of parent width
+ # self.setMinimumWidth(self.diagAreaLayout.minimumSize().width()) #12% of parent width
+ self.diagAreaWidget.setLayout(self.diagAreaLayout)
+ self.diagArea.setWidget(self.diagAreaWidget)
def toolbarItems(self, items):
#helper functions to create required buttons
@@ -103,10 +108,12 @@ class toolbarButton(QToolButton):
def __init__(self, parent = None, item = None):
super(toolbarButton, self).__init__(parent)
#uses fbs resource manager to get icons
- self.setIcon(QIcon(resourceManager.get_resource(f'toolbar/{item["icon"]}')))
- self.setIconSize(QSize(40, 40)) #unecessary but left for future references
+ self.setIcon(QIcon(fileImporter(f'toolbar/{item["icon"]}')))
+ self.setIconSize(QSize(64, 64)) #unecessary but left for future references
self.dragStartPosition = None #intialize value for drag event
self.itemObject = item['object'] #refer current item object, to handle drag mime
+ for i in item['args']:
+ self.itemObject += f"/{i}"
self.setText(item["name"]) #button text
self.setToolTip(item["name"]) #button tooltip
@@ -135,4 +142,4 @@ class toolbarButton(QToolButton):
def minimumSizeHint(self):
#defines button size
- return QSize(30, 30) \ No newline at end of file
+ return QSize(40, 40) \ No newline at end of file
diff --git a/src/main/python/utils/undo.py b/src/main/python/utils/undo.py
index 7832483..cf539e7 100644
--- a/src/main/python/utils/undo.py
+++ b/src/main/python/utils/undo.py
@@ -1,13 +1,32 @@
+"""
+Contains custom undo commands that can be pushed to undo stack
+"""
from PyQt5.QtWidgets import QUndoCommand
+from re import compile
+
+def repl(x):
+ return f"{x[0][0]} {x[0][1].lower()}"
+
+regex = compile(r"([a-z][A-Z])")
+
+def objectName(obj):
+ name = regex.sub(repl, obj.m_type if obj.__class__.__name__ == 'NodeItem' else obj.__class__.__name__)
+ # if obj.__class__.__name__ != 'line':
+ # name = 'Draw ' + name[0].upper() + name[1:]
+ # else:
+ # name = 'Add ' +
+ return name[0].upper() + name[1:] + ' symbol'
class addCommand(QUndoCommand):
-
+ """
+ QUndoCommand for add item event
+ """
def __init__(self, addItem, scene, parent = None):
super(addCommand, self).__init__(parent)
self.scene = scene
self.diagramItem = addItem
self.itemPos = addItem.pos()
- self.setText(f"Add {self.diagramItem} {self.itemPos}")
+ self.setText(f"Add {objectName(self.diagramItem)}")
def undo(self):
self.scene.removeItem(self.diagramItem)
@@ -20,13 +39,15 @@ class addCommand(QUndoCommand):
self.scene.update()
class deleteCommand(QUndoCommand):
-
+ """
+ QUndoCommand for delete item event
+ """
def __init__(self, item, scene, parent = None):
super(deleteCommand, self).__init__(parent)
self.scene = scene
item.setSelected(False)
self.diagramItem = item
- self.setText(f"Delete {self.diagramItem} {self.diagramItem.pos()}")
+ self.setText(f"Delete {objectName(self.diagramItem)} at {self.diagramItem.pos().x()}, {self.diagramItem.y()}")
def undo(self):
self.scene.addItem(self.diagramItem)
@@ -36,7 +57,9 @@ class deleteCommand(QUndoCommand):
self.scene.removeItem(self.diagramItem)
class moveCommand(QUndoCommand):
-
+ """
+ QUndoCommand for move item event
+ """
def __init__(self, item, lastPos, parent = None):
super(moveCommand, self).__init__(parent)
self.diagramItem = item
@@ -46,18 +69,38 @@ class moveCommand(QUndoCommand):
def undo(self):
self.diagramItem.setPos(self.lastPos)
self.diagramItem.scene().update()
- self.setText(f"Move {self.diagramItem} {self.newPos}")
+ self.setText(f"Move {objectName(self.diagramItem)} to {self.newPos.x()}, {self.newPos.y()}")
def redo(self):
self.diagramItem.setPos(self.newPos)
- self.setText(f"Move {self.diagramItem} {self.newPos}")
+ self.setText(f"Move {objectName(self.diagramItem)} to {self.newPos.x()}, {self.newPos.y()}")
def mergeWith(self, move):
+ #merges multiple move commands so that a move event is not added twice.
item = move.diagramItem
if self.diagramItem != item:
return False
self.newPos = item.pos()
- self.setText(f"Move {self.diagramItem} {self.newPos}")
- return True \ No newline at end of file
+ self.setText(f"Move {objectName(self.diagramItem)} to {self.newPos.x()}, {self.newPos.y()}")
+ return True
+
+class resizeCommand(QUndoCommand):
+ """
+ """
+ def __init__(self, new, canvas, widget, parent = None):
+ super(resizeCommand, self).__init__(parent)
+ self.parent = canvas
+ self.old = self.parent.canvasSize, self.parent.ppi
+ self.new = new
+ self.widget = widget
+ self.setText(f'Change canvas dimensions to {new[0]} at {new[1]} ppi')
+
+ def undo(self):
+ self.parent.canvasSize, self.parent.ppi = self.old
+ self.widget.resizeHandler()
+
+ def redo(self):
+ self.parent.canvasSize, self.parent.ppi = self.new
+ self.widget.resizeHandler() \ No newline at end of file
diff --git a/src/main/resources/base/config/items.json b/src/main/resources/base/config/items.json
new file mode 100644
index 0000000..3fbc55b
--- /dev/null
+++ b/src/main/resources/base/config/items.json
@@ -0,0 +1,902 @@
+{
+ "Ellipse": {
+ "name": "Ellipse",
+ "icon": "ellipse.png",
+ "object": "QGraphicsEllipseItem",
+ "args": [20, 20, 300, 300]
+ },
+ "airBlownCooler": {
+ "name": "Air blown cooler",
+ "icon": "AirBlownCooler.png",
+ "object": "NodeItem",
+ "args": ["airBlownCooler"]
+ },
+ "alkylation": {
+ "name": "Alkylation",
+ "icon": "Alkylation.png",
+ "object": "NodeItem",
+ "args": ["alkylation"]
+ },
+ "automaticStroker": {
+ "name": "Automatic stroker",
+ "icon": "AutomaticStroker.png",
+ "object": "NodeItem",
+ "args": ["automaticStroker"]
+ },
+ "axialCompressor": {
+ "name": "Axial compressor",
+ "icon": "AxialCompressor.png",
+ "object": "NodeItem",
+ "args": ["axialCompressor"]
+ },
+ "axialFlowFan": {
+ "name": "Axial flow fan",
+ "icon": "AxialFlowFan.png",
+ "object": "NodeItem",
+ "args": ["axialFlowFan"]
+ },
+ "bag": {
+ "name": "Bag",
+ "icon": "Bag.png",
+ "object": "NodeItem",
+ "args": ["bag"]
+ },
+ "boiler": {
+ "name": "Boiler",
+ "icon": "Boiler.png",
+ "object": "NodeItem",
+ "args": ["boiler"]
+ },
+ "boomLoader": {
+ "name": "Boom loader",
+ "icon": "BoomLoader.png",
+ "object": "NodeItem",
+ "args": ["boomLoader"]
+ },
+ "breaker": {
+ "name": "Breaker",
+ "icon": "Breaker.png",
+ "object": "NodeItem",
+ "args": ["breaker"]
+ },
+ "briquettingMachine": {
+ "name": "Briquetting machine",
+ "icon": "BriquettingMachine.png",
+ "object": "NodeItem",
+ "args": ["briquettingMachine"]
+ },
+ "cavityPump": {
+ "name": "Cavity pump",
+ "icon": "CavityPump.png",
+ "object": "NodeItem",
+ "args": ["cavityPump"]
+ },
+ "centrifugal": {
+ "name": "Centrifugal",
+ "icon": "Centrifugal.png",
+ "object": "NodeItem",
+ "args": ["centrifugal"]
+ },
+ "centrifugalBlower": {
+ "name": "Centrifugal blower",
+ "icon": "CentrifugalBlower.png",
+ "object": "NodeItem",
+ "args": ["centrifugalBlower"]
+ },
+ "centrifugalCompressor": {
+ "name": "Centrifugal compressor",
+ "icon": "CentrifugalCompressor.png",
+ "object": "NodeItem",
+ "args": ["centrifugalCompressor"]
+ },
+ "centrifugalCompressor2": {
+ "name": "Centrifugal compressor2",
+ "icon": "CentrifugalCompressor2.png",
+ "object": "NodeItem",
+ "args": ["centrifugalCompressor2"]
+ },
+ "centrifugalCompressor3": {
+ "name": "Centrifugal compressor3",
+ "icon": "CentrifugalCompressor3.png",
+ "object": "NodeItem",
+ "args": ["centrifugalCompressor3"]
+ },
+ "centrifugalCompressor4": {
+ "name": "Centrifugal compressor4",
+ "icon": "CentrifugalCompressor4.png",
+ "object": "NodeItem",
+ "args": ["centrifugalCompressor4"]
+ },
+ "centrifugalPump": {
+ "name": "Centrifugal pump",
+ "icon": "CentrifugalPump.png",
+ "object": "NodeItem",
+ "args": ["centrifugalPump"]
+ },
+ "centrifugalPump2": {
+ "name": "Centrifugal pump2",
+ "icon": "CentrifugalPump2.png",
+ "object": "NodeItem",
+ "args": ["centrifugalPump2"]
+ },
+ "centrifugalPump3": {
+ "name": "Centrifugal pump3",
+ "icon": "CentrifugalPump3.png",
+ "object": "NodeItem",
+ "args": ["centrifugalPump3"]
+ },
+ "centrifugalPump4": {
+ "name": "Centrifugal pump4",
+ "icon": "CentrifugalPump4.png",
+ "object": "NodeItem",
+ "args": ["centrifugalPump4"]
+ },
+ "chimneyTowerHyperbolic": {
+ "name": "Chimney tower hyperbolic",
+ "icon": "ChimneyTowerHyperbolic.png",
+ "object": "NodeItem",
+ "args": ["chimneyTowerHyperbolic"]
+ },
+ "coarseCrusher": {
+ "name": "Coarse crusher",
+ "icon": "CoarseCrusher.png",
+ "object": "NodeItem",
+ "args": ["coarseCrusher"]
+ },
+ "column": {
+ "name": "Column",
+ "icon": "Column.png",
+ "object": "NodeItem",
+ "args": ["column"]
+ },
+ "compressor": {
+ "name": "Compressor",
+ "icon": "Compressor.png",
+ "object": "NodeItem",
+ "args": ["compressor"]
+ },
+ "compressor2": {
+ "name": "Compressor2",
+ "icon": "Compressor2.png",
+ "object": "NodeItem",
+ "args": ["compressor2"]
+ },
+ "compressorSilencer": {
+ "name": "Compressor silencer",
+ "icon": "CompressorSilencer.png",
+ "object": "NodeItem",
+ "args": ["compressorSilencer"]
+ },
+ "compressorVaccumPump": {
+ "name": "Compressor vaccum pump",
+ "icon": "CompressorVaccumPump.png",
+ "object": "NodeItem",
+ "args": ["compressorVaccumPump"]
+ },
+ "condenser": {
+ "name": "Condenser",
+ "icon": "Condenser.png",
+ "object": "NodeItem",
+ "args": ["condenser"]
+ },
+ "coneCrusher": {
+ "name": "Cone crusher",
+ "icon": "ConeCrusher.png",
+ "object": "NodeItem",
+ "args": ["coneCrusher"]
+ },
+ "cooler": {
+ "name": "Cooler",
+ "icon": "Cooler.png",
+ "object": "NodeItem",
+ "args": ["cooler"]
+ },
+ "coolingTower2": {
+ "name": "Cooling tower2",
+ "icon": "CoolingTower2.png",
+ "object": "NodeItem",
+ "args": ["coolingTower2"]
+ },
+ "coolingTower3": {
+ "name": "Cooling tower3",
+ "icon": "CoolingTower3.png",
+ "object": "NodeItem",
+ "args": ["coolingTower3"]
+ },
+ "counterflowForcedDraft": {
+ "name": "Counterflow forced draft",
+ "icon": "CounterflowForcedDraft.png",
+ "object": "NodeItem",
+ "args": ["counterflowForcedDraft"]
+ },
+ "crossflowInducedDraft": {
+ "name": "Crossflow induced draft",
+ "icon": "CrossflowInducedDraft.png",
+ "object": "NodeItem",
+ "args": ["crossflowInducedDraft"]
+ },
+ "crusher": {
+ "name": "Crusher",
+ "icon": "Crusher.png",
+ "object": "NodeItem",
+ "args": ["crusher"]
+ },
+ "diaphragmCompressor": {
+ "name": "Diaphragm compressor",
+ "icon": "DiaphragmCompressor.png",
+ "object": "NodeItem",
+ "args": ["diaphragmCompressor"]
+ },
+ "dieselMotor": {
+ "name": "Diesel motor",
+ "icon": "DieselMotor.png",
+ "object": "NodeItem",
+ "args": ["dieselMotor"]
+ },
+ "doubleFlowTurbine": {
+ "name": "Double flow turbine",
+ "icon": "DoubleFlowTurbine.png",
+ "object": "NodeItem",
+ "args": ["doubleFlowTurbine"]
+ },
+ "doublePipeHeat": {
+ "name": "Double pipe heat",
+ "icon": "DoublePipeHeat.png",
+ "object": "NodeItem",
+ "args": ["doublePipeHeat"]
+ },
+ "dryer": {
+ "name": "Dryer",
+ "icon": "Dryer.png",
+ "object": "NodeItem",
+ "args": ["dryer"]
+ },
+ "dryingOven": {
+ "name": "Drying oven",
+ "icon": "DryingOven.png",
+ "object": "NodeItem",
+ "args": ["dryingOven"]
+ },
+ "ejector": {
+ "name": "Ejector",
+ "icon": "Ejector.png",
+ "object": "NodeItem",
+ "args": ["ejector"]
+ },
+ "ejectorCompressor": {
+ "name": "Ejector compressor",
+ "icon": "EjectorCompressor.png",
+ "object": "NodeItem",
+ "args": ["ejectorCompressor"]
+ },
+ "electricMotor": {
+ "name": "Electric motor",
+ "icon": "ElectricMotor.png",
+ "object": "NodeItem",
+ "args": ["electricMotor"]
+ },
+ "extractorHood": {
+ "name": "Extractor hood",
+ "icon": "ExtractorHood.png",
+ "object": "NodeItem",
+ "args": ["extractorHood"]
+ },
+ "fan": {
+ "name": "Fan",
+ "icon": "Fan.png",
+ "object": "NodeItem",
+ "args": ["fan"]
+ },
+ "fanBlades": {
+ "name": "Fan blades",
+ "icon": "FanBlades.png",
+ "object": "NodeItem",
+ "args": ["fanBlades"]
+ },
+ "fanBlades2": {
+ "name": "Fan blades2",
+ "icon": "FanBlades2.png",
+ "object": "NodeItem",
+ "args": ["fanBlades2"]
+ },
+ "fineCrushers": {
+ "name": "Fine crushers",
+ "icon": "FineCrushers.png",
+ "object": "NodeItem",
+ "args": ["fineCrushers"]
+ },
+ "firedHeater": {
+ "name": "Fired heater",
+ "icon": "FiredHeater.png",
+ "object": "NodeItem",
+ "args": ["firedHeater"]
+ },
+ "fluidCatalyticCracking": {
+ "name": "Fluid catalytic cracking",
+ "icon": "FluidCatalyticCracking.png",
+ "object": "NodeItem",
+ "args": ["fluidCatalyticCracking"]
+ },
+ "fluidCoking": {
+ "name": "Fluid coking",
+ "icon": "FluidCoking.png",
+ "object": "NodeItem",
+ "args": ["fluidCoking"]
+ },
+ "fluidizedBedDryer": {
+ "name": "Fluidized bed dryer",
+ "icon": "FluidizedBedDryer.png",
+ "object": "NodeItem",
+ "args": ["fluidizedBedDryer"]
+ },
+ "fluidizedReactor": {
+ "name": "Fluidized reactor",
+ "icon": "FluidizedReactor.png",
+ "object": "NodeItem",
+ "args": ["fluidizedReactor"]
+ },
+ "forcedDraftCooling": {
+ "name": "Forced draft cooling",
+ "icon": "ForcedDraftCooling.png",
+ "object": "NodeItem",
+ "args": ["forcedDraftCooling"]
+ },
+ "forcedDraftCoolingTower": {
+ "name": "Forced draft cooling tower",
+ "icon": "ForcedDraftCoolingTower.png",
+ "object": "NodeItem",
+ "args": ["forcedDraftCoolingTower"]
+ },
+ "furnace": {
+ "name": "Furnace",
+ "icon": "Furnace.png",
+ "object": "NodeItem",
+ "args": ["furnace"]
+ },
+ "furnace2": {
+ "name": "Furnace2",
+ "icon": "Furnace2.png",
+ "object": "NodeItem",
+ "args": ["furnace2"]
+ },
+ "gasBlower": {
+ "name": "Gas blower",
+ "icon": "GasBlower.png",
+ "object": "NodeItem",
+ "args": ["gasBlower"]
+ },
+ "gasBottle": {
+ "name": "Gas bottle",
+ "icon": "GasBottle.png",
+ "object": "NodeItem",
+ "args": ["gasBottle"]
+ },
+ "gearPump": {
+ "name": "Gear pump",
+ "icon": "GearPump.png",
+ "object": "NodeItem",
+ "args": ["gearPump"]
+ },
+ "generator": {
+ "name": "Generator",
+ "icon": "Generator.png",
+ "object": "NodeItem",
+ "args": ["generator"]
+ },
+ "halfPipeMixingVessel": {
+ "name": "Half pipe mixing vessel",
+ "icon": "HalfPipeMixingVessel.png",
+ "object": "NodeItem",
+ "args": ["halfPipeMixingVessel"]
+ },
+ "hammerCrusher": {
+ "name": "Hammer crusher",
+ "icon": "HammerCrusher.png",
+ "object": "NodeItem",
+ "args": ["hammerCrusher"]
+ },
+ "hammerCrusher2": {
+ "name": "Hammer crusher2",
+ "icon": "HammerCrusher2.png",
+ "object": "NodeItem",
+ "args": ["hammerCrusher2"]
+ },
+ "heatConsumer": {
+ "name": "Heat consumer",
+ "icon": "HeatConsumer.png",
+ "object": "NodeItem",
+ "args": ["heatConsumer"]
+ },
+ "heater": {
+ "name": "Heater",
+ "icon": "Heater.png",
+ "object": "NodeItem",
+ "args": ["heater"]
+ },
+ "heatExchanger": {
+ "name": "Heat exchanger",
+ "icon": "HeatExchanger.png",
+ "object": "NodeItem",
+ "args": ["heatExchanger"]
+ },
+ "heatExchanger2": {
+ "name": "Heat exchanger2",
+ "icon": "HeatExchanger2.png",
+ "object": "NodeItem",
+ "args": ["heatExchanger2"]
+ },
+ "horizontalPump": {
+ "name": "Horizontal pump",
+ "icon": "HorizontalPump.png",
+ "object": "NodeItem",
+ "args": ["horizontalPump"]
+ },
+ "horizontalVessel": {
+ "name": "Horizontal vessel",
+ "icon": "HorizontalVessel.png",
+ "object": "NodeItem",
+ "args": ["horizontalVessel"]
+ },
+ "hydroCracking": {
+ "name": "Hydro cracking",
+ "icon": "HydroCracking.png",
+ "object": "NodeItem",
+ "args": ["hydroCracking"]
+ },
+ "hydrocracking2": {
+ "name": "Hydrocracking2",
+ "icon": "Hydrocracking2.png",
+ "object": "NodeItem",
+ "args": ["hydrocracking2"]
+ },
+ "hydrodesulfurization": {
+ "name": "Hydrodesulfurization",
+ "icon": "Hydrodesulfurization.png",
+ "object": "NodeItem",
+ "args": ["hydrodesulfurization"]
+ },
+ "impactCrusher": {
+ "name": "Impact crusher",
+ "icon": "ImpactCrusher.png",
+ "object": "NodeItem",
+ "args": ["impactCrusher"]
+ },
+ "iSOCentrifugalPump": {
+ "name": "ISOCentrifugal pump",
+ "icon": "ISOCentrifugalPump.png",
+ "object": "NodeItem",
+ "args": ["iSOCentrifugalPump"]
+ },
+ "iSODiaphragmPump": {
+ "name": "ISODiaphragm pump",
+ "icon": "ISODiaphragmPump.png",
+ "object": "NodeItem",
+ "args": ["iSODiaphragmPump"]
+ },
+ "iSOGearPump": {
+ "name": "ISOGear pump",
+ "icon": "ISOGearPump.png",
+ "object": "NodeItem",
+ "args": ["iSOGearPump"]
+ },
+ "iSOLiquidPump": {
+ "name": "ISOLiquid pump",
+ "icon": "ISOLiquidPump.png",
+ "object": "NodeItem",
+ "args": ["iSOLiquidPump"]
+ },
+ "iSOPositiveDisplacementPump": {
+ "name": "ISOPositive displacement pump",
+ "icon": "ISOPositiveDisplacementPump.png",
+ "object": "NodeItem",
+ "args": ["iSOPositiveDisplacementPump"]
+ },
+ "iSOProgressivePump": {
+ "name": "ISOProgressive pump",
+ "icon": "ISOProgressivePump.png",
+ "object": "NodeItem",
+ "args": ["iSOProgressivePump"]
+ },
+ "iSOReciprocatingPistonPump": {
+ "name": "ISOReciprocating piston pump",
+ "icon": "ISOReciprocatingPistonPump.png",
+ "object": "NodeItem",
+ "args": ["iSOReciprocatingPistonPump"]
+ },
+ "iSOScrewPump": {
+ "name": "ISOScrew pump",
+ "icon": "ISOScrewPump.png",
+ "object": "NodeItem",
+ "args": ["iSOScrewPump"]
+ },
+ "jacketedMixingVessel": {
+ "name": "Jacketed mixing vessel",
+ "icon": "JacketedMixingVessel.png",
+ "object": "NodeItem",
+ "args": ["jacketedMixingVessel"]
+ },
+ "jawCrusher": {
+ "name": "Jaw crusher",
+ "icon": "JawCrusher.png",
+ "object": "NodeItem",
+ "args": ["jawCrusher"]
+ },
+ "liquidRingCompressor": {
+ "name": "Liquid ring compressor",
+ "icon": "LiquidRingCompressor.png",
+ "object": "NodeItem",
+ "args": ["liquidRingCompressor"]
+ },
+ "liquidRingVaccumPump": {
+ "name": "Liquid ring vaccum pump",
+ "icon": "LiquidRingVaccumPump.png",
+ "object": "NodeItem",
+ "args": ["liquidRingVaccumPump"]
+ },
+ "mediumCrusher": {
+ "name": "Medium crusher",
+ "icon": "MediumCrusher.png",
+ "object": "NodeItem",
+ "args": ["mediumCrusher"]
+ },
+ "mixing": {
+ "name": "Mixing",
+ "icon": "Mixing.png",
+ "object": "NodeItem",
+ "args": ["mixing"]
+ },
+ "mixingReactor": {
+ "name": "Mixing reactor",
+ "icon": "MixingReactor.png",
+ "object": "NodeItem",
+ "args": ["mixingReactor"]
+ },
+ "motor": {
+ "name": "Motor",
+ "icon": "Motor.png",
+ "object": "NodeItem",
+ "args": ["motor"]
+ },
+ "motorDrivenTurbin": {
+ "name": "Motor driven turbin",
+ "icon": "MotorDrivenTurbin.png",
+ "object": "NodeItem",
+ "args": ["motorDrivenTurbin"]
+ },
+ "motorGenerator": {
+ "name": "Motor generator",
+ "icon": "MotorGenerator.png",
+ "object": "NodeItem",
+ "args": ["motorGenerator"]
+ },
+ "movingShelfDryer": {
+ "name": "Moving shelf dryer",
+ "icon": "MovingShelfDryer.png",
+ "object": "NodeItem",
+ "args": ["movingShelfDryer"]
+ },
+ "oilBurner": {
+ "name": "Oil burner",
+ "icon": "OilBurner.png",
+ "object": "NodeItem",
+ "args": ["oilBurner"]
+ },
+ "openTank": {
+ "name": "Open tank",
+ "icon": "OpenTank.png",
+ "object": "NodeItem",
+ "args": ["openTank"]
+ },
+ "packedTower": {
+ "name": "Packed tower",
+ "icon": "PackedTower.png",
+ "object": "NodeItem",
+ "args": ["packedTower"]
+ },
+ "peristallticPump": {
+ "name": "Peristalltic pump",
+ "icon": "PeristallticPump.png",
+ "object": "NodeItem",
+ "args": ["peristallticPump"]
+ },
+ "pistonCompressor": {
+ "name": "Piston compressor",
+ "icon": "PistonCompressor.png",
+ "object": "NodeItem",
+ "args": ["pistonCompressor"]
+ },
+ "plateTower": {
+ "name": "Plate tower",
+ "icon": "PlateTower.png",
+ "object": "NodeItem",
+ "args": ["plateTower"]
+ },
+ "positiveDisplacementPump": {
+ "name": "Positive displacement pump",
+ "icon": "PositiveDisplacementPump.png",
+ "object": "NodeItem",
+ "args": ["positiveDisplacementPump"]
+ },
+ "positiveDisplacementPump2": {
+ "name": "Positive displacement pump2",
+ "icon": "PositiveDisplacementPump2.png",
+ "object": "NodeItem",
+ "args": ["positiveDisplacementPump2"]
+ },
+ "proportioningPump": {
+ "name": "Proportioning pump",
+ "icon": "ProportioningPump.png",
+ "object": "NodeItem",
+ "args": ["proportioningPump"]
+ },
+ "proportioningPump2": {
+ "name": "Proportioning pump2",
+ "icon": "ProportioningPump2.png",
+ "object": "NodeItem",
+ "args": ["proportioningPump2"]
+ },
+ "pump": {
+ "name": "Pump",
+ "icon": "Pump.png",
+ "object": "NodeItem",
+ "args": ["pump"]
+ },
+ "pump2": {
+ "name": "Pump2",
+ "icon": "Pump2.png",
+ "object": "NodeItem",
+ "args": ["pump2"]
+ },
+ "reboilerHeatExchanger": {
+ "name": "Reboiler heat exchanger",
+ "icon": "ReboilerHeatExchanger.png",
+ "object": "NodeItem",
+ "args": ["reboilerHeatExchanger"]
+ },
+ "reciprocatingCompressor": {
+ "name": "Reciprocating compressor",
+ "icon": "ReciprocatingCompressor.png",
+ "object": "NodeItem",
+ "args": ["reciprocatingCompressor"]
+ },
+ "reciprocatingCompressor2": {
+ "name": "Reciprocating compressor2",
+ "icon": "ReciprocatingCompressor2.png",
+ "object": "NodeItem",
+ "args": ["reciprocatingCompressor2"]
+ },
+ "reciprocatingPump": {
+ "name": "Reciprocating pump",
+ "icon": "ReciprocatingPump.png",
+ "object": "NodeItem",
+ "args": ["reciprocatingPump"]
+ },
+ "reciprocatingPump2": {
+ "name": "Reciprocating pump2",
+ "icon": "ReciprocatingPump2.png",
+ "object": "NodeItem",
+ "args": ["reciprocatingPump2"]
+ },
+ "reciprocativeCompressor": {
+ "name": "Reciprocative compressor",
+ "icon": "ReciprocativeCompressor.png",
+ "object": "NodeItem",
+ "args": ["reciprocativeCompressor"]
+ },
+ "ringCompressor": {
+ "name": "Ring compressor",
+ "icon": "RingCompressor.png",
+ "object": "NodeItem",
+ "args": ["ringCompressor"]
+ },
+ "rollerConveryorBeltDryer": {
+ "name": "Roller converyor belt dryer",
+ "icon": "RollerConveryorBeltDryer.png",
+ "object": "NodeItem",
+ "args": ["rollerConveryorBeltDryer"]
+ },
+ "rollerCrusher": {
+ "name": "Roller crusher",
+ "icon": "RollerCrusher.png",
+ "object": "NodeItem",
+ "args": ["rollerCrusher"]
+ },
+ "rollerVaneCompressor": {
+ "name": "Roller vane compressor",
+ "icon": "RollerVaneCompressor.png",
+ "object": "NodeItem",
+ "args": ["rollerVaneCompressor"]
+ },
+ "rotaryCompressor": {
+ "name": "Rotary compressor",
+ "icon": "RotaryCompressor.png",
+ "object": "NodeItem",
+ "args": ["rotaryCompressor"]
+ },
+ "rotaryCompressor2": {
+ "name": "Rotary compressor2",
+ "icon": "RotaryCompressor2.png",
+ "object": "NodeItem",
+ "args": ["rotaryCompressor2"]
+ },
+ "rotaryCompressor3": {
+ "name": "Rotary compressor3",
+ "icon": "RotaryCompressor3.png",
+ "object": "NodeItem",
+ "args": ["rotaryCompressor3"]
+ },
+ "rotaryCompressorSilencers": {
+ "name": "Rotary compressor silencers",
+ "icon": "RotaryCompressorSilencers.png",
+ "object": "NodeItem",
+ "args": ["rotaryCompressorSilencers"]
+ },
+ "rotaryGearPump": {
+ "name": "Rotary gear pump",
+ "icon": "RotaryGearPump.png",
+ "object": "NodeItem",
+ "args": ["rotaryGearPump"]
+ },
+ "rotaryPump": {
+ "name": "Rotary pump",
+ "icon": "RotaryPump.png",
+ "object": "NodeItem",
+ "args": ["rotaryPump"]
+ },
+ "screen": {
+ "name": "Screen",
+ "icon": "Screen.png",
+ "object": "NodeItem",
+ "args": ["screen"]
+ },
+ "screwPump": {
+ "name": "Screw pump",
+ "icon": "ScrewPump.png",
+ "object": "NodeItem",
+ "args": ["screwPump"]
+ },
+ "screwPump2": {
+ "name": "Screw pump2",
+ "icon": "ScrewPump2.png",
+ "object": "NodeItem",
+ "args": ["screwPump2"]
+ },
+ "selectableCompressor": {
+ "name": "Selectable compressor",
+ "icon": "SelectableCompressor.png",
+ "object": "NodeItem",
+ "args": ["selectableCompressor"]
+ },
+ "selectableFan": {
+ "name": "Selectable fan",
+ "icon": "SelectableFan.png",
+ "object": "NodeItem",
+ "args": ["selectableFan"]
+ },
+ "singlePassHeat": {
+ "name": "Single pass heat",
+ "icon": "SinglePassHeat.png",
+ "object": "NodeItem",
+ "args": ["singlePassHeat"]
+ },
+ "spiralHeatExchanger": {
+ "name": "Spiral heat exchanger",
+ "icon": "SpiralHeatExchanger.png",
+ "object": "NodeItem",
+ "args": ["spiralHeatExchanger"]
+ },
+ "spray": {
+ "name": "Spray",
+ "icon": "Spray.png",
+ "object": "NodeItem",
+ "args": ["spray"]
+ },
+ "sprayDryer": {
+ "name": "Spray dryer",
+ "icon": "SprayDryer.png",
+ "object": "NodeItem",
+ "args": ["sprayDryer"]
+ },
+ "straightTubesHeat": {
+ "name": "Straight tubes heat",
+ "icon": "StraightTubesHeat.png",
+ "object": "NodeItem",
+ "args": ["straightTubesHeat"]
+ },
+ "submersiblePump": {
+ "name": "Submersible pump",
+ "icon": "SubmersiblePump.png",
+ "object": "NodeItem",
+ "args": ["submersiblePump"]
+ },
+ "sumpPump": {
+ "name": "Sump pump",
+ "icon": "SumpPump.png",
+ "object": "NodeItem",
+ "args": ["sumpPump"]
+ },
+ "tank": {
+ "name": "Tank",
+ "icon": "Tank.png",
+ "object": "NodeItem",
+ "args": ["tank"]
+ },
+ "transport": {
+ "name": "Transport",
+ "icon": "Transport.png",
+ "object": "NodeItem",
+ "args": ["transport"]
+ },
+ "tripleFanBlades": {
+ "name": "Triple fan blades",
+ "icon": "TripleFanBlades.png",
+ "object": "NodeItem",
+ "args": ["tripleFanBlades"]
+ },
+ "tubular": {
+ "name": "Tubular",
+ "icon": "Tubular.png",
+ "object": "NodeItem",
+ "args": ["tubular"]
+ },
+ "turbineDriver": {
+ "name": "Turbine driver",
+ "icon": "TurbineDriver.png",
+ "object": "NodeItem",
+ "args": ["turbineDriver"]
+ },
+ "turbinePump": {
+ "name": "Turbine pump",
+ "icon": "TurbinePump.png",
+ "object": "NodeItem",
+ "args": ["turbinePump"]
+ },
+ "uTubeHeatExchanger": {
+ "name": "UTube heat exchanger",
+ "icon": "UTubeHeatExchanger.png",
+ "object": "NodeItem",
+ "args": ["uTubeHeatExchanger"]
+ },
+ "vaccumPump": {
+ "name": "Vaccum pump",
+ "icon": "VaccumPump.png",
+ "object": "NodeItem",
+ "args": ["vaccumPump"]
+ },
+ "variousCrushers": {
+ "name": "Various crushers",
+ "icon": "VariousCrushers.png",
+ "object": "NodeItem",
+ "args": ["variousCrushers"]
+ },
+ "verticalPump": {
+ "name": "Vertical pump",
+ "icon": "VerticalPump.png",
+ "object": "NodeItem",
+ "args": ["verticalPump"]
+ },
+ "verticalPump2": {
+ "name": "Vertical pump2",
+ "icon": "VerticalPump2.png",
+ "object": "NodeItem",
+ "args": ["verticalPump2"]
+ },
+ "verticalVessel": {
+ "name": "Vertical vessel",
+ "icon": "VerticalVessel.png",
+ "object": "NodeItem",
+ "args": ["verticalVessel"]
+ },
+ "vibrationCrusher": {
+ "name": "Vibration crusher",
+ "icon": "VibrationCrusher.png",
+ "object": "NodeItem",
+ "args": ["vibrationCrusher"]
+ },
+ "wastewaterTreatment": {
+ "name": "Wastewater treatment",
+ "icon": "WastewaterTreatment.png",
+ "object": "NodeItem",
+ "args": ["wastewaterTreatment"]
+ }
+} \ No newline at end of file
diff --git a/src/main/resources/base/config/paperSizes.json b/src/main/resources/base/config/paperSizes.json
new file mode 100644
index 0000000..3f85b89
--- /dev/null
+++ b/src/main/resources/base/config/paperSizes.json
@@ -0,0 +1,32 @@
+{
+ "A0": {
+ "72": [2384, 3370],
+ "96": [3179, 4494],
+ "150": [4967, 7022],
+ "300": [9933, 14043]
+ },
+ "A1": {
+ "72": [1684, 2384],
+ "96": [2245, 3179],
+ "150": [3508, 4967],
+ "300": [7016, 9933]
+ },
+ "A2": {
+ "72": [1191, 1684],
+ "96": [1587, 2245],
+ "150": [2480, 3508],
+ "300": [4960, 7016]
+ },
+ "A3": {
+ "72": [842, 1191],
+ "96": [1123, 1587],
+ "150": [1754, 2480],
+ "300": [3508, 4960]
+ },
+ "A4": {
+ "72": [595, 842],
+ "96": [794, 1123],
+ "150": [1240, 1754],
+ "300": [2480, 3508]
+ }
+} \ No newline at end of file
diff --git a/src/main/resources/base/svg/ellipse.svg b/src/main/resources/base/svg/ellipse.svg
new file mode 100644
index 0000000..8802667
--- /dev/null
+++ b/src/main/resources/base/svg/ellipse.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<svg xmlns="http://example.org" xmlns:svg="http://www.w3.org/2000/svg">
+ <!-- parent contents here -->
+ <svg:svg version="1.2" baseProfile="tiny" viewBox="0 0 100 100">
+ <svg:ellipse cx="50" cy="50" rx="50" ry="50" fill="none" stroke="black" stroke-width="1" />
+ </svg:svg>
+ <!-- ... -->
+</svg> \ No newline at end of file