Story line can display characters

This commit is contained in:
Olivier Keshavjee 2016-02-29 23:25:23 +01:00
parent b3ebcaee10
commit f40a43b6ed
2 changed files with 161 additions and 43 deletions

View file

@ -373,56 +373,125 @@ def infos(ref):
return qApp.translate("references", "Unknown reference: {}.").format(ref)
def tooltip(ref):
"""Returns a tooltip in HTML for the reference ``ref``."""
def shortInfos(ref):
"""Returns infos about reference ``ref``.
Returns -1 if ``ref`` is not a valid reference, and None if it is valid but unknown."""
match = re.fullmatch(RegEx, ref)
if not match:
return qApp.translate("references", "Not a reference: {}.").format(ref)
return -1
_type = match.group(1)
_ref = match.group(2)
infos = {}
infos["ID"] = _ref
if _type == TextLetter:
infos["type"] = TextLetter
m = mainWindow().mdlOutline
idx = m.getIndexByID(_ref)
if not idx.isValid():
return qApp.translate("references", "Unknown reference: {}.").format(ref)
return None
item = idx.internalPointer()
if item.isFolder():
tt = qApp.translate("references", "Folder: <b>{}</b>").format(item.title())
infos["text_type"] = "folder"
else:
tt = qApp.translate("references", "Text: <b>{}</b>").format(item.title())
tt += "<br><i>{}</i>".format(item.path())
infos["text_type"] = "text"
return tt
infos["title"] = item.title()
infos["path"] = item.path()
return infos
elif _type == PersoLetter:
infos["type"] = PersoLetter
m = mainWindow().mdlPersos
item = m.item(int(_ref), Perso.name.value)
if item:
return qApp.translate("references", "Character: <b>{}</b>").format(item.text())
infos["title"] = item.text()
infos["name"] = item.text()
return infos
elif _type == PlotLetter:
infos["type"] = PlotLetter
m = mainWindow().mdlPlots
name = m.getPlotNameByID(_ref)
if name:
return qApp.translate("references", "Plot: <b>{}</b>").format(name)
infos["title"] = name
return infos
elif _type == WorldLetter:
infos["type"] = WorldLetter
m = mainWindow().mdlWorld
item = m.itemByID(_ref)
if item:
name = item.text()
path = m.path(item)
return qApp.translate("references", "World: <b>{name}</b>{path}").format(
name=name,
path=" <span style='color:gray;'>({})</span>".format(path) if path else "")
infos["title"] = name
infos["path"] = path
return infos
return qApp.translate("references", "<b>Unknown reference:</b> {}.").format(ref)
return None
def title(ref):
"""Returns a the title (or name) for the reference ``ref``."""
infos = shortInfos(ref)
if infos and infos != -1 and "title" in infos:
return infos["title"]
else:
return None
def type(ref):
infos = shortInfos(ref)
if infos and infos != -1:
return infos["type"]
def ID(ref):
infos = shortInfos(ref)
if infos and infos != -1:
return infos["ID"]
def tooltip(ref):
"""Returns a tooltip in HTML for the reference ``ref``."""
infos = shortInfos(ref)
if not infos:
return qApp.translate("references", "<b>Unknown reference:</b> {}.").format(ref)
if infos == -1:
return qApp.translate("references", "Not a reference: {}.").format(ref)
if infos["type"] == TextLetter:
if infos["text_type"] == "folder":
tt = qApp.translate("references", "Folder: <b>{}</b>").format(infos["title"])
else:
tt = qApp.translate("references", "Text: <b>{}</b>").format(infos["title"])
tt += "<br><i>{}</i>".format(infos["path"])
return tt
elif infos["type"] == PersoLetter:
return qApp.translate("references", "Character: <b>{}</b>").format(infos["title"])
elif infos["type"] == PlotLetter:
return qApp.translate("references", "Plot: <b>{}</b>").format(infos["title"])
elif infos["type"] == WorldLetter:
return qApp.translate("references", "World: <b>{name}</b>{path}").format(
name=infos["title"],
path=" <span style='color:gray;'>({})</span>".format(infos["path"]) if infos["path"] else "")
###############################################################################

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python
# --!-- coding: utf8 --!--
from PyQt5.QtCore import Qt, QTimer, QRectF
from PyQt5.QtGui import QBrush, QPen, QFontMetrics, QFontMetricsF
from PyQt5.QtGui import QBrush, QPen, QFontMetrics, QFontMetricsF, QColor
from PyQt5.QtWidgets import QWidget, QGraphicsScene, QGraphicsSimpleTextItem, QMenu, QAction, QGraphicsRectItem, \
QGraphicsLineItem, QGraphicsEllipseItem
@ -32,15 +32,17 @@ class storylineView(QWidget, Ui_storylineView):
def generateMenu(self):
m = QMenu()
for i in [
self.tr("Show Plots"),
self.tr("Show Characters"),
self.tr("Show Objects"),
]:
a = QAction(i, m)
a.setCheckable(True)
a.setEnabled(False)
m.addAction(a)
self.actPlots = QAction(self.tr("Show Plots"), m)
self.actPlots.setCheckable(True)
self.actPlots.setChecked(True)
self.actPlots.toggled.connect(self.reloadTimer.start)
m.addAction(self.actPlots)
self.actCharacters = QAction(self.tr("Show Characters"), m)
self.actCharacters.setCheckable(True)
self.actCharacters.setChecked(False)
self.actCharacters.toggled.connect(self.reloadTimer.start)
m.addAction(self.actCharacters)
self.btnSettings.setMenu(m)
@ -55,6 +57,33 @@ class storylineView(QWidget, Ui_storylineView):
self._mdlPersos = mdlPersos
self._mdlPersos.dataChanged.connect(self.reloadTimer.start)
def plotReferences(self):
"Returns a list of plot references"
if not self._mdlPlots:
pass
plotsID = self._mdlPlots.getPlotsByImportance()
r = []
for importance in plotsID:
for ID in importance:
ref = references.plotReference(ID)
r.append(ref)
return r
def persosReferences(self):
"Returns a list of character references"
if not self._mdlPersos:
pass
IDs = self._mdlPersos.getPersosByImportance()
r = []
for importance in IDs:
for ID in importance:
ref = references.persoReference(ID)
r.append(ref)
return r
def refresh(self):
if not self._mdlPlots or not self._mdlOutline or not self._mdlPersos:
@ -82,24 +111,24 @@ class storylineView(QWidget, Ui_storylineView):
MAX_LEVEL = maxLevel(root)
# Generate left entries
# (As of now, plot only)
plotsID = self._mdlPlots.getPlotsByImportance()
# Get the list of tracked items (array of references)
trackedItems = []
fm = QFontMetrics(s.font())
max_name = 0
for importance in plotsID:
for ID in importance:
name = self._mdlPlots.getPlotNameByID(ID)
ref = references.plotReference(ID, searchable=True)
if self.actPlots.isChecked():
trackedItems += self.plotReferences()
trackedItems.append((ID, ref, name))
max_name = max(fm.width(name), max_name)
if self.actCharacters.isChecked():
trackedItems += self.persosReferences()
ROWS_HEIGHT = len(trackedItems) * (LINE_HEIGHT + SPACING )
TITLE_WIDTH = max_name + 2 * SPACING
fm = QFontMetrics(s.font())
max_name = 0
for ref in trackedItems:
name = references.title(ref)
max_name = max(fm.width(name), max_name)
TITLE_WIDTH = max_name + 2 * SPACING
# Add Folders and Texts
outline = OutlineRect(0, 0, 0, ROWS_HEIGHT + SPACING + MAX_LEVEL * LEVEL_HEIGHT)
@ -150,9 +179,22 @@ class storylineView(QWidget, Ui_storylineView):
rectChild.setToolTip(references.tooltip(references.textReference(child.ID())))
# Find tracked references in that scene (or parent folders)
for ID, ref, name in trackedItems:
for ref in trackedItems:
result = []
# Tests if POV
scenePOV = False # Will hold true of character is POV of the current text, not containing folder
if references.type(ref) == references.PersoLetter:
ID = references.ID(ref)
c = child
while c:
if c.POV() == ID:
result.append(c.ID())
if c == child: scenePOV = True
c = c.parent()
# Search in notes/references
c = child
while c:
result += references.findReferencesTo(ref, c, recursive=False)
@ -162,7 +204,7 @@ class storylineView(QWidget, Ui_storylineView):
ref2 = result[0]
# Create a RefCircle with the reference
c = RefCircle(TEXT_WIDTH / 2, - CIRCLE_WIDTH / 2, CIRCLE_WIDTH, ID=ref2)
c = RefCircle(TEXT_WIDTH / 2, - CIRCLE_WIDTH / 2, CIRCLE_WIDTH, ID=ref2, important=scenePOV)
# Store it, with the position of that item, to display it on the line later on
refCircles.append((ref, c, rect.mapToItem(outline, rectChild.pos())))
@ -173,22 +215,27 @@ class storylineView(QWidget, Ui_storylineView):
OUTLINE_WIDTH = itemWidth(root)
# Add Plots
# Add Tracked items
i = 0
itemsRect = s.addRect(0, 0, 0, 0)
itemsRect.setPos(0, MAX_LEVEL * LEVEL_HEIGHT + SPACING)
for ID, ref, name in trackedItems:
color = randomColor()
for ref in trackedItems:
if references.type(ref) == references.PersoLetter:
color = QColor(self._mdlPersos.getPersoColorByID(references.ID(ref)))
else:
color = randomColor()
# Rect
r = QGraphicsRectItem(0, 0, TITLE_WIDTH, LINE_HEIGHT, itemsRect)
r.setPen(QPen(Qt.NoPen))
r.setBrush(QBrush(color))
r.setPos(0, i * LINE_HEIGHT + i * SPACING)
r.setToolTip(references.tooltip(ref))
i += 1
# Text
name = references.title(ref)
txt = QGraphicsSimpleTextItem(name, r)
txt.setPos(r.boundingRect().center() - txt.boundingRect().center())
@ -198,7 +245,7 @@ class storylineView(QWidget, Ui_storylineView):
line.setPos(TITLE_WIDTH, r.mapToScene(r.rect().center()).y())
s.addItem(line)
line.setPen(QPen(color, 5))
line.setToolTip(self.tr("Plot: ") + name)
line.setToolTip(references.tooltip(ref))
# We add the circles / references to text, on the line
for ref2, circle, pos in refCircles:
@ -225,13 +272,15 @@ class OutlineRect(QGraphicsRectItem):
class RefCircle(QGraphicsEllipseItem):
def __init__(self, x, y, diameter, parent=None, ID=None):
def __init__(self, x, y, diameter, parent=None, ID=None, important=False):
QGraphicsEllipseItem.__init__(self, x, y, diameter, diameter, parent)
self.setBrush(Qt.white)
self._ref = references.textReference(ID)
self.setToolTip(references.tooltip(self._ref))
self.setPen(QPen(Qt.black, 2))
self.setAcceptHoverEvents(True)
if important:
self.setBrush(Qt.black)
def multiplyDiameter(self, factor):
r1 = self.rect()