summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpravindalve2020-06-17 14:00:15 +0530
committerGitHub2020-06-17 14:00:15 +0530
commit75696d91982d07a33ff77729dc979bf7d8bb1a3f (patch)
tree0ad06f80d5c7a4dfef68a9cbd5df4f3746c33206
parent20f1d2b0d14f5ee73cb92a62395c71c838259b67 (diff)
parent2184341d6cb906e55409513754074ab5fdb27d14 (diff)
downloadChemical-PFD-75696d91982d07a33ff77729dc979bf7d8bb1a3f.tar.gz
Chemical-PFD-75696d91982d07a33ff77729dc979bf7d8bb1a3f.tar.bz2
Chemical-PFD-75696d91982d07a33ff77729dc979bf7d8bb1a3f.zip
Merge pull request #19 from Blakeinstein/streamTable
Stream table Feature
-rw-r--r--src/main/python/main.py4
-rw-r--r--src/main/python/shapes/line.py11
-rw-r--r--src/main/python/utils/canvas.py31
-rw-r--r--src/main/python/utils/fileWindow.py2
-rw-r--r--src/main/python/utils/graphics.py9
-rw-r--r--src/main/python/utils/streamTable.py183
-rw-r--r--src/main/resources/base/app.qss13
7 files changed, 241 insertions, 12 deletions
diff --git a/src/main/python/main.py b/src/main/python/main.py
index 9def7fb..42b4e48 100644
--- a/src/main/python/main.py
+++ b/src/main/python/main.py
@@ -143,7 +143,7 @@ class appWindow(QMainWindow):
def closeEvent(self, event):
#save alert on window close
if len(self.activeFiles) and not dialogs.saveEvent(self):
- event.ignore()
+ event.ignore()
else:
event.accept()
self.writeSettings()
@@ -184,7 +184,7 @@ class appWindow(QMainWindow):
#Key input handler
def keyPressEvent(self, event):
#overload key press event for custom keyboard shortcuts
- if event.modifiers() and Qt.ControlModifier:
+ if event.modifiers() & Qt.ControlModifier:
if event.key() == Qt.Key_N:
self.newProject()
diff --git a/src/main/python/shapes/line.py b/src/main/python/shapes/line.py
index 85c9274..1438fbc 100644
--- a/src/main/python/shapes/line.py
+++ b/src/main/python/shapes/line.py
@@ -1,8 +1,9 @@
import math
from PyQt5.QtGui import QPen, QPainterPath, QBrush, QPainterPathStroker, QPainter, QCursor, QPolygonF
from PyQt5.QtWidgets import QGraphicsItem, QGraphicsPathItem, QGraphicsTextItem, QMenu, QGraphicsLineItem
-from PyQt5.QtCore import Qt, QPointF, QRectF, QLineF
+from PyQt5.QtCore import Qt, QPointF, QRectF, QLineF, pyqtSignal
+from collections import defaultdict
class Grabber(QGraphicsPathItem):
"""
@@ -122,6 +123,8 @@ class Grabber(QGraphicsPathItem):
class LineLabel(QGraphicsTextItem):
+ nameChanged = pyqtSignal()
+
def __init__(self, pos, parent=None):
super(LineLabel, self).__init__()
# initial text
@@ -146,7 +149,8 @@ class LineLabel(QGraphicsTextItem):
self.line.setFlag(QGraphicsItem.ItemStacksBehindParent)
# reset position of line
self.resetPos()
-
+ self.values = defaultdict(lambda: 0)
+
def paint(self, painter, option, widget):
# draw ellipse shape
painter.save() # save painter
@@ -280,6 +284,9 @@ class LineLabel(QGraphicsTextItem):
def focusOutEvent(self, event):
super(LineLabel, self).focusOutEvent(event)
+ self.setTextInteractionFlags(Qt.NoTextInteraction)
+ self.nameChanged.emit()
+
self.setTextInteractionFlags(Qt.NoTextInteraction) # set text non interactive
def __getstate__(self):
diff --git a/src/main/python/utils/canvas.py b/src/main/python/utils/canvas.py
index 480a2e1..47e95a9 100644
--- a/src/main/python/utils/canvas.py
+++ b/src/main/python/utils/canvas.py
@@ -1,12 +1,13 @@
-from PyQt5.QtCore import Qt, QPointF
+from PyQt5.QtCore import Qt, QPointF, QRectF
from PyQt5.QtGui import QBrush, QPalette
from PyQt5.QtWidgets import (QFileDialog, QApplication, QHBoxLayout, QMenu,
- QTabWidget, QWidget, QSpacerItem, QStyle,)
+ QTabWidget, QWidget, QSpacerItem, QStyle, QGraphicsProxyWidget)
from . import dialogs
from .graphics import customView, customScene
from .data import paperSizes, ppiList, sheetDimensionList
from .app import shapeGrips, lines
+from .streamTable import streamTable, moveRect
import shapes
@@ -24,12 +25,13 @@ class canvas(customView):
self._ppi = ppi
self._canvasSize = size
self._landscape = landscape
- # self.setFixedSize(parent.size())
+ self.streamTable = None
#Create area for the graphic items to be placed, this is just here right now for the future
# when we will draw items on this, this might be changed if QGraphicScene is subclassed.
#set layout and background color
- self.painter = customScene()
+ self.painter = customScene()
+ self.painter.labelAdded.connect(self.updateStreamTable)
self.painter.setBackgroundBrush(QBrush(Qt.white)) #set white background
self.setScene(self.painter)
@@ -38,7 +40,22 @@ class canvas(customView):
self.parentMdiArea = parentMdiArea
self.parentFileWindow = parentFileWindow
self.customContextMenuRequested.connect(self.sideViewContextMenu)
-
+
+ def addStreamTable(self, pos=QPointF(0, 0), table=None):
+ self.streamTable = table if table else streamTable(self.labelItems, canvas=self)
+
+ self.streamTableRect = moveRect()
+ self.streamTableRect.setFlags(moveRect.ItemIsMovable |
+ moveRect.ItemIsSelectable)
+ self.streamTableProxy = QGraphicsProxyWidget(self.streamTableRect)
+ self.streamTableProxy.setWidget(self.streamTable)
+ self.painter.addItem(self.streamTableRect)
+ self.streamTableRect.setPos(pos)
+
+ def updateStreamTable(self, item):
+ if self.streamTable:
+ self.streamTable.model.insertColumn(item = item)
+
def sideViewContextMenu(self, pos):
self.parentFileWindow.sideViewContextMenu(self.mapTo(self.parentFileWindow, pos))
@@ -80,6 +97,10 @@ class canvas(customView):
# generator to filter out certain items
for i in self.painter.items():
yield i
+
+ @property
+ def labelItems(self):
+ return [i for i in self.items if isinstance(i, shapes.LineLabel)]
@property
def canvasSize(self):
diff --git a/src/main/python/utils/fileWindow.py b/src/main/python/utils/fileWindow.py
index 6d35437..e85d513 100644
--- a/src/main/python/utils/fileWindow.py
+++ b/src/main/python/utils/fileWindow.py
@@ -109,6 +109,8 @@ class fileWindow(QMdiSubWindow):
menu.addAction("Remove Side View" if self.sideViewTab == self.tabber.currentWidget() else "View Side-By-Side",
self.sideViewMode)
menu.addAction("Reset Zoom", lambda : setattr(self.tabber.currentWidget().view, 'zoom', 1))
+ if self.tabber.currentWidget().streamTable is None:
+ menu.addAction("Add Stream Table", lambda x=self, pos=point: x.tabber.currentWidget().addStreamTable(pos))
menu.exec_(self.tabber.mapToGlobal(point))
def sideViewMode(self):
diff --git a/src/main/python/utils/graphics.py b/src/main/python/utils/graphics.py
index e17fa49..3e1d193 100644
--- a/src/main/python/utils/graphics.py
+++ b/src/main/python/utils/graphics.py
@@ -1,4 +1,4 @@
-from PyQt5.QtCore import Qt, QPointF
+from PyQt5.QtCore import Qt, QPointF, pyqtSignal
from PyQt5.QtGui import QPen, QKeySequence
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QGraphicsProxyWidget, QGraphicsItem, QUndoStack, QAction, QUndoView
@@ -11,6 +11,7 @@ class customView(QGraphicsView):
"""
Defines custom QGraphicsView with zoom features and drag-drop accept event, overriding wheel event
"""
+
def __init__(self, scene = None, parent=None):
if scene is not None: #overloaded constructor
super(customView, self).__init__(scene, parent)
@@ -54,7 +55,7 @@ class customView(QGraphicsView):
def wheelEvent(self, QWheelEvent):
#overload wheelevent, to zoom if control is pressed, else scroll normally
- if Qt.ControlModifier: #check if control is pressed
+ if QWheelEvent.modifiers() & Qt.ControlModifier: #check if control is pressed
if QWheelEvent.source() == Qt.MouseEventNotSynthesized: #check if precision mouse(mac)
# angle delta is 1/8th of a degree per scroll unit
if self.zoom + QWheelEvent.angleDelta().y()/2880 > 0.1: # hit and trial value (2880)
@@ -65,7 +66,7 @@ class customView(QGraphicsView):
self.zoom += QWheelEvent.angleDelta().y()
QWheelEvent.accept() # accept event so that scrolling doesnt happen simultaneously
else:
- return super().wheelEvent(self, QWheelEvent) # scroll if ctrl not pressed
+ return super(customView, self).wheelEvent(QWheelEvent) # scroll if ctrl not pressed
@property
def zoom(self):
@@ -83,6 +84,8 @@ class customScene(QGraphicsScene):
"""
Extends QGraphicsScene with undo-redo functionality
"""
+ labelAdded = pyqtSignal(shapes.QGraphicsItem)
+
def __init__(self, *args, parent=None):
super(customScene, self).__init__(*args, parent=parent)
diff --git a/src/main/python/utils/streamTable.py b/src/main/python/utils/streamTable.py
new file mode 100644
index 0000000..acccdee
--- /dev/null
+++ b/src/main/python/utils/streamTable.py
@@ -0,0 +1,183 @@
+from PyQt5.QtCore import Qt, QSize, QRect, QPoint, QAbstractTableModel, pyqtSignal, QModelIndex
+from PyQt5.QtGui import QBrush, QPen, QColor, QCursor
+from PyQt5.QtWidgets import QTableView, QMenu, QGraphicsRectItem, QInputDialog, QStyledItemDelegate, QHeaderView
+
+from collections import defaultdict
+
+class streamTableModel(QAbstractTableModel):
+ updateEvent = pyqtSignal()
+
+ def __init__(self, parent, list, header, *args):
+ super(streamTableModel, self).__init__(parent, *args)
+ self.list = list
+ self.header = header
+
+ def columnCount(self, parent=None):
+ return len(self.list)
+
+ def rowCount(self, parent=None):
+ return len(self.header)
+
+ def data(self, index, role):
+ if role == Qt.TextAlignmentRole:
+ return Qt.AlignHCenter
+ if role == Qt.BackgroundColorRole:
+ return Qt.white
+ if not index.isValid():
+ return None
+ elif role != Qt.DisplayRole:
+ return None
+ if index.row() == 0:
+ return self.list[index.column()].toPlainText()
+ else:
+ return self.list[index.column()].values[self.header[index.row()]]
+
+ def setData(self, index, value, role):
+ if not index.isValid():
+ return False
+ elif role != Qt.EditRole:
+ return False
+ if index.row() == 0:
+ self.list[index.column()].setPlainText(value)
+ else:
+ self.list[index.column()].values[self.header[index.row()]] = value
+ return True
+
+ def insertColumn(self, int=None, item=None):
+ int = int if int else self.rowCount()+1
+ self.beginInsertColumns(QModelIndex(), int, int)
+ self.list.insert(int, item)
+ self.endInsertColumns()
+ self.updateEvent.emit()
+
+ def insertRow(self, int=None, name="newVal"):
+ self.beginInsertRows(QModelIndex(), int, int)
+ self.header.insert(int, name)
+ self.endInsertRows()
+ self.updateEvent.emit()
+
+ def deleteRow(self, row):
+ self.beginRemoveRows(QModelIndex(), row, row)
+ valName = self.header.pop(row)
+ self.endRemoveRows()
+ for i in self.list:
+ i.values.pop(valName)
+ self.updateEvent.emit()
+
+ def headerData(self, col, orientation, role):
+ if orientation == Qt.Vertical and role == Qt.DisplayRole:
+ return self.header[col]
+ return None
+
+ def flags(self, index):
+ return (super(streamTableModel, self).flags(index) | Qt.ItemIsEditable)
+
+class streamTable(QTableView):
+
+ def __init__(self, itemLabels=[], canvas=None, parent=None):
+ super(streamTable, self).__init__(parent=parent)
+ self.canvas = canvas
+ for i in itemLabels:
+ i.nameChanged.connect(self.repaint)
+ header = ["name", "val1", "val2", "val3", "val4", "val5"]
+ self.model = streamTableModel(self, itemLabels, header)
+ self.setShowGrid(False)
+
+ self.horizontalHeader().hide()
+ header = verticalHeader(Qt.Vertical, self)
+ self.setVerticalHeader(header)
+ header.labelChangeRequested.connect(self.labelChange)
+
+ self.setModel(self.model)
+ self.borderThickness = defaultdict(lambda: False)
+ self.model.updateEvent.connect(self.resizeHandler)
+
+ self.setItemDelegateForRow(0, drawBorderDelegate(self))
+
+ def mousePressEvent(self, event):
+ if event.button() == Qt.RightButton:
+ point = event.pos()
+ # col = self.getCol(point.x())
+ index = self.indexAt(point)
+ menu = QMenu("Context Menu", self)
+ menu.addAction("Toggle bottom border thickness", lambda x=index.row(): self.changeRowBorder(x))
+ menu.addAction("Insert Row to bottom", lambda x=index.row(): self.insertRowBottom(x))
+ menu.addAction("Delete row", lambda x=index.row(): self.model.deleteRow(x))
+ menu.exec_(self.mapToGlobal(point)+ QPoint(20, 25))
+ event.accept()
+ return super(streamTable, self).mousePressEvent(event)
+
+ def changeRowBorder(self, row):
+ if self.borderThickness[row]:
+ self.borderThickness[row] = False
+ self.setItemDelegateForRow(row, QStyledItemDelegate(self))
+ else:
+ self.borderThickness[row] = True
+ self.setItemDelegateForRow(row, drawBorderDelegate(self))
+
+ def labelChange(self, index):
+ newName, bool = QInputDialog.getText(self, "Change Property Name", "Enter new name",
+ text = self.model.header[index])
+ if bool:
+ for i in self.model.list:
+ i.values[newName] = i.values.pop(self.model.header[index])
+ self.model.header[index] = newName
+ self.repaint()
+
+ def insertRowBottom(self, row):
+ name, bool = QInputDialog.getText(self, "New Property", "Enter name",
+ text = "newVal")
+ if bool:
+ self.model.insertRow(row + 1, name)
+ self.repaint()
+
+ def resizeHandler(self):
+ self.resize(self.sizeHint())
+
+ def sizeHint(self):
+ return self.rect().size()
+
+ def rect(self):
+ w = self.verticalHeader().width() + 4
+ for i in range(self.model.columnCount()):
+ w += self.columnWidth(i)
+ h = 0
+ for i in range(self.model.rowCount()):
+ h += self.rowHeight(i)
+ return QRect(0, 0, w, h)
+
+class drawBorderDelegate(QStyledItemDelegate):
+
+ # def __init__(self, parent):
+ # super(drawBorderDelegate, self).__init__(parent)
+
+ def paint(self, painter, option, index):
+ rect = option.rect
+ painter.drawLine(rect.bottomLeft(), rect.bottomRight())
+ painter.setPen(QPen(Qt.black, 1, Qt.SolidLine))
+ super(drawBorderDelegate, self).paint(painter, option, index)
+
+class moveRect(QGraphicsRectItem):
+
+ def __init__(self, sideLength = 15, *args):
+ super(moveRect, self).__init__(-sideLength, -sideLength, sideLength, sideLength)
+ self.setBrush(Qt.transparent)
+ self.setPen(QPen(Qt.transparent))
+ self.setCursor(QCursor(Qt.SizeAllCursor))
+ self.setAcceptHoverEvents(True)
+
+ def hoverEnterEvent(self, event):
+ self.setBrush(QBrush(QColor(0, 0, 0, 120)))
+ return super(moveRect, self).hoverEnterEvent(event)
+
+ def hoverLeaveEvent(self, event):
+ self.setBrush(QBrush(QColor(0, 0, 0, 0)))
+ return super(moveRect, self).hoverLeaveEvent(event)
+
+class verticalHeader(QHeaderView):
+ labelChangeRequested = pyqtSignal(int)
+
+ def mouseDoubleClickEvent(self, event):
+ index = self.logicalIndexAt(event.pos())
+ self.labelChangeRequested.emit(index)
+ return super().mouseDoubleClickEvent(event) \ No newline at end of file
diff --git a/src/main/resources/base/app.qss b/src/main/resources/base/app.qss
index e0b5140..5650279 100644
--- a/src/main/resources/base/app.qss
+++ b/src/main/resources/base/app.qss
@@ -264,4 +264,17 @@ customTabWidget customView {
border-width: 0px;
padding: 5px;
border-radius: 2px;
+}
+QHeaderView {
+ qproperty-defaultAlignment: AlignHCenter;
+}
+QHeaderView::section {
+ padding: 4px;
+ border-style: none;
+ background-color: white;
+}
+
+QTableView {
+ border: none;
+ background-color: white;
} \ No newline at end of file