diff --git a/manuskript/mainWindow.py b/manuskript/mainWindow.py index 7fc3a51..ed6bc4c 100644 --- a/manuskript/mainWindow.py +++ b/manuskript/mainWindow.py @@ -322,6 +322,8 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.mainEditor.setFolderView(settings.folderView) self.mainEditor.updateFolderViewButtons(settings.folderView) self.tabMain.setCurrentIndex(settings.lastTab) + # We force to emit even if it opens on the current tab + self.tabMain.currentChanged.emit(settings.lastTab) self.mainEditor.updateCorkBackground() # Set autosave @@ -406,6 +408,16 @@ class MainWindow(QMainWindow, Ui_MainWindow): if sttgns.contains("revisionsState"): state = [False if v == "false" else True for v in sttgns.value("revisionsState")] self.redacMetadata.revisions.restoreState(state) + if sttgns.contains("splitterRedacH"): + self.splitterRedacH.restoreState(sttgns.value("splitterRedacH")) + if sttgns.contains("splitterRedacV"): + self.splitterRedacV.restoreState(sttgns.value("splitterRedacV")) + if sttgns.contains("toolbar"): + # self.toolbar is not initialized yet, so we just store balue + self._toolbarState = sttgns.value("toolbar") + else: + self._toolbarState = "" + def closeEvent(self, event): # Save State and geometry and other things @@ -413,8 +425,10 @@ class MainWindow(QMainWindow, Ui_MainWindow): sttgns.setValue("geometry", self.saveGeometry()) sttgns.setValue("windowState", self.saveState()) sttgns.setValue("metadataState", self.redacMetadata.saveState()) - sttgns.setValue("metadataState", self.redacMetadata.saveState()) sttgns.setValue("revisionsState", self.redacMetadata.revisions.saveState()) + sttgns.setValue("splitterRedacH", self.splitterRedacH.saveState()) + sttgns.setValue("splitterRedacV", self.splitterRedacV.saveState()) + sttgns.setValue("toolbar", self.toolbar.saveState()) # Specific settings to save before quitting settings.lastTab = self.tabMain.currentIndex() @@ -699,6 +713,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.treeOutlineOutline.setModel(self.mdlOutline) # self.redacEditor.setModel(self.mdlOutline) + self.storylineView.setModels(self.mdlOutline, self.mdlPersos, self.mdlPlots) self.treeOutlineOutline.selectionModel().selectionChanged.connect(lambda: self.outlineItemEditor.selectionChanged( @@ -799,6 +814,9 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.toolbar.addCustomWidget(self.tr("Book summary"), self.grpPlotSummary, self.TabPlots) self.toolbar.addCustomWidget(self.tr("Project tree"), self.treeRedacWidget, self.TabRedac) self.toolbar.addCustomWidget(self.tr("Metadata"), self.redacMetadata, self.TabRedac) + self.toolbar.addCustomWidget(self.tr("Story line"), self.storylineView, self.TabRedac) + if self._toolbarState: + self.toolbar.restoreState(self._toolbarState) # Custom "tab" bar on the left self.lstTabs.setIconSize(QSize(48, 48)) @@ -838,9 +856,12 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.splitterOutlineV.setStretchFactor(0, 75) self.splitterOutlineV.setStretchFactor(1, 25) - self.splitterRedac.setStretchFactor(0, 30) - self.splitterRedac.setStretchFactor(1, 40) - self.splitterRedac.setStretchFactor(2, 30) + self.splitterRedacV.setStretchFactor(0, 75) + self.splitterRedacV.setStretchFactor(1, 25) + + self.splitterRedacH.setStretchFactor(0, 30) + self.splitterRedacH.setStretchFactor(1, 40) + self.splitterRedacH.setStretchFactor(2, 30) # QFormLayout stretch for w in [self.txtWorldDescription, self.txtWorldPassion, self.txtWorldConflict]: diff --git a/manuskript/models/outlineModel.py b/manuskript/models/outlineModel.py index 36faa59..a3450a8 100644 --- a/manuskript/models/outlineModel.py +++ b/manuskript/models/outlineModel.py @@ -836,11 +836,20 @@ class outlineItem(): return lst - def findItemsContaining(self, text, columns, mainWindow, caseSensitive=False): + def findItemsContaining(self, text, columns, mainWindow=mainWindow(), caseSensitive=False, recursive=True): """Returns a list if IDs of all subitems containing ``text`` in columns ``columns`` (being a list of int). """ + lst = self.itemContains(text, columns, mainWindow, caseSensitive) + + if recursive: + for c in self.children(): + lst.extend(c.findItemsContaining(text, columns, mainWindow, caseSensitive)) + + return lst + + def itemContains(self, text, columns, mainWindow=mainWindow(), caseSensitive=False): lst = [] text = text.lower() if not caseSensitive else text for c in columns: @@ -863,9 +872,6 @@ class outlineItem(): if not self.ID() in lst: lst.append(self.ID()) - for c in self.children(): - lst.extend(c.findItemsContaining(text, columns, mainWindow, caseSensitive)) - return lst ############################################################################### diff --git a/manuskript/models/references.py b/manuskript/models/references.py index 8afa728..ac29a06 100644 --- a/manuskript/models/references.py +++ b/manuskript/models/references.py @@ -21,30 +21,47 @@ RegEx = r"{(\w):(\d+):?.*?}" RegExNonCapturing = r"{\w:\d+:?.*?}" # The basic format of the references EmptyRef = "{{{}:{}:{}}}" +EmptyRefSearchable = "{{{}:{}:" PersoLetter = "C" TextLetter = "T" PlotLetter = "P" WorldLetter = "W" -def plotReference(ID): - """Takes the ID of a plot and returns a reference for that plot.""" - return EmptyRef.format(PlotLetter, ID, "") +def plotReference(ID, searchable=False): + """Takes the ID of a plot and returns a reference for that plot. + @searchable: returns a stripped version that allows simple text search.""" + if not searchable: + return EmptyRef.format(PlotLetter, ID, "") + else: + return EmptyRefSearchable.format(PlotLetter, ID, "") -def persoReference(ID): - """Takes the ID of a character and returns a reference for that character.""" - return EmptyRef.format(PersoLetter, ID, "") +def persoReference(ID, searchable=False): + """Takes the ID of a character and returns a reference for that character. + @searchable: returns a stripped version that allows simple text search.""" + if not searchable: + return EmptyRef.format(PersoLetter, ID, "") + else: + return EmptyRefSearchable.format(PersoLetter, ID, "") -def textReference(ID): - """Takes the ID of an outline item and returns a reference for that item.""" - return EmptyRef.format(TextLetter, ID, "") +def textReference(ID, searchable=False): + """Takes the ID of an outline item and returns a reference for that item. + @searchable: returns a stripped version that allows simple text search.""" + if not searchable: + return EmptyRef.format(TextLetter, ID, "") + else: + return EmptyRefSearchable.format(TextLetter, ID, "") -def worldReference(ID): - """Takes the ID of a world item and returns a reference for that item.""" - return EmptyRef.format(WorldLetter, ID, "") +def worldReference(ID, searchable=False): + """Takes the ID of a world item and returns a reference for that item. + @searchable: returns a stripped version that allows simple text search.""" + if not searchable: + return EmptyRef.format(WorldLetter, ID, "") + else: + return EmptyRefSearchable.format(WorldLetter, ID, "") ############################################################################### @@ -375,7 +392,10 @@ def tooltip(ref): item = idx.internalPointer() - tt = qApp.translate("references", "Text: {}").format(item.title()) + if item.isFolder(): + tt = qApp.translate("references", "Folder: {}").format(item.title()) + else: + tt = qApp.translate("references", "Text: {}").format(item.title()) tt += "
{}".format(item.path()) return tt @@ -451,11 +471,32 @@ def linkifyAllRefs(text): return re.sub(RegEx, lambda m: refToLink(m.group(0)), text) +def findReferencesTo(ref, parent=None, recursive=True): + """List of text items containing references ref, and returns IDs. + Starts from item parent. If None, starts from root.""" + oM = mainWindow().mdlOutline + + if parent == None: + parent = oM.rootItem + + # Removes everything after the second ':': '{L:ID:random text}' → '{L:ID:' + ref = ref[:ref.index(":", ref.index(":") + 1)+1] + + # Bare form '{L:ID}' + ref2 = ref[:-1] + "}" + + # Since it's a simple search (no regex), we search for both. + lst = parent.findItemsContaining(ref, [Outline.notes.value], recursive=recursive) + lst += parent.findItemsContaining(ref2, [Outline.notes.value], recursive=recursive) + + return lst + def listReferences(ref, title=qApp.translate("references", "Referenced in:")): oM = mainWindow().mdlOutline listRefs = "" - ref = ref[:ref.index(":", ref.index(":") + 1)] - lst = oM.findItemsContaining(ref, [Outline.notes.value]) + + lst = findReferencesTo(ref) + for t in lst: idx = oM.getIndexByID(t) listRefs += "
  • {text}
  • ".format( diff --git a/manuskript/ui/collapsibleDockWidgets.py b/manuskript/ui/collapsibleDockWidgets.py index f6e64e1..5afebf0 100644 --- a/manuskript/ui/collapsibleDockWidgets.py +++ b/manuskript/ui/collapsibleDockWidgets.py @@ -69,6 +69,7 @@ class collapsibleDockWidgets(QToolBar): # widget.installEventFilter(self) b = verticalButton(self) b.setDefaultAction(a) + #b.setChecked(widget.isVisible()) a2 = self.addWidget(b) self.otherWidgets.append((b, a2, widget, group)) @@ -87,6 +88,22 @@ class collapsibleDockWidgets(QToolBar): else: action.setVisible(True) + def saveState(self): + # We just need to save states of the custom widgets. + state = [] + for btn, act, w, grp in self.otherWidgets: + state.append( + (grp, btn.text(), btn.isChecked()) + ) + return state + + def restoreState(self, state): + for group, title, status in state: + for btn, act, widget, grp in self.otherWidgets: + if group == grp and title == btn.text(): + btn.setChecked(status) + widget.setVisible(status) + class verticalButton(QToolButton): def __init__(self, parent): diff --git a/manuskript/ui/mainWindow.py b/manuskript/ui/mainWindow.py index 4abf5c1..8eac15f 100644 --- a/manuskript/ui/mainWindow.py +++ b/manuskript/ui/mainWindow.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'manuskript/ui/mainWindow.ui' # -# Created: Mon Feb 8 11:20:10 2016 +# Created: Sun Feb 28 13:22:17 2016 # by: PyQt5 UI code generator 5.2.1 # # WARNING! All changes made in this file will be lost! @@ -869,10 +869,15 @@ class Ui_MainWindow(object): self.verticalLayout_15 = QtWidgets.QVBoxLayout(self.lytTabRedac) self.verticalLayout_15.setContentsMargins(0, 0, 0, 0) self.verticalLayout_15.setObjectName("verticalLayout_15") - self.splitterRedac = QtWidgets.QSplitter(self.lytTabRedac) - self.splitterRedac.setOrientation(QtCore.Qt.Horizontal) - self.splitterRedac.setObjectName("splitterRedac") - self.treeRedacWidget = QtWidgets.QWidget(self.splitterRedac) + self.splitterRedacV = QtWidgets.QSplitter(self.lytTabRedac) + self.splitterRedacV.setOrientation(QtCore.Qt.Vertical) + self.splitterRedacV.setChildrenCollapsible(False) + self.splitterRedacV.setObjectName("splitterRedacV") + self.splitterRedacH = QtWidgets.QSplitter(self.splitterRedacV) + self.splitterRedacH.setOrientation(QtCore.Qt.Horizontal) + self.splitterRedacH.setChildrenCollapsible(False) + self.splitterRedacH.setObjectName("splitterRedacH") + self.treeRedacWidget = QtWidgets.QWidget(self.splitterRedacH) self.treeRedacWidget.setObjectName("treeRedacWidget") self.verticalLayout_30 = QtWidgets.QVBoxLayout(self.treeRedacWidget) self.verticalLayout_30.setContentsMargins(0, 0, 0, 0) @@ -905,11 +910,13 @@ class Ui_MainWindow(object): spacerItem16 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_31.addItem(spacerItem16) self.verticalLayout_30.addLayout(self.horizontalLayout_31) - self.mainEditor = mainEditor(self.splitterRedac) + self.mainEditor = mainEditor(self.splitterRedacH) self.mainEditor.setObjectName("mainEditor") - self.redacMetadata = metadataView(self.splitterRedac) + self.redacMetadata = metadataView(self.splitterRedacH) self.redacMetadata.setObjectName("redacMetadata") - self.verticalLayout_15.addWidget(self.splitterRedac) + self.storylineView = storylineView(self.splitterRedacV) + self.storylineView.setObjectName("storylineView") + self.verticalLayout_15.addWidget(self.splitterRedacV) self.tabMain.addTab(self.lytTabRedac, "") self.lytTabDebug = QtWidgets.QWidget() self.lytTabDebug.setObjectName("lytTabDebug") @@ -1159,7 +1166,7 @@ class Ui_MainWindow(object): self.retranslateUi(MainWindow) self.stack.setCurrentIndex(1) - self.tabMain.setCurrentIndex(4) + self.tabMain.setCurrentIndex(6) self.tabSummary.setCurrentIndex(0) self.tabPersos.setCurrentIndex(0) self.tabPlot.setCurrentIndex(0) @@ -1294,19 +1301,20 @@ class Ui_MainWindow(object): self.actCloseProject.setText(_translate("MainWindow", "&Close project")) self.actCompile.setText(_translate("MainWindow", "Co&mpile")) self.actCompile.setShortcut(_translate("MainWindow", "F6")) - self.actToolFrequency.setText(_translate("MainWindow", "Frequency Analyzer")) + self.actToolFrequency.setText(_translate("MainWindow", "&Frequency Analyzer")) -from manuskript.ui.welcome import welcome -from manuskript.ui.views.metadataView import metadataView -from manuskript.ui.views.basicItemView import basicItemView -from manuskript.ui.editors.mainEditor import mainEditor -from manuskript.ui.views.plotTreeView import plotTreeView -from manuskript.ui.sldImportance import sldImportance -from manuskript.ui.views.textEditCompleter import textEditCompleter -from manuskript.ui.views.treeView import treeView -from manuskript.ui.views.persoTreeView import persoTreeView -from manuskript.ui.search import search -from manuskript.ui.cheatSheet import cheatSheet -from manuskript.ui.views.outlineView import outlineView -from manuskript.ui.views.textEditView import textEditView from manuskript.ui.views.lineEditView import lineEditView +from manuskript.ui.cheatSheet import cheatSheet +from manuskript.ui.editors.mainEditor import mainEditor +from manuskript.ui.views.outlineView import outlineView +from manuskript.ui.views.treeView import treeView +from manuskript.ui.views.textEditView import textEditView +from manuskript.ui.views.storylineView import storylineView +from manuskript.ui.views.persoTreeView import persoTreeView +from manuskript.ui.views.plotTreeView import plotTreeView +from manuskript.ui.search import search +from manuskript.ui.views.basicItemView import basicItemView +from manuskript.ui.welcome import welcome +from manuskript.ui.views.textEditCompleter import textEditCompleter +from manuskript.ui.sldImportance import sldImportance +from manuskript.ui.views.metadataView import metadataView diff --git a/manuskript/ui/mainWindow.ui b/manuskript/ui/mainWindow.ui index 2d2f1cd..2720d37 100644 --- a/manuskript/ui/mainWindow.ui +++ b/manuskript/ui/mainWindow.ui @@ -124,7 +124,7 @@ QTabWidget::Rounded - 4 + 6 true @@ -1770,88 +1770,100 @@ 0 - + - Qt::Horizontal + Qt::Vertical - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QAbstractItemView::EditKeyPressed - - - false - - - - - - - - - - - - - ../../../../../../../.designer/backup../../../../../../../.designer/backup - - - - - - - - - - - ../../../../../../../.designer/backup../../../../../../../.designer/backup - - - - - - - - - - - ../../../../../../../.designer/backup../../../../../../../.designer/backup - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - + + false + + + + Qt::Horizontal + + + false + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractItemView::EditKeyPressed + + + false + + + + + + + + + + + + + ../../../../../../../.designer/backup../../../../../../../.designer/backup + + + + + + + + + + + ../../../../../../../.designer/backup../../../../../../../.designer/backup + + + + + + + + + + + ../../../../../../../.designer/backup../../../../../../../.designer/backup + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + - - + @@ -2323,7 +2335,7 @@ QListView::item:hover { - Frequency Analyzer + &Frequency Analyzer @@ -2405,6 +2417,12 @@ QListView::item:hover { QTextEdit
    manuskript.ui.views.textEditCompleter.h
    + + storylineView + QWidget +
    manuskript.ui.views.storylineView.h
    + 1 +
    diff --git a/manuskript/ui/views/storylineView.py b/manuskript/ui/views/storylineView.py new file mode 100644 index 0000000..ac149f7 --- /dev/null +++ b/manuskript/ui/views/storylineView.py @@ -0,0 +1,265 @@ +#!/usr/bin/env python +# --!-- coding: utf8 --!-- +from PyQt5.QtCore import Qt, QTimer, QRectF +from PyQt5.QtGui import QBrush, QPen, QFontMetrics, QFontMetricsF +from PyQt5.QtWidgets import QWidget, QGraphicsScene, QGraphicsSimpleTextItem, QMenu, QAction, QGraphicsRectItem, \ + QGraphicsLineItem, QGraphicsEllipseItem + +from manuskript.enums import Outline +from manuskript.functions import randomColor +from manuskript.models import references +from manuskript.ui.views.storylineView_ui import Ui_storylineView + + +class storylineView(QWidget, Ui_storylineView): + def __init__(self, parent=None): + QWidget.__init__(self, parent) + self.setupUi(self) + self._mdlPlots = None + self.scene = QGraphicsScene() + self.view.setScene(self.scene) + + self.reloadTimer = QTimer() + self.reloadTimer.timeout.connect(self.refresh) + self.reloadTimer.setSingleShot(True) + self.reloadTimer.setInterval(500) + + self.btnRefresh.clicked.connect(self.refresh) + self.sldTxtSize.sliderMoved.connect(self.reloadTimer.start) + + self.generateMenu() + + 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.btnSettings.setMenu(m) + + def setModels(self, mdlOutline, mdlPersos, mdlPlots): + self._mdlPlots = mdlPlots + # self._mdlPlots.dataChanged.connect(self.refresh) + # self._mdlPlots.rowsInserted.connect(self.refresh) + + self._mdlOutline = mdlOutline + self._mdlOutline.dataChanged.connect(self.reloadTimer.start) + + self._mdlPersos = mdlPersos + self._mdlPersos.dataChanged.connect(self.reloadTimer.start) + + + def refresh(self): + if not self._mdlPlots or not self._mdlOutline or not self._mdlPersos: + pass + + LINE_HEIGHT = 18 + SPACING = 3 + TEXT_WIDTH = self.sldTxtSize.value() + CIRCLE_WIDTH = 10 + LEVEL_HEIGHT = 12 + + s = self.scene + s.clear() + + # Get Max Level (max depth) + root = self._mdlOutline.rootItem + def maxLevel(item, level=0, max=0): + if level > max: + max = level + for c in item.children(): + m = maxLevel(c, level + 1) + if m > max: + max = m + return max + + MAX_LEVEL = maxLevel(root) + + # Generate left entries + # (As of now, plot only) + plotsID = self._mdlPlots.getPlotsByImportance() + 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) + + trackedItems.append((ID, ref, name)) + max_name = max(fm.width(name), max_name) + + ROWS_HEIGHT = len(trackedItems) * (LINE_HEIGHT + SPACING ) + TITLE_WIDTH = max_name + 2 * SPACING + + + # Add Folders and Texts + outline = OutlineRect(0, 0, 0, ROWS_HEIGHT + SPACING + MAX_LEVEL * LEVEL_HEIGHT) + s.addItem(outline) + outline.setPos(TITLE_WIDTH + SPACING, 0) + + refCircles = [] # a list of all references, to be added later on the lines + + # A Function to add a rect with centered elided text + def addRectText(x, w, parent, text="", level=0, tooltip=""): + deltaH = LEVEL_HEIGHT if level else 0 + r = OutlineRect(0, 0, w, parent.rect().height()-deltaH, parent, title=text) + r.setPos(x, deltaH) + + txt = QGraphicsSimpleTextItem(text, r) + f = txt.font() + f.setPointSize(8) + fm = QFontMetricsF(f) + elidedText = fm.elidedText(text, Qt.ElideMiddle, w) + txt.setFont(f) + txt.setText(elidedText) + txt.setPos(r.boundingRect().center() - txt.boundingRect().center()) + txt.setY(0) + return r + + # A function to returns an item's width, by counting its children + def itemWidth(item): + if item.isFolder(): + r = 0 + for c in item.children(): + r += itemWidth(c) + return r or TEXT_WIDTH + else: + return TEXT_WIDTH + + def listItems(item, rect, level=0): + delta = 0 + for child in item.children(): + w = itemWidth(child) + + if child.isFolder(): + parent = addRectText(delta, w, rect, child.title(), level, tooltip=child.title()) + parent.setToolTip(references.tooltip(references.textReference(child.ID()))) + listItems(child, parent, level + 1) + + else: + rectChild = addRectText(delta, TEXT_WIDTH, rect, "", level, tooltip=child.title()) + rectChild.setToolTip(references.tooltip(references.textReference(child.ID()))) + + # Find tracked references in that scene (or parent folders) + for ID, ref, name in trackedItems: + + result = [] + c = child + while c: + result += references.findReferencesTo(ref, c, recursive=False) + c = c.parent() + + if result: + ref2 = result[0] + + # Create a RefCircle with the reference + c = RefCircle(TEXT_WIDTH / 2, - CIRCLE_WIDTH / 2, CIRCLE_WIDTH, ID=ref2) + + # 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()))) + + delta += w + + listItems(root, outline) + + OUTLINE_WIDTH = itemWidth(root) + + # Add Plots + 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() + + # 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) + i += 1 + + # Text + txt = QGraphicsSimpleTextItem(name, r) + txt.setPos(r.boundingRect().center() - txt.boundingRect().center()) + + # Line + line = PlotLine(0, 0, + OUTLINE_WIDTH + SPACING, 0) + line.setPos(TITLE_WIDTH, r.mapToScene(r.rect().center()).y()) + s.addItem(line) + line.setPen(QPen(color, 5)) + line.setToolTip(self.tr("Plot: ") + name) + + # We add the circles / references to text, on the line + for ref2, circle, pos in refCircles: + if ref2 == ref: + circle.setParentItem(line) + circle.setPos(pos.x(), 0) + + # self.view.fitInView(0, 0, TOTAL_WIDTH, i * LINE_HEIGHT, Qt.KeepAspectRatioByExpanding) # KeepAspectRatio + self.view.setSceneRect(0, 0, 0, 0) + + +class OutlineRect(QGraphicsRectItem): + def __init__(self, x, y, w, h, parent=None, title=None): + QGraphicsRectItem.__init__(self, x, y, w, h, parent) + self.setBrush(Qt.white) + self.setAcceptHoverEvents(True) + self._title = title + + def hoverEnterEvent(self, event): + self.setBrush(Qt.lightGray) + + def hoverLeaveEvent(self, event): + self.setBrush(Qt.white) + + +class RefCircle(QGraphicsEllipseItem): + def __init__(self, x, y, diameter, parent=None, ID=None): + 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) + + def multiplyDiameter(self, factor): + r1 = self.rect() + r2 = QRectF(0, 0, r1.width() * factor, r1.height() * factor) + self.setRect(r2) + self.setPos(self.pos() + r1.center() - r2.center()) + + def mouseDoubleClickEvent(self, event): + references.open(self._ref) + + def hoverEnterEvent(self, event): + self.multiplyDiameter(2) + + def hoverLeaveEvent(self, event): + self.multiplyDiameter(.5) + + +class PlotLine(QGraphicsLineItem): + def __init__(self, x1, y1, x2, y2, parent=None): + QGraphicsLineItem.__init__(self, x1, y1, x2, y2, parent) + self.setAcceptHoverEvents(True) + + def hoverEnterEvent(self, QGraphicsSceneHoverEvent): + p = self.pen() + p.setWidth(10) + self.setPen(p) + + def hoverLeaveEvent(self, QGraphicsSceneHoverEvent): + p = self.pen() + p.setWidth(5) + self.setPen(p) diff --git a/manuskript/ui/views/storylineView_ui.py b/manuskript/ui/views/storylineView_ui.py new file mode 100644 index 0000000..9f886ff --- /dev/null +++ b/manuskript/ui/views/storylineView_ui.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'manuskript/ui/views/storylineView_ui.ui' +# +# Created: Sun Feb 28 09:13:29 2016 +# by: PyQt5 UI code generator 5.2.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_storylineView(object): + def setupUi(self, storylineView): + storylineView.setObjectName("storylineView") + storylineView.resize(1040, 130) + self.horizontalLayout = QtWidgets.QHBoxLayout(storylineView) + self.horizontalLayout.setSpacing(0) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setSpacing(0) + self.verticalLayout.setObjectName("verticalLayout") + self.btnZoomIn = QtWidgets.QPushButton(storylineView) + self.btnZoomIn.setMaximumSize(QtCore.QSize(32, 32)) + self.btnZoomIn.setFlat(True) + self.btnZoomIn.setObjectName("btnZoomIn") + self.verticalLayout.addWidget(self.btnZoomIn) + self.btnZoomOut = QtWidgets.QPushButton(storylineView) + self.btnZoomOut.setMaximumSize(QtCore.QSize(32, 32)) + self.btnZoomOut.setFlat(True) + self.btnZoomOut.setObjectName("btnZoomOut") + self.verticalLayout.addWidget(self.btnZoomOut) + self.btnRefresh = QtWidgets.QPushButton(storylineView) + self.btnRefresh.setMaximumSize(QtCore.QSize(32, 32)) + self.btnRefresh.setText("") + icon = QtGui.QIcon.fromTheme("view-refresh") + self.btnRefresh.setIcon(icon) + self.btnRefresh.setFlat(True) + self.btnRefresh.setObjectName("btnRefresh") + self.verticalLayout.addWidget(self.btnRefresh) + self.sldTxtSize = QtWidgets.QSlider(storylineView) + self.sldTxtSize.setMinimum(1) + self.sldTxtSize.setMaximum(100) + self.sldTxtSize.setProperty("value", 20) + self.sldTxtSize.setOrientation(QtCore.Qt.Vertical) + self.sldTxtSize.setObjectName("sldTxtSize") + self.verticalLayout.addWidget(self.sldTxtSize) + self.btnSettings = QtWidgets.QPushButton(storylineView) + self.btnSettings.setMaximumSize(QtCore.QSize(32, 32)) + self.btnSettings.setText("") + icon = QtGui.QIcon.fromTheme("preferences-system") + self.btnSettings.setIcon(icon) + self.btnSettings.setFlat(True) + self.btnSettings.setObjectName("btnSettings") + self.verticalLayout.addWidget(self.btnSettings) + self.horizontalLayout.addLayout(self.verticalLayout) + self.view = QtWidgets.QGraphicsView(storylineView) + self.view.setObjectName("view") + self.horizontalLayout.addWidget(self.view) + + self.retranslateUi(storylineView) + QtCore.QMetaObject.connectSlotsByName(storylineView) + + def retranslateUi(self, storylineView): + _translate = QtCore.QCoreApplication.translate + storylineView.setWindowTitle(_translate("storylineView", "Form")) + self.btnZoomIn.setText(_translate("storylineView", "+")) + self.btnZoomOut.setText(_translate("storylineView", "-")) + diff --git a/manuskript/ui/views/storylineView_ui.ui b/manuskript/ui/views/storylineView_ui.ui new file mode 100644 index 0000000..069de66 --- /dev/null +++ b/manuskript/ui/views/storylineView_ui.ui @@ -0,0 +1,136 @@ + + + storylineView + + + + 0 + 0 + 1040 + 130 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + + 32 + 32 + + + + + + + + true + + + + + + + + 32 + 32 + + + + - + + + true + + + + + + + + 32 + 32 + + + + + + + + + + + + true + + + + + + + 1 + + + 100 + + + 20 + + + Qt::Vertical + + + + + + + + 32 + 32 + + + + + + + + + + + + true + + + + + + + + + + + + + diff --git a/sample-projects/book-of-acts.msk b/sample-projects/book-of-acts.msk index 48f0092..0bc4d5b 100644 Binary files a/sample-projects/book-of-acts.msk and b/sample-projects/book-of-acts.msk differ