Customising the Spreadsheet
The functionality of the Spreadsheet View can be extended by registering a custom column class via Python.
Creating custom columns allows you to display extra information in the Spreadsheet view, e.g. notes/metadata in Tags, or certain properties of a Clip which are not displayed by default.
You can also customise the appearance of cells, e.g. the colour, size, font or icon displayed.
Text data stored in your custom cells is also searchable in the Spreadsheet’s search filter box.
Registering Custom Columns
To create your custom columns, you need to create a custom column class, which inherits from a ‘new style’ python object class.
You then inject your custom column class (e.g. MyCustomColumns) into the hiero.ui.customColumn module, like so:
hiero.ui.customColumn = MyCustomColumns()
Note
hiero.ui.customColumn is a specially reserved module location that Hiero looks for when creating custom Spreadsheet columns. It can only contain a single custom column class.
Once you have registered your custom columns, you can right-click in the Spreadsheet View, to select which columns you would like to display.
An example of creating custom spreadsheet columns can be found here, or by running the code below:
# Shows how to add custom columns to the Spreadsheet view
import hiero.ui
from PySide2 import (QtCore, QtWidgets, QtGui)
_itemData = dict() # Just for example purposes. In real life, you'd store this in the model
class CustomSpreadsheetColumns(QtCore.QObject):
"""
A class defining custom columns for Hiero's spreadsheet view. This has a similar, but
slightly simplified, interface to the QAbstractItemModel and QItemDelegate classes.
"""
def numColumns(self):
"""
Return the number of custom columns in the spreadsheet view
"""
return 3
def columnName(self, column):
"""
Return the name of a custom column
"""
if column == 0:
return "Python Tags"
if column == 1:
return "Python Name"
if column == 2:
return "Python Row"
return ""
def getData(self, row, column, item):
"""
Return the data in a cell
"""
if column == 0:
return ""
if column == 1:
if item in _itemData:
return str(_itemData[item])
return item.name()
if column == 2:
return str(row+1)
return None
def setData(self, row, column, item, data):
"""
Set the data in a cell
"""
print( "setData", (self, row, column, item, data) )
_itemData[item] = str(data)
def getTooltip(self, row, column, item):
"""
Return the tooltip for a cell
"""
return "Tooltip: "+str(row)+"/"+str(column)+": "+item.name()
def getFont(self, row, column, item):
"""
Return the tooltip for a cell
"""
if column == 1:
return QtGui.QFont("Courier", 24)
return None
def getBackground(self, row, column, item):
"""
Return the background colour for a cell
"""
if column == 1:
return QtGui.QColor(64, 255, 64)
return None
def getForeground(self, row, column, item):
"""
Return the text colour for a cell
"""
if column == 1:
return QtGui.QColor(255, 64, 64)
return None
def getIcon(self, row, column, item):
"""
Return the icon for a cell
"""
if column == 1:
return QtGui.QIcon("icons:Add.png")
return None
def getSizeHint(self, row, column, item):
"""
Return the size hint for a cell
"""
if column == 0:
return QtCore.QSize(300, 32)
return None
def paintCell(self, row, column, item, painter, option):
"""
Paint a custom cell. Return True if the cell was painted, or False to continue
with the default cell painting.
"""
if column == 0:
if option.state & QtWidgets.QStyle.State_Selected:
painter.fillRect(option.rect, option.palette.highlight())
iconSize = 20
r = QtCore.QRect(option.rect.x(), option.rect.y()+(option.rect.height()-iconSize)/2, iconSize, iconSize)
tags = item.tags()
if len(tags) > 0:
painter.save()
painter.setClipRect(option.rect)
for tag in item.tags():
QtGui.QIcon(tag.icon()).paint(painter, r, QtCore.Qt.AlignLeft)
r.translate(r.width()+2, 0)
painter.restore()
return True
return False
def createEditor(self, row, column, item, view):
"""
Create an editing widget for a custom cell
"""
tags = item.tags()
if column == 0 and len(tags) > 0:
cb = QtWidgets.QComboBox()
for tag in tags:
cb.addItem(QtGui.QIcon(tag.icon()), tag.name())
cb.currentIndexChanged.connect(self.indexChanged);
print( "createEditor:", (self, row, column, item, view) )
return cb
return None
def setEditorData(self, row, column, item, editor):
"""
Update the custom editor from the model data. Return True if this was done.
"""
print( "setEditorData:", (self, row, column, item, editor) )
if column == 1:
try:
print( " - setEditorData:", _itemData[item] )
text = str(_itemData[item])
editor.setText(text)
return True
except:
print( "No existing data for item" )
return False
def setModelData(self, row, column, item, editor):
"""
Update the model data from the custom editor. Return True if this was done.
"""
print( "setModelData:", (self, row, column, item, editor) )
if column == 1:
_itemData[item] = str(editor.text())
print( " - setModelData:", _itemData[item] )
return True
return False
def dropMimeData(self, row, column, item, data, items):
"""
Handle a drag and drop operation
"""
print( "dropMimeData", (self, row, column, item, data.formats(), items) )
return None
def indexChanged(self, index):
"""
This method is called when our custom widget changes index.
"""
print( "ComboBox index changed:", index )
# Register our custom columns
hiero.ui.customColumn = CustomSpreadsheetColumns()