manuskript/manuskript/ui/editors/fullScreenEditor.py

373 lines
14 KiB
Python
Raw Normal View History

2015-06-20 04:47:45 +12:00
#!/usr/bin/env python
2016-02-07 00:34:22 +13:00
# --!-- coding: utf8 --!--
import os
from PyQt5.QtCore import Qt, QSize, QPoint, QRect, QEvent, QTimer
from PyQt5.QtGui import QFontMetrics, QColor, QBrush, QPalette, QPainter, QPixmap
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QFrame, QWidget, QPushButton, qApp, QStyle, QComboBox, QLabel, QScrollBar, \
QStyleOptionSlider, QHBoxLayout, QVBoxLayout, QMenu, QAction
2015-06-20 04:47:45 +12:00
# Spell checker support
2016-02-07 00:34:22 +13:00
from manuskript import settings
from manuskript.enums import Outline
from manuskript.functions import allPaths, drawProgress
from manuskript.ui.editors.locker import locker
from manuskript.ui.editors.textFormat import textFormat
from manuskript.ui.editors.themes import findThemePath, generateTheme, setThemeEditorDatas
from manuskript.ui.editors.themes import loadThemeDatas
from manuskript.ui.views.textEditView import textEditView
try:
import enchant
except ImportError:
enchant = None
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
class fullScreenEditor(QWidget):
2015-06-21 10:36:25 +12:00
def __init__(self, index, parent=None):
2015-06-20 04:47:45 +12:00
QWidget.__init__(self, parent)
self._background = None
2015-06-21 10:36:25 +12:00
self._index = index
2015-06-20 04:47:45 +12:00
self._theme = findThemePath(settings.fullScreenTheme)
self._themeDatas = loadThemeDatas(self._theme)
self.setMouseTracking(True)
self._geometries = {}
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
# Text editor
2016-02-07 00:34:22 +13:00
self.editor = textEditView(self,
index=index,
spellcheck=settings.spellcheck,
highlighting=True,
dict=settings.dict)
2015-06-20 04:47:45 +12:00
self.editor.setFrameStyle(QFrame.NoFrame)
self.editor.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.editor.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.editor.installEventFilter(self)
self.editor.setMouseTracking(True)
2015-06-21 07:35:57 +12:00
self.editor.setVerticalScrollBar(myScrollBar())
2015-06-20 04:47:45 +12:00
self.scrollBar = self.editor.verticalScrollBar()
self.scrollBar.setParent(self)
2016-02-07 00:34:22 +13:00
2015-06-21 10:36:25 +12:00
# Top Panel
2015-06-21 07:35:57 +12:00
self.topPanel = myPanel(parent=self)
2016-02-07 00:34:22 +13:00
# self.topPanel.layout().addStretch(1)
# Spell checking
if enchant:
self.btnSpellCheck = QPushButton(self)
self.btnSpellCheck.setFlat(True)
self.btnSpellCheck.setIcon(QIcon.fromTheme("tools-check-spelling"))
self.btnSpellCheck.setCheckable(True)
self.btnSpellCheck.setChecked(self.editor.spellcheck)
self.btnSpellCheck.toggled.connect(self.editor.toggleSpellcheck)
self.topPanel.layout().addWidget(self.btnSpellCheck)
2016-02-07 00:34:22 +13:00
2015-06-21 10:36:25 +12:00
self.topPanel.layout().addStretch(1)
2016-02-07 00:34:22 +13:00
# Formatting
self.textFormat = textFormat(self)
self.topPanel.layout().addWidget(self.textFormat)
self.topPanel.layout().addStretch(1)
2016-02-07 00:34:22 +13:00
self.btnClose = QPushButton(self)
self.btnClose.setIcon(qApp.style().standardIcon(QStyle.SP_DialogCloseButton))
self.btnClose.clicked.connect(self.close)
self.btnClose.setFlat(True)
self.topPanel.layout().addWidget(self.btnClose)
2016-02-07 00:34:22 +13:00
# Left Panel
self._locked = False
self.leftPanel = myPanel(vertical=True, parent=self)
self.locker = locker(self)
self.locker.lockChanged.connect(self.setLocked)
self.leftPanel.layout().addWidget(self.locker)
2016-02-07 00:34:22 +13:00
2015-06-21 10:36:25 +12:00
# Bottom Panel
self.bottomPanel = myPanel(parent=self)
2016-02-07 00:34:22 +13:00
2015-06-21 10:36:25 +12:00
self.bottomPanel.layout().addSpacing(24)
2015-06-21 07:35:57 +12:00
self.lstThemes = QComboBox(self)
self.lstThemes.setAttribute(Qt.WA_TranslucentBackground)
paths = allPaths("resources/themes")
for p in paths:
lst = [i for i in os.listdir(p) if os.path.splitext(i)[1] == ".theme"]
for t in lst:
themeIni = os.path.join(p, t)
name = loadThemeDatas(themeIni)["Name"]
# self.lstThemes.addItem(os.path.splitext(t)[0])
self.lstThemes.addItem(name)
self.lstThemes.setItemData(self.lstThemes.count()-1, os.path.splitext(t)[0])
self.lstThemes.setCurrentIndex(self.lstThemes.findData(settings.fullScreenTheme))
# self.lstThemes.setCurrentText(settings.fullScreenTheme)
2015-06-21 07:35:57 +12:00
self.lstThemes.currentTextChanged.connect(self.setTheme)
2015-06-21 10:36:25 +12:00
self.lstThemes.setMaximumSize(QSize(300, QFontMetrics(qApp.font()).height()))
self.bottomPanel.layout().addWidget(QLabel(self.tr("Theme:"), self))
self.bottomPanel.layout().addWidget(self.lstThemes)
self.bottomPanel.layout().addStretch(1)
2016-02-07 00:34:22 +13:00
2015-06-21 10:36:25 +12:00
self.lblProgress = QLabel(self)
self.lblProgress.setMaximumSize(QSize(200, 14))
self.lblProgress.setMinimumSize(QSize(100, 14))
self.lblWC = QLabel(self)
self.bottomPanel.layout().addWidget(self.lblWC)
self.bottomPanel.layout().addWidget(self.lblProgress)
self.updateStatusBar()
2016-02-07 00:34:22 +13:00
2015-06-21 10:36:25 +12:00
self.bottomPanel.layout().addSpacing(24)
2016-02-07 00:34:22 +13:00
2015-06-23 20:50:19 +12:00
# Connection
self._index.model().dataChanged.connect(self.dataChanged)
2016-02-07 00:34:22 +13:00
# self.updateTheme()
2015-06-20 04:47:45 +12:00
self.showFullScreen()
2016-02-07 00:34:22 +13:00
# self.showMaximized()
# self.show()
def setLocked(self, val):
self._locked = val
self.btnClose.setVisible(not val)
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
def setTheme(self, themeName):
themeName = self.lstThemes.currentData()
2015-06-21 10:36:25 +12:00
settings.fullScreenTheme = themeName
2015-06-21 07:35:57 +12:00
self._theme = findThemePath(themeName)
2015-06-20 04:47:45 +12:00
self._themeDatas = loadThemeDatas(self._theme)
self.updateTheme()
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
def updateTheme(self):
# Reinit stored geometries for hiding widgets
self._geometries = {}
2015-06-20 04:47:45 +12:00
rect = self.geometry()
self._background = generateTheme(self._themeDatas, rect)
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
setThemeEditorDatas(self.editor, self._themeDatas, self._background, rect)
2016-02-07 00:34:22 +13:00
2015-06-21 07:35:57 +12:00
# Colors
if self._themeDatas["Foreground/Color"] == self._themeDatas["Background/Color"] or \
2016-02-07 00:34:22 +13:00
self._themeDatas["Foreground/Opacity"] < 5:
self._bgcolor = QColor(self._themeDatas["Text/Color"])
self._fgcolor = QColor(self._themeDatas["Background/Color"])
2015-06-21 07:35:57 +12:00
else:
self._bgcolor = QColor(self._themeDatas["Foreground/Color"])
self._bgcolor.setAlpha(self._themeDatas["Foreground/Opacity"] * 255 / 100)
self._fgcolor = QColor(self._themeDatas["Text/Color"])
2015-06-21 10:36:25 +12:00
if self._themeDatas["Text/Color"] == self._themeDatas["Foreground/Color"]:
self._fgcolor = QColor(self._themeDatas["Background/Color"])
2016-02-07 00:34:22 +13:00
2015-06-21 07:35:57 +12:00
# ScrollBar
2015-06-20 04:47:45 +12:00
r = self.editor.geometry()
w = qApp.style().pixelMetric(QStyle.PM_ScrollBarExtent)
r.setWidth(w)
2015-06-21 10:36:25 +12:00
r.moveRight(rect.right() - rect.left())
2015-06-20 04:47:45 +12:00
self.scrollBar.setGeometry(r)
2016-02-07 00:34:22 +13:00
# self.scrollBar.setVisible(False)
self.hideWidget(self.scrollBar)
2015-06-21 02:45:54 +12:00
p = self.scrollBar.palette()
b = QBrush(self._background.copy(self.scrollBar.geometry()))
p.setBrush(QPalette.Base, b)
self.scrollBar.setPalette(p)
2016-02-07 00:34:22 +13:00
2015-06-21 07:35:57 +12:00
self.scrollBar.setColor(self._bgcolor)
2016-02-07 00:34:22 +13:00
# Left Panel
r = self.locker.geometry()
r.moveTopLeft(QPoint(
2016-02-07 00:34:22 +13:00
0,
self.geometry().height() / 2 - r.height() / 2
))
self.leftPanel.setGeometry(r)
self.hideWidget(self.leftPanel)
self.leftPanel.setColor(self._bgcolor)
2016-02-07 00:34:22 +13:00
# Top / Bottom Panels
2015-06-21 07:35:57 +12:00
r = QRect(0, 0, 0, 24)
r.setWidth(rect.width())
2016-02-07 00:34:22 +13:00
# r.moveLeft(rect.center().x() - r.width() / 2)
2015-06-21 07:35:57 +12:00
self.topPanel.setGeometry(r)
2016-02-07 00:34:22 +13:00
# self.topPanel.setVisible(False)
self.hideWidget(self.topPanel)
2015-06-21 10:36:25 +12:00
r.moveBottom(rect.bottom() - rect.top())
2015-06-21 07:35:57 +12:00
self.bottomPanel.setGeometry(r)
2016-02-07 00:34:22 +13:00
# self.bottomPanel.setVisible(False)
self.hideWidget(self.bottomPanel)
2015-06-21 07:35:57 +12:00
self.topPanel.setColor(self._bgcolor)
self.bottomPanel.setColor(self._bgcolor)
2016-02-07 00:34:22 +13:00
2015-06-21 07:35:57 +12:00
# Lst theme
2016-02-07 00:34:22 +13:00
# p = self.lstThemes.palette()
2015-06-21 10:36:25 +12:00
p = self.palette()
2015-06-21 07:35:57 +12:00
p.setBrush(QPalette.Button, self._bgcolor)
p.setBrush(QPalette.ButtonText, self._fgcolor)
p.setBrush(QPalette.WindowText, self._fgcolor)
2016-02-07 00:34:22 +13:00
2015-06-21 10:36:25 +12:00
for panel in (self.bottomPanel, self.topPanel):
for i in range(panel.layout().count()):
item = panel.layout().itemAt(i)
2016-02-07 00:34:22 +13:00
if item.widget():
2015-06-21 10:36:25 +12:00
item.widget().setPalette(p)
2016-02-07 00:34:22 +13:00
# self.lstThemes.setPalette(p)
# self.lblWC.setPalette(p)
2015-06-21 07:35:57 +12:00
self.update()
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
def paintEvent(self, event):
if self._background:
painter = QPainter(self)
2015-06-21 02:45:54 +12:00
painter.setClipRegion(event.region())
2015-06-20 04:47:45 +12:00
painter.drawPixmap(event.rect(), self._background, event.rect())
painter.end()
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
def resizeEvent(self, event):
self.updateTheme()
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
def keyPressEvent(self, event):
if event.key() in [Qt.Key_Escape, Qt.Key_F11] and \
2016-02-07 00:34:22 +13:00
not self._locked:
2015-06-20 04:47:45 +12:00
self.close()
else:
QWidget.keyPressEvent(self, event)
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
def mouseMoveEvent(self, event):
r = self.geometry()
2016-02-07 00:34:22 +13:00
for w in [self.scrollBar, self.topPanel,
self.bottomPanel, self.leftPanel]:
2016-02-07 00:34:22 +13:00
# w.setVisible(w.geometry().contains(event.pos()))
if self._geometries[w].contains(event.pos()):
self.showWidget(w)
else:
self.hideWidget(w)
2016-02-07 00:34:22 +13:00
def hideWidget(self, widget):
if widget not in self._geometries:
self._geometries[widget] = widget.geometry()
if hasattr(widget, "_autoHide") and not widget._autoHide:
return
# Hides wiget in the bottom right corner
widget.move(self.geometry().bottomRight() + QPoint(1, 1))
2016-02-07 00:34:22 +13:00
def showWidget(self, widget):
if widget in self._geometries:
widget.move(self._geometries[widget].topLeft())
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
def eventFilter(self, obj, event):
2015-06-21 10:36:25 +12:00
if obj == self.editor and event.type() == QEvent.Enter:
2016-02-07 00:34:22 +13:00
for w in [self.scrollBar, self.topPanel,
self.bottomPanel, self.leftPanel]:
2016-02-07 00:34:22 +13:00
# w.setVisible(False)
self.hideWidget(w)
2015-06-20 04:47:45 +12:00
return QWidget.eventFilter(self, obj, event)
2016-02-07 00:34:22 +13:00
2015-06-21 10:36:25 +12:00
def dataChanged(self, topLeft, bottomRight):
# This is called sometimes after self has been destroyed. Don't know why.
if not self or not self._index:
2015-06-21 10:36:25 +12:00
return
if topLeft.row() <= self._index.row() <= bottomRight.row():
self.updateStatusBar()
2016-02-07 00:34:22 +13:00
2015-06-21 10:36:25 +12:00
def updateStatusBar(self):
if self._index:
item = self._index.internalPointer()
2016-02-07 00:34:22 +13:00
2015-06-21 10:36:25 +12:00
wc = item.data(Outline.wordCount.value)
goal = item.data(Outline.goal.value)
pg = item.data(Outline.goalPercentage.value)
2016-02-07 00:34:22 +13:00
2015-06-21 10:36:25 +12:00
if goal:
rect = self.lblProgress.geometry()
rect = QRect(QPoint(0, 0), rect.size())
self.px = QPixmap(rect.size())
self.px.fill(Qt.transparent)
p = QPainter(self.px)
drawProgress(p, rect, pg, 2)
p.end()
self.lblProgress.setPixmap(self.px)
self.lblWC.setText(self.tr("{} words / {}").format(wc, goal))
else:
2015-06-23 20:50:19 +12:00
self.lblProgress.hide()
self.lblWC.setText(self.tr("{} words").format(wc))
2016-02-07 00:34:22 +13:00
self.locker.setWordCount(wc)
# If there's a goal, then we update the locker target's number of word accordingly
# (also if there is a word count, we deduce it.
if goal and not self.locker.isLocked():
if wc and goal - wc > 0:
self.locker.spnWordTarget.setValue(goal - wc)
elif not wc:
self.locker.spnWordTarget.setValue(goal)
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
class myScrollBar(QScrollBar):
def __init__(self, color=Qt.white, parent=None):
QScrollBar.__init__(self, parent)
self._color = color
2016-02-07 00:34:22 +13:00
# self.setAttribute(Qt.WA_TranslucentBackground)
2015-06-21 02:45:54 +12:00
self.timer = QTimer()
2015-06-21 10:36:25 +12:00
self.timer.setInterval(500)
2015-06-21 02:45:54 +12:00
self.timer.setSingleShot(True)
self.timer.timeout.connect(lambda: self.parent().hideWidget(self))
2015-06-21 02:45:54 +12:00
self.valueChanged.connect(lambda v: self.timer.start())
self.valueChanged.connect(lambda: self.parent().showWidget(self))
2016-02-07 00:34:22 +13:00
2015-06-21 07:35:57 +12:00
def setColor(self, color):
self._color = color
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
def paintEvent(self, event):
opt = QStyleOptionSlider()
self.initStyleOption(opt)
style = qApp.style()
painter = QPainter(self)
2016-02-07 00:34:22 +13:00
2015-06-21 02:45:54 +12:00
# Background (Necessary with Qt 5.2 it seems, not with 5.4)
2016-02-07 00:34:22 +13:00
# painter.save()
# painter.setPen(Qt.NoPen)
# painter.setBrush(self.palette().brush(QPalette.Base))
# painter.drawRect(event.rect())
# painter.restore()
# slider
2015-06-20 04:47:45 +12:00
r = style.subControlRect(style.CC_ScrollBar, opt, style.SC_ScrollBarSlider)
painter.fillRect(r, self._color)
painter.end()
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
class myPanel(QWidget):
def __init__(self, color=Qt.white, vertical=False, parent=None):
2015-06-20 04:47:45 +12:00
QWidget.__init__(self, parent)
self._color = color
self.show()
self.setAttribute(Qt.WA_TranslucentBackground)
self._autoHide = True
if not vertical:
self.setLayout(QHBoxLayout())
else:
self.setLayout(QVBoxLayout())
2015-06-21 07:35:57 +12:00
self.layout().setContentsMargins(0, 0, 0, 0)
2016-02-07 00:34:22 +13:00
2015-06-21 07:35:57 +12:00
def setColor(self, color):
self._color = color
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
def paintEvent(self, event):
r = event.rect()
painter = QPainter(self)
2016-02-07 00:34:22 +13:00
painter.fillRect(r, self._color)
def setAutoHide(self, value):
self._autoHide = value
def mouseReleaseEvent(self, event):
if event.button() == Qt.RightButton:
m = QMenu()
a = QAction(self.tr("Auto-hide"), m)
a.setCheckable(True)
a.setChecked(self._autoHide)
a.toggled.connect(self.setAutoHide)
m.addAction(a)
m.popup(self.mapToGlobal(event.pos()))
self._m = m