manuskript/manuskript/ui/editors/themes.py

290 lines
9.9 KiB
Python
Raw Normal View History

#!/usr/bin/env python
2016-02-07 00:34:22 +13:00
# --!-- coding: utf8 --!--
2015-06-20 04:47:45 +12:00
# Lots of stuff from here comes from the excellet focuswriter.
2016-02-07 00:34:22 +13:00
import os
2015-06-21 02:45:54 +12:00
import re
2016-02-07 00:34:22 +13:00
from PyQt5.QtCore import QSettings, QRect, QSize, Qt, QPoint, QFile, QIODevice, QTextStream
from PyQt5.QtGui import QPixmap, QPainter, QColor, QBrush, QImage, QTextBlockFormat, QTextCharFormat, QFont, qGray
from PyQt5.QtWidgets import qApp, QFrame
from manuskript.functions import allPaths, appPath
from manuskript.ui.views.textEditView import textEditView
def loadThemeDatas(themeFile):
settings = QSettings(themeFile, QSettings.IniFormat)
_themeData = {}
2016-02-07 00:34:22 +13:00
# Theme name
_themeData["Name"] = getThemeName(themeFile)
2016-02-07 00:34:22 +13:00
# Window Background
loadThemeSetting(_themeData, settings, "Background/Color", "#000000")
loadThemeSetting(_themeData, settings, "Background/ImageFile", "")
loadThemeSetting(_themeData, settings, "Background/Type", 0)
2016-02-07 00:34:22 +13:00
# Text Background
loadThemeSetting(_themeData, settings, "Foreground/Color", "#ffffff")
loadThemeSetting(_themeData, settings, "Foreground/Opacity", 50)
loadThemeSetting(_themeData, settings, "Foreground/Margin", 40)
loadThemeSetting(_themeData, settings, "Foreground/Padding", 10)
loadThemeSetting(_themeData, settings, "Foreground/Position", 1)
loadThemeSetting(_themeData, settings, "Foreground/Rounding", 5)
loadThemeSetting(_themeData, settings, "Foreground/Width", 700)
2016-02-07 00:34:22 +13:00
# Text Options
loadThemeSetting(_themeData, settings, "Text/Color", "#ffffff")
loadThemeSetting(_themeData, settings, "Text/Font", qApp.font().toString())
loadThemeSetting(_themeData, settings, "Text/Misspelled", "#ff0000")
2016-02-07 00:34:22 +13:00
# Paragraph Options
loadThemeSetting(_themeData, settings, "Spacings/IndendFirstLine", False)
loadThemeSetting(_themeData, settings, "Spacings/LineSpacing", 100)
loadThemeSetting(_themeData, settings, "Spacings/ParagraphAbove", 0)
loadThemeSetting(_themeData, settings, "Spacings/ParagraphBelow", 0)
loadThemeSetting(_themeData, settings, "Spacings/TabWidth", 48)
2016-02-07 00:34:22 +13:00
return _themeData
2016-02-07 00:34:22 +13:00
def loadThemeSetting(datas, settings, key, default):
if settings.contains(key):
datas[key] = type(default)(settings.value(key))
else:
datas[key] = default
2016-02-07 00:34:22 +13:00
def getThemeName(theme):
settings = QSettings(theme, QSettings.IniFormat)
2016-02-07 00:34:22 +13:00
if settings.contains("Name"):
return settings.value("Name")
else:
return os.path.splitext(os.path.split(theme)[1])[0]
2016-02-07 00:34:22 +13:00
def themeTextRect(themeDatas, screenRect):
margin = themeDatas["Foreground/Margin"]
x = 0
y = margin
width = min(themeDatas["Foreground/Width"], screenRect.width() - 2 * margin)
height = screenRect.height() - 2 * margin
2016-02-07 00:34:22 +13:00
if themeDatas["Foreground/Position"] == 0: # Left
x = margin
elif themeDatas["Foreground/Position"] == 1: # Center
x = (screenRect.width() - width) / 2
elif themeDatas["Foreground/Position"] == 2: # Right
x = screenRect.width() - margin - width
elif themeDatas["Foreground/Position"] == 3: # Stretched
x = margin
width = screenRect.width() - 2 * margin
return QRect(x, y, width, height)
2016-02-07 00:34:22 +13:00
def createThemePreview(theme, screenRect, size=QSize(200, 120)):
if type(theme) == str and os.path.exists(theme):
# Theme is the path to an ini file
themeDatas = loadThemeDatas(theme)
else:
themeDatas = theme
2016-02-07 00:34:22 +13:00
pixmap = generateTheme(themeDatas, screenRect)
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
addThemePreviewText(pixmap, themeDatas, screenRect)
2016-02-07 00:34:22 +13:00
px = QPixmap(pixmap).scaled(size, Qt.KeepAspectRatio)
2016-02-07 00:34:22 +13:00
w = px.width() / 10
h = px.height() / 10
r = themeTextRect(themeDatas, screenRect)
2016-02-07 00:34:22 +13:00
painter = QPainter(px)
2016-02-07 00:34:22 +13:00
painter.drawPixmap(QRect(w, h, w * 4, h * 5), pixmap,
QRect(r.topLeft() - QPoint(w / 3, h / 3), QSize(w * 4, h * 5)))
painter.setPen(Qt.white)
2016-02-07 00:34:22 +13:00
painter.drawRect(QRect(w, h, w * 4, h * 5))
painter.end()
2016-02-07 00:34:22 +13:00
return px
2015-06-20 04:47:45 +12:00
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
def findThemePath(themeName):
2015-06-21 02:45:54 +12:00
p = findFirstFile(re.escape("{}.theme".format(themeName)), "resources/themes")
if not p:
return findFirstFile(".*\.theme", "resources/themes")
else:
return p
2015-06-20 04:47:45 +12:00
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
def findBackground(filename):
2015-06-21 02:45:54 +12:00
return findFirstFile(re.escape(filename), "resources/backgrounds")
2015-06-20 04:47:45 +12:00
2016-02-07 00:34:22 +13:00
2015-06-21 02:45:54 +12:00
def findFirstFile(regex, path="resources"):
2015-06-20 04:47:45 +12:00
paths = allPaths(path)
for p in paths:
lst = os.listdir(p)
for l in lst:
2015-06-21 02:45:54 +12:00
if re.match(regex, l):
2015-06-20 04:47:45 +12:00
return os.path.join(p, l)
2016-02-07 00:34:22 +13:00
def generateTheme(themeDatas, screenRect):
# Window Background
px = QPixmap(screenRect.size())
px.fill(QColor(themeDatas["Background/Color"]))
2016-02-07 00:34:22 +13:00
painter = QPainter(px)
if themeDatas["Background/ImageFile"]:
path = findBackground(themeDatas["Background/ImageFile"])
_type = themeDatas["Background/Type"]
if path and _type > 0:
2016-02-07 00:34:22 +13:00
if _type == 1: # Tiled
painter.fillRect(screenRect, QBrush(QImage(path)))
else:
img = QImage(path)
scaled = img.size()
2016-02-07 00:34:22 +13:00
if _type == 3: # Stretched
scaled.scale(screenRect.size(), Qt.IgnoreAspectRatio)
2016-02-07 00:34:22 +13:00
elif _type == 4: # Scaled
scaled.scale(screenRect.size(), Qt.KeepAspectRatio)
2016-02-07 00:34:22 +13:00
elif _type == 5: # Zoomed
scaled.scale(screenRect.size(), Qt.KeepAspectRatioByExpanding)
2016-02-07 00:34:22 +13:00
painter.drawImage((screenRect.width() - scaled.width()) / 2,
(screenRect.height() - scaled.height()) / 2, img.scaled(scaled))
# Text Background
textRect = themeTextRect(themeDatas, screenRect)
2016-02-07 00:34:22 +13:00
painter.save()
color = QColor(themeDatas["Foreground/Color"])
color.setAlpha(themeDatas["Foreground/Opacity"] * 255 / 100)
painter.setBrush(color)
painter.setPen(Qt.NoPen)
r = themeDatas["Foreground/Rounding"]
painter.drawRoundedRect(textRect, r, r)
painter.restore()
2016-02-07 00:34:22 +13:00
painter.end()
2015-06-20 04:47:45 +12:00
return px
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
def themeEditorGeometry(themeDatas, textRect):
padding = themeDatas["Foreground/Padding"]
x = textRect.x() + padding
y = textRect.y() + padding + themeDatas["Spacings/ParagraphAbove"]
width = textRect.width() - 2 * padding
height = textRect.height() - 2 * padding - themeDatas["Spacings/ParagraphAbove"]
2015-06-20 04:47:45 +12:00
return x, y, width, height
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
def getThemeBlockFormat(themeDatas):
bf = QTextBlockFormat()
bf.setLineHeight(themeDatas["Spacings/LineSpacing"], QTextBlockFormat.ProportionalHeight)
bf.setTextIndent(themeDatas["Spacings/TabWidth"] * 1 if themeDatas["Spacings/IndendFirstLine"] else 0)
bf.setTopMargin(themeDatas["Spacings/ParagraphAbove"])
bf.setBottomMargin(themeDatas["Spacings/ParagraphBelow"])
2015-06-20 04:47:45 +12:00
return bf
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
def setThemeEditorDatas(editor, themeDatas, pixmap, screenRect):
textRect = themeTextRect(themeDatas, screenRect)
x, y, width, height = themeEditorGeometry(themeDatas, textRect)
editor.setGeometry(x, y, width, height)
2016-02-07 00:34:22 +13:00
# p = editor.palette()
##p.setBrush(QPalette.Base, QBrush(pixmap.copy(x, y, width, height)))
2016-02-07 00:34:22 +13:00
# p.setBrush(QPalette.Base, QColor(Qt.transparent))
# p.setColor(QPalette.Text, QColor(themeDatas["Text/Color"]))
# p.setColor(QPalette.Highlight, QColor(themeDatas["Text/Color"]))
# p.setColor(QPalette.HighlightedText, Qt.black if qGray(QColor(themeDatas["Text/Color"]).rgb()) > 127 else Qt.white)
# editor.setPalette(p)
2015-06-20 04:47:45 +12:00
editor.setAttribute(Qt.WA_NoSystemBackground, True)
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
bf = getThemeBlockFormat(themeDatas)
editor.setDefaultBlockFormat(bf)
2016-02-07 00:34:22 +13:00
# b = editor.document().firstBlock()
# cursor = editor.textCursor()
# cursor.setBlockFormat(bf)
# while b.isValid():
# bf2 = b.blockFormat()
# bf2.merge(bf)
# cursor.setPosition(b.position())
##cursor.setPosition(b.position(), QTextCursor.KeepAnchor)
# cursor.setBlockFormat(bf2)
# b = b.next()
2015-06-20 04:47:45 +12:00
editor.setTabStopWidth(themeDatas["Spacings/TabWidth"])
editor.document().setIndentWidth(themeDatas["Spacings/TabWidth"])
2016-02-07 00:34:22 +13:00
2015-06-25 23:41:55 +12:00
editor.highlighter.setMisspelledColor(QColor(themeDatas["Text/Misspelled"]))
2016-02-07 00:34:22 +13:00
2015-06-25 23:41:55 +12:00
cf = QTextCharFormat()
2016-02-07 00:34:22 +13:00
# f = QFont()
# f.fromString(themeDatas["Text/Font"])
# cf.setFont(f)
editor.highlighter.setDefaultCharFormat(cf)
f = QFont()
f.fromString(themeDatas["Text/Font"])
2016-02-07 00:34:22 +13:00
# editor.setFont(f)
editor.setStyleSheet("""
background: transparent;
color: {foreground};
font-family: {ff};
font-size: {fs};
selection-color: {sc};
selection-background-color: {sbc};
""".format(
foreground=themeDatas["Text/Color"],
ff=f.family(),
fs="{}pt".format(str(f.pointSize())),
sc="black" if qGray(QColor(themeDatas["Text/Color"]).rgb()) > 127 else "white",
sbc=themeDatas["Text/Color"],
2016-02-07 00:34:22 +13:00
)
)
2015-06-26 03:06:07 +12:00
editor._fromTheme = True
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
def addThemePreviewText(pixmap, themeDatas, screenRect):
# Text
2015-06-25 20:01:28 +12:00
previewText = textEditView(highlighting=True)
2015-06-20 04:47:45 +12:00
previewText.setFrameStyle(QFrame.NoFrame)
previewText.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
previewText.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
2015-06-21 02:45:54 +12:00
f = QFile(appPath("resources/themes/preview.txt"))
f.open(QIODevice.ReadOnly)
previewText.setPlainText(QTextStream(f).readAll())
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
setThemeEditorDatas(previewText, themeDatas, pixmap, screenRect)
2016-02-07 00:34:22 +13:00
2015-06-20 04:47:45 +12:00
previewText.render(pixmap, previewText.pos())
2016-02-07 00:34:22 +13:00
## Text Background
##themeDatas["Foreground/Color"]
##themeDatas["Foreground/Opacity"]
##themeDatas["Foreground/Margin"]
##themeDatas["Foreground/Padding"]
##themeDatas["Foreground/Position"]
##themeDatas["Foreground/Rounding"]
##themeDatas["Foreground/Width"]
2016-02-07 00:34:22 +13:00
## Text Options
##themeDatas["Text/Color"]
##themeDatas["Text/Font"]
2016-02-07 00:34:22 +13:00
# themeDatas["Text/Misspelled"]
## Paragraph Options
##themeDatas["Spacings/IndendFirstLine"]
##themeDatas["Spacings/LineSpacing"]
##themeDatas["Spacings/ParagraphAbove"]
##themeDatas["Spacings/ParagraphBelow"]
2016-02-07 00:34:22 +13:00
##themeDatas["Spacings/TabWidth"]