2015-06-29 09:46:51 +12:00
|
|
|
#!/usr/bin/env python
|
2016-02-07 00:34:22 +13:00
|
|
|
# --!-- coding: utf8 --!--
|
|
|
|
from PyQt5.QtCore import QSize, QModelIndex, Qt
|
|
|
|
from PyQt5.QtGui import QPixmap, QColor, QIcon, QBrush
|
2023-03-08 08:56:54 +13:00
|
|
|
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QColorDialog, QDialog, QMessageBox
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2016-03-04 04:38:38 +13:00
|
|
|
from manuskript.enums import Character
|
|
|
|
from manuskript.functions import iconColor, mainWindow
|
2017-11-15 02:48:28 +13:00
|
|
|
from manuskript.ui import style as S
|
2023-03-05 12:58:25 +13:00
|
|
|
from manuskript.ui import characterInfoDialog
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2015-06-29 09:46:51 +12:00
|
|
|
|
2016-03-04 04:38:38 +13:00
|
|
|
class characterTreeView(QTreeWidget):
|
|
|
|
"""
|
|
|
|
A QTreeWidget that displays characters from a characterModel in respect of their importance.
|
|
|
|
"""
|
2015-06-29 09:46:51 +12:00
|
|
|
def __init__(self, parent=None):
|
|
|
|
QTreeWidget.__init__(self, parent)
|
|
|
|
self._model = None
|
|
|
|
self._catRow = [-1, -1, -1]
|
|
|
|
self._filter = ""
|
|
|
|
self._lastID = -1
|
|
|
|
self._updating = False
|
|
|
|
self.setRootIsDecorated(False)
|
|
|
|
self.setIndentation(10)
|
2015-06-29 20:22:18 +12:00
|
|
|
self.setHeaderHidden(True)
|
|
|
|
self.setIconSize(QSize(24, 24))
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2015-06-29 09:46:51 +12:00
|
|
|
self.setColumnCount(1)
|
|
|
|
self._rootItem = QTreeWidgetItem()
|
|
|
|
self.insertTopLevelItem(0, self._rootItem)
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2020-06-01 08:33:14 +12:00
|
|
|
self.importanceMap = {self.tr("Main"):2, self.tr("Secondary"):1, self.tr("Minor"):0}
|
|
|
|
|
2016-03-04 04:38:38 +13:00
|
|
|
def setCharactersModel(self, model):
|
2015-06-29 09:46:51 +12:00
|
|
|
self._model = model
|
|
|
|
self._model.dataChanged.connect(self.updateMaybe)
|
|
|
|
self._model.rowsInserted.connect(self.updateMaybe2)
|
|
|
|
self._model.rowsRemoved.connect(self.updateMaybe2)
|
|
|
|
self.updateItems()
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2015-06-29 09:46:51 +12:00
|
|
|
def setFilter(self, text):
|
|
|
|
self._filter = text
|
|
|
|
self.updateItems()
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2015-06-29 09:46:51 +12:00
|
|
|
def updateMaybe(self, topLeft, bottomRight):
|
|
|
|
if topLeft.parent() != QModelIndex():
|
|
|
|
return
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2017-11-16 09:05:48 +13:00
|
|
|
if topLeft.column() <= Character.name <= bottomRight.column():
|
2015-06-29 09:46:51 +12:00
|
|
|
# Update name
|
|
|
|
self.updateNames()
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2017-11-16 09:05:48 +13:00
|
|
|
elif topLeft.column() <= Character.importance <= bottomRight.column():
|
2015-06-29 09:46:51 +12:00
|
|
|
# Importance changed
|
|
|
|
self.updateItems()
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2015-06-29 09:46:51 +12:00
|
|
|
def updateMaybe2(self, parent, first, last):
|
2016-02-07 00:34:22 +13:00
|
|
|
# Rows inserted or removed, we update only if they are topLevel rows.
|
2015-06-29 09:46:51 +12:00
|
|
|
if parent == QModelIndex():
|
|
|
|
self.updateItems()
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2015-06-29 09:46:51 +12:00
|
|
|
def updateNames(self):
|
|
|
|
for i in range(self.topLevelItemCount()):
|
|
|
|
item = self.topLevelItem(i)
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2016-03-04 04:38:38 +13:00
|
|
|
for child in range(item.childCount()):
|
|
|
|
sub = item.child(child)
|
2015-06-29 09:46:51 +12:00
|
|
|
ID = sub.data(0, Qt.UserRole)
|
2021-02-22 11:45:34 +13:00
|
|
|
if ID != None:
|
2015-06-29 20:22:18 +12:00
|
|
|
# Update name
|
2016-03-04 04:38:38 +13:00
|
|
|
c = self._model.getCharacterByID(ID)
|
|
|
|
name = c.name()
|
2015-06-29 09:46:51 +12:00
|
|
|
sub.setText(0, name)
|
2015-06-29 20:22:18 +12:00
|
|
|
# Update icon
|
|
|
|
px = QPixmap(32, 32)
|
2016-03-04 04:38:38 +13:00
|
|
|
color = c.color()
|
2015-06-29 20:22:18 +12:00
|
|
|
px.fill(color)
|
|
|
|
sub.setIcon(0, QIcon(px))
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2015-06-29 09:46:51 +12:00
|
|
|
def updateItems(self):
|
|
|
|
if not self._model:
|
|
|
|
return
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2015-06-29 09:46:51 +12:00
|
|
|
if self.currentItem():
|
|
|
|
self._lastID = self.currentItem().data(0, Qt.UserRole)
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2015-06-29 09:46:51 +12:00
|
|
|
self._updating = True
|
|
|
|
self.clear()
|
2016-03-04 04:38:38 +13:00
|
|
|
characters = self._model.getCharactersByImportance()
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2020-06-01 08:33:14 +12:00
|
|
|
for i, importanceLevel in enumerate(self.importanceMap):
|
2016-03-04 04:38:38 +13:00
|
|
|
# Create category item
|
2020-06-01 08:33:14 +12:00
|
|
|
cat = QTreeWidgetItem(self, [importanceLevel])
|
2017-11-15 02:48:28 +13:00
|
|
|
cat.setBackground(0, QBrush(QColor(S.highlightLight)))
|
|
|
|
cat.setForeground(0, QBrush(QColor(S.highlightedTextDark)))
|
2015-06-29 09:46:51 +12:00
|
|
|
cat.setTextAlignment(0, Qt.AlignCenter)
|
|
|
|
f = cat.font(0)
|
|
|
|
f.setBold(True)
|
|
|
|
cat.setFont(0, f)
|
|
|
|
self.addTopLevelItem(cat)
|
2016-02-07 00:34:22 +13:00
|
|
|
# cat.setChildIndicatorPolicy(cat.DontShowIndicator)
|
|
|
|
|
2016-03-04 04:38:38 +13:00
|
|
|
for c in characters[i]:
|
|
|
|
name = c.name()
|
|
|
|
# Check if name passes filter
|
2016-02-07 00:34:22 +13:00
|
|
|
if not self._filter.lower() in name.lower():
|
2015-06-29 09:46:51 +12:00
|
|
|
continue
|
2016-03-04 04:38:38 +13:00
|
|
|
|
2015-06-29 09:46:51 +12:00
|
|
|
item = QTreeWidgetItem(cat, [name])
|
2016-03-04 04:38:38 +13:00
|
|
|
item.setData(0, Qt.UserRole, c.ID())
|
2015-06-29 09:46:51 +12:00
|
|
|
px = QPixmap(32, 32)
|
2016-03-04 04:38:38 +13:00
|
|
|
color = QColor(c.color())
|
2015-06-29 09:46:51 +12:00
|
|
|
px.fill(color)
|
|
|
|
item.setIcon(0, QIcon(px))
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2016-03-04 04:38:38 +13:00
|
|
|
if c.ID() == self._lastID:
|
2015-06-29 09:46:51 +12:00
|
|
|
self.setCurrentItem(item)
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2015-06-29 09:46:51 +12:00
|
|
|
self.expandAll()
|
|
|
|
self._updating = False
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2020-06-01 08:33:14 +12:00
|
|
|
def addCharacter(self):
|
|
|
|
curr_item = self.currentItem()
|
|
|
|
curr_importance = 0
|
|
|
|
|
|
|
|
# check if an item is selected
|
2021-02-22 11:45:34 +13:00
|
|
|
if curr_item != None:
|
|
|
|
if curr_item.parent() == None:
|
2020-06-01 08:33:14 +12:00
|
|
|
# this is a top-level category, so find its importance
|
|
|
|
# get the current text, then look up the importance level
|
|
|
|
text = curr_item.text(0)
|
|
|
|
curr_importance = self.importanceMap[text]
|
|
|
|
else:
|
|
|
|
# get the importance from the currently-highlighted character
|
|
|
|
curr_character = self.currentCharacter()
|
|
|
|
curr_importance = curr_character.importance()
|
|
|
|
|
|
|
|
self._model.addCharacter(importance=curr_importance)
|
|
|
|
|
2023-03-08 08:56:54 +13:00
|
|
|
def removeCharacters(self):
|
2016-03-04 04:38:38 +13:00
|
|
|
"""
|
2023-03-08 08:56:54 +13:00
|
|
|
Removes selected characters.
|
2016-03-04 04:38:38 +13:00
|
|
|
"""
|
2023-03-08 08:56:54 +13:00
|
|
|
IDs = self.currentCharacterIDs()
|
|
|
|
|
|
|
|
# If none of the IDs are valid, do nothing.
|
|
|
|
if not any(IDs):
|
2021-12-01 11:40:31 +13:00
|
|
|
return None
|
2023-03-08 08:56:54 +13:00
|
|
|
|
|
|
|
#Get confirmation from user
|
|
|
|
confirm = QMessageBox.warning(
|
|
|
|
self, "Delete selected character(s)?",
|
|
|
|
"Are you sure you want to delete the selected character(s)?",
|
|
|
|
QMessageBox.Yes | QMessageBox.No
|
|
|
|
)
|
|
|
|
if confirm != QMessageBox.Yes:
|
|
|
|
return None
|
|
|
|
|
|
|
|
#Delete all selected characters
|
|
|
|
for ID in IDs:
|
|
|
|
self._model.removeCharacter(ID)
|
|
|
|
return IDs
|
2016-03-04 04:38:38 +13:00
|
|
|
|
|
|
|
def choseCharacterColor(self):
|
|
|
|
ID = self.currentCharacterID()
|
|
|
|
c = self._model.getCharacterByID(ID)
|
2020-03-31 16:55:30 +13:00
|
|
|
|
2016-03-04 04:38:38 +13:00
|
|
|
if c:
|
|
|
|
color = iconColor(c.icon)
|
|
|
|
else:
|
|
|
|
color = Qt.white
|
2020-03-31 16:55:30 +13:00
|
|
|
|
2016-03-04 04:38:38 +13:00
|
|
|
self.colorDialog = QColorDialog(color, mainWindow())
|
|
|
|
color = self.colorDialog.getColor(color)
|
2020-03-31 16:55:30 +13:00
|
|
|
|
2016-03-04 04:38:38 +13:00
|
|
|
if color.isValid():
|
|
|
|
c.setColor(color)
|
|
|
|
mainWindow().updateCharacterColor(ID)
|
|
|
|
|
2020-03-31 16:55:30 +13:00
|
|
|
def changeCharacterPOVState(self, state):
|
|
|
|
ID = self.currentCharacterID()
|
|
|
|
c = self._model.getCharacterByID(ID)
|
|
|
|
c.setPOVEnabled(state == Qt.Checked)
|
|
|
|
mainWindow().updateCharacterPOVState(ID)
|
|
|
|
|
2016-03-04 04:38:38 +13:00
|
|
|
def addCharacterInfo(self):
|
2023-03-05 12:58:25 +13:00
|
|
|
#Setting up dialog
|
|
|
|
charInfoDialog = QDialog()
|
|
|
|
charInfoUi = characterInfoDialog.Ui_characterInfoDialog()
|
|
|
|
charInfoUi.setupUi(charInfoDialog)
|
|
|
|
|
|
|
|
if charInfoDialog.exec_() == QDialog.Accepted:
|
|
|
|
# User clicked OK, get the input values
|
|
|
|
description = charInfoUi.descriptionLineEdit.text()
|
|
|
|
value = charInfoUi.valueLineEdit.text()
|
|
|
|
|
|
|
|
# Add the character info with the input values
|
2023-03-08 08:27:16 +13:00
|
|
|
ID = self.currentCharacterID()
|
|
|
|
self._model.addCharacterInfo(ID, description, value)
|
2023-03-05 12:58:25 +13:00
|
|
|
|
|
|
|
|
2016-03-04 04:38:38 +13:00
|
|
|
|
|
|
|
def removeCharacterInfo(self):
|
2020-03-31 16:55:30 +13:00
|
|
|
self._model.removeCharacterInfo(self.currentCharacterID())
|
2016-03-04 04:38:38 +13:00
|
|
|
|
|
|
|
def currentCharacterID(self):
|
2015-06-29 09:46:51 +12:00
|
|
|
ID = None
|
|
|
|
if self.currentItem():
|
|
|
|
ID = self.currentItem().data(0, Qt.UserRole)
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2016-03-04 04:38:38 +13:00
|
|
|
return ID
|
|
|
|
|
2023-03-05 12:58:25 +13:00
|
|
|
def currentCharacterIDs(self): #Exactly like currentCharacterID(), except for multiselection
|
|
|
|
IDs = []
|
|
|
|
for item in self.selectedItems():
|
|
|
|
ID = item.data(0, Qt.UserRole)
|
|
|
|
if ID is not None:
|
|
|
|
IDs.append(ID)
|
|
|
|
return IDs
|
|
|
|
|
2016-03-04 04:38:38 +13:00
|
|
|
def currentCharacter(self):
|
|
|
|
"""
|
|
|
|
Returns the selected character
|
|
|
|
@return: Character
|
|
|
|
"""
|
|
|
|
ID = self.currentCharacterID()
|
|
|
|
return self._model.getCharacterByID(ID)
|
2023-03-06 02:14:58 +13:00
|
|
|
def currentCharacters(self):
|
|
|
|
"""
|
|
|
|
Returns the selected characters (when multiple are selected)
|
|
|
|
@return: List of Characters
|
|
|
|
"""
|
|
|
|
IDs = self.currentCharacterIDs()
|
|
|
|
characters = []
|
|
|
|
for ID in IDs:
|
|
|
|
characters.append(self._model.getCharacterByID(ID))
|
|
|
|
return characters
|
2016-02-07 00:34:22 +13:00
|
|
|
|
2016-03-04 05:18:30 +13:00
|
|
|
def getItemByID(self, ID):
|
|
|
|
for t in range(self.topLevelItemCount()):
|
|
|
|
for i in range(self.topLevelItem(t).childCount()):
|
|
|
|
item = self.topLevelItem(t).child(i)
|
|
|
|
if item.data(0, Qt.UserRole) == ID:
|
|
|
|
return item
|
|
|
|
|
2015-06-29 09:46:51 +12:00
|
|
|
def mouseDoubleClickEvent(self, event):
|
|
|
|
item = self.currentItem()
|
2021-12-01 11:08:59 +13:00
|
|
|
if item is None:
|
|
|
|
return
|
2015-06-29 09:46:51 +12:00
|
|
|
# Catching double clicks to forbid collapsing of toplevel items
|
|
|
|
if item.parent():
|
|
|
|
QTreeWidget.mouseDoubleClickEvent(self, event)
|