mirror of
https://github.com/olivierkes/manuskript.git
synced 2024-05-15 10:22:26 +12:00
8d356c52ce
See issue #52. Enable selection of background color in addition to background image for index cards. This setting is accessed from the manuskript menu **Edit -> Settings -> Views -> Index cards**. Keep initial default of "writingdesk" background image for Index cards. Also update comments for functions to better describe how these work.
748 lines
34 KiB
Python
748 lines
34 KiB
Python
#!/usr/bin/env python
|
|
# --!-- coding: utf8 --!--
|
|
import os
|
|
from collections import OrderedDict
|
|
|
|
from PyQt5.QtCore import QSize, QSettings, QRegExp, QTranslator, QObject
|
|
from PyQt5.QtCore import Qt
|
|
from PyQt5.QtGui import QIntValidator, QIcon, QFont, QColor, QPixmap, QStandardItem, QPainter
|
|
from PyQt5.QtWidgets import QStyleFactory, QWidget, QStyle, QColorDialog, QListWidgetItem, QMessageBox
|
|
from PyQt5.QtWidgets import qApp
|
|
|
|
# Spell checker support
|
|
from manuskript import settings
|
|
from manuskript.enums import Outline
|
|
from manuskript.functions import allPaths, iconColor, writablePath, appPath, findWidgetsOfClass
|
|
from manuskript.functions import mainWindow, findBackground
|
|
from manuskript.ui.editors.tabSplitter import tabSplitter
|
|
from manuskript.ui.editors.themes import createThemePreview
|
|
from manuskript.ui.editors.themes import getThemeName
|
|
from manuskript.ui.editors.themes import loadThemeDatas
|
|
from manuskript.ui.settings_ui import Ui_Settings
|
|
from manuskript.ui.views.outlineView import outlineView
|
|
from manuskript.ui.views.textEditView import textEditView
|
|
from manuskript.ui.welcome import welcome
|
|
|
|
try:
|
|
import enchant
|
|
except ImportError:
|
|
enchant = None
|
|
|
|
|
|
class settingsWindow(QWidget, Ui_Settings):
|
|
def __init__(self, mainWindow):
|
|
QWidget.__init__(self)
|
|
self.setupUi(self)
|
|
self.mw = mainWindow
|
|
|
|
# UI
|
|
for i in range(self.lstMenu.count()):
|
|
item = self.lstMenu.item(i)
|
|
item.setSizeHint(QSize(item.sizeHint().width(), 42))
|
|
item.setTextAlignment(Qt.AlignCenter)
|
|
self.lstMenu.setMaximumWidth(150)
|
|
|
|
# General
|
|
self.cmbStyle.addItems(list(QStyleFactory.keys()))
|
|
self.cmbStyle.setCurrentIndex([i.lower() for i in list(QStyleFactory.keys())].index(qApp.style().objectName()))
|
|
self.cmbStyle.currentIndexChanged[str].connect(self.setStyle)
|
|
|
|
self.cmbTranslation.clear()
|
|
tr = OrderedDict()
|
|
tr["English"] = ""
|
|
tr["Français"] = "manuskript_fr.qm"
|
|
tr["Español"] = "manuskript_es.qm"
|
|
|
|
for name in tr:
|
|
self.cmbTranslation.addItem(name, tr[name])
|
|
|
|
sttgs = QSettings(qApp.organizationName(), qApp.applicationName())
|
|
if sttgs.contains("applicationTranslation") and sttgs.value("applicationTranslation") in tr.values():
|
|
self.cmbTranslation.setCurrentText([i for i in tr if tr[i] == sttgs.value("applicationTranslation")][0])
|
|
|
|
self.cmbTranslation.currentIndexChanged.connect(self.setTranslation)
|
|
|
|
self.txtAutoSave.setValidator(QIntValidator(0, 999, self))
|
|
self.txtAutoSaveNoChanges.setValidator(QIntValidator(0, 999, self))
|
|
self.chkAutoSave.setChecked(settings.autoSave)
|
|
self.chkAutoSaveNoChanges.setChecked(settings.autoSaveNoChanges)
|
|
self.txtAutoSave.setText(str(settings.autoSaveDelay))
|
|
self.txtAutoSaveNoChanges.setText(str(settings.autoSaveNoChangesDelay))
|
|
self.chkSaveOnQuit.setChecked(settings.saveOnQuit)
|
|
self.chkSaveToZip.setChecked(settings.saveToZip)
|
|
self.chkAutoSave.stateChanged.connect(self.saveSettingsChanged)
|
|
self.chkAutoSaveNoChanges.stateChanged.connect(self.saveSettingsChanged)
|
|
self.chkSaveOnQuit.stateChanged.connect(self.saveSettingsChanged)
|
|
self.chkSaveToZip.stateChanged.connect(self.saveSettingsChanged)
|
|
self.txtAutoSave.textEdited.connect(self.saveSettingsChanged)
|
|
self.txtAutoSaveNoChanges.textEdited.connect(self.saveSettingsChanged)
|
|
autoLoad, last = self.mw.welcome.getAutoLoadValues()
|
|
self.chkAutoLoad.setChecked(autoLoad)
|
|
self.chkAutoLoad.stateChanged.connect(self.saveSettingsChanged)
|
|
|
|
# Revisions
|
|
opt = settings.revisions
|
|
self.chkRevisionsKeep.setChecked(opt["keep"])
|
|
self.chkRevisionsKeep.stateChanged.connect(self.revisionsSettingsChanged)
|
|
self.chkRevisionRemove.setChecked(opt["smartremove"])
|
|
self.chkRevisionRemove.toggled.connect(self.revisionsSettingsChanged)
|
|
self.spnRevisions10Mn.setValue(60 / opt["rules"][10 * 60])
|
|
self.spnRevisions10Mn.valueChanged.connect(self.revisionsSettingsChanged)
|
|
self.spnRevisionsHour.setValue(60 * 10 / opt["rules"][60 * 60])
|
|
self.spnRevisionsHour.valueChanged.connect(self.revisionsSettingsChanged)
|
|
self.spnRevisionsDay.setValue(60 * 60 / opt["rules"][60 * 60 * 24])
|
|
self.spnRevisionsDay.valueChanged.connect(self.revisionsSettingsChanged)
|
|
self.spnRevisionsMonth.setValue(60 * 60 * 24 / opt["rules"][60 * 60 * 24 * 30])
|
|
self.spnRevisionsMonth.valueChanged.connect(self.revisionsSettingsChanged)
|
|
self.spnRevisionsEternity.setValue(60 * 60 * 24 * 7 / opt["rules"][None])
|
|
self.spnRevisionsEternity.valueChanged.connect(self.revisionsSettingsChanged)
|
|
|
|
# Views
|
|
self.tabViews.setCurrentIndex(0)
|
|
lst = ["Nothing", "POV", "Label", "Progress", "Compile"]
|
|
for cmb in self.viewSettingsDatas():
|
|
item, part = self.viewSettingsDatas()[cmb]
|
|
cmb.setCurrentIndex(lst.index(settings.viewSettings[item][part]))
|
|
cmb.currentIndexChanged.connect(self.viewSettingsChanged)
|
|
|
|
for chk in self.outlineColumnsData():
|
|
col = self.outlineColumnsData()[chk]
|
|
chk.setChecked(col in settings.outlineViewColumns)
|
|
chk.stateChanged.connect(self.outlineColumnsChanged)
|
|
|
|
self.chkOutlinePOV.setVisible(settings.viewMode != "simple") # Hides checkbox if non-fiction view mode
|
|
|
|
for item, what, value in [
|
|
(self.rdoTreeItemCount, "InfoFolder", "Count"),
|
|
(self.rdoTreeWC, "InfoFolder", "WC"),
|
|
(self.rdoTreeProgress, "InfoFolder", "Progress"),
|
|
(self.rdoTreeSummary, "InfoFolder", "Summary"),
|
|
(self.rdoTreeNothing, "InfoFolder", "Nothing"),
|
|
(self.rdoTreeTextWC, "InfoText", "WC"),
|
|
(self.rdoTreeTextProgress, "InfoText", "Progress"),
|
|
(self.rdoTreeTextSummary, "InfoText", "Summary"),
|
|
(self.rdoTreeTextNothing, "InfoText", "Nothing"),
|
|
]:
|
|
item.setChecked(settings.viewSettings["Tree"][what] == value)
|
|
item.toggled.connect(self.treeViewSettignsChanged)
|
|
|
|
self.populatesCmbBackgrounds(self.cmbCorkImage)
|
|
self.setCorkImageDefault()
|
|
self.updateCorkColor()
|
|
self.cmbCorkImage.currentIndexChanged.connect(self.setCorkBackground)
|
|
self.btnCorkColor.clicked.connect(self.setCorkColor)
|
|
|
|
# Text editor
|
|
opt = settings.textEditor
|
|
self.setButtonColor(self.btnEditorFontColor, opt["fontColor"])
|
|
self.btnEditorFontColor.clicked.connect(self.choseEditorFontColor)
|
|
self.setButtonColor(self.btnEditorMisspelledColor, opt["misspelled"])
|
|
self.btnEditorMisspelledColor.clicked.connect(self.choseEditorMisspelledColor)
|
|
self.setButtonColor(self.btnEditorBackgroundColor, opt["background"])
|
|
self.btnEditorBackgroundColor.clicked.connect(self.choseEditorBackgroundColor)
|
|
f = QFont()
|
|
f.fromString(opt["font"])
|
|
self.cmbEditorFontFamily.setCurrentFont(f)
|
|
self.cmbEditorFontFamily.currentFontChanged.connect(self.updateEditorSettings)
|
|
self.spnEditorFontSize.setValue(f.pointSize())
|
|
self.spnEditorFontSize.valueChanged.connect(self.updateEditorSettings)
|
|
self.cmbEditorLineSpacing.setCurrentIndex(
|
|
0 if opt["lineSpacing"] == 100 else
|
|
1 if opt["lineSpacing"] == 150 else
|
|
2 if opt["lineSpacing"] == 200 else
|
|
3)
|
|
self.cmbEditorLineSpacing.currentIndexChanged.connect(self.updateEditorSettings)
|
|
self.spnEditorLineSpacing.setValue(opt["lineSpacing"])
|
|
self.spnEditorLineSpacing.valueChanged.connect(self.updateEditorSettings)
|
|
self.spnEditorLineSpacing.setEnabled(opt["lineSpacing"] not in [100, 150, 200])
|
|
self.spnEditorLineSpacing.valueChanged.connect(self.updateEditorSettings)
|
|
self.spnEditorTabWidth.setValue(opt["tabWidth"])
|
|
self.spnEditorTabWidth.valueChanged.connect(self.updateEditorSettings)
|
|
self.chkEditorIndent.setChecked(opt["indent"])
|
|
self.chkEditorIndent.stateChanged.connect(self.updateEditorSettings)
|
|
self.spnEditorParaAbove.setValue(opt["spacingAbove"])
|
|
self.spnEditorParaAbove.valueChanged.connect(self.updateEditorSettings)
|
|
self.spnEditorParaBelow.setValue(opt["spacingBelow"])
|
|
self.spnEditorParaBelow.valueChanged.connect(self.updateEditorSettings)
|
|
|
|
# Labels
|
|
self.lstLabels.setModel(self.mw.mdlLabels)
|
|
self.lstLabels.setRowHidden(0, True)
|
|
self.lstLabels.clicked.connect(self.updateLabelColor)
|
|
self.btnLabelAdd.clicked.connect(self.addLabel)
|
|
self.btnLabelRemove.clicked.connect(self.removeLabel)
|
|
self.btnLabelColor.clicked.connect(self.setLabelColor)
|
|
|
|
# Statuses
|
|
self.lstStatus.setModel(self.mw.mdlStatus)
|
|
self.lstStatus.setRowHidden(0, True)
|
|
self.btnStatusAdd.clicked.connect(self.addStatus)
|
|
self.btnStatusRemove.clicked.connect(self.removeStatus)
|
|
|
|
# Fullscreen
|
|
self._editingTheme = None
|
|
self.btnThemeEditOK.setIcon(qApp.style().standardIcon(QStyle.SP_DialogApplyButton))
|
|
self.btnThemeEditOK.clicked.connect(self.saveTheme)
|
|
self.btnThemeEditCancel.setIcon(qApp.style().standardIcon(QStyle.SP_DialogCancelButton))
|
|
self.btnThemeEditCancel.clicked.connect(self.cancelEdit)
|
|
self.cmbThemeEdit.currentIndexChanged.connect(self.themeEditStack.setCurrentIndex)
|
|
self.cmbThemeEdit.setCurrentIndex(0)
|
|
self.cmbThemeEdit.currentIndexChanged.emit(0)
|
|
self.themeStack.setCurrentIndex(0)
|
|
self.lstThemes.currentItemChanged.connect(self.themeSelected)
|
|
self.populatesThemesList()
|
|
self.btnThemeAdd.clicked.connect(self.newTheme)
|
|
self.btnThemeEdit.clicked.connect(self.editTheme)
|
|
self.btnThemeRemove.clicked.connect(self.removeTheme)
|
|
|
|
def setTab(self, tab):
|
|
|
|
tabs = {
|
|
"General": 0,
|
|
"Views": 1,
|
|
"Labels": 2,
|
|
"Status": 3,
|
|
"Fullscreen": 4,
|
|
}
|
|
|
|
if tab in tabs:
|
|
self.lstMenu.setCurrentRow(tabs[tab])
|
|
else:
|
|
self.lstMenu.setCurrentRow(tab)
|
|
####################################################################################################
|
|
# GENERAL #
|
|
####################################################################################################
|
|
|
|
def setStyle(self, style):
|
|
# Save style to Qt Settings
|
|
sttgs = QSettings(qApp.organizationName(), qApp.applicationName())
|
|
sttgs.setValue("applicationStyle", style)
|
|
qApp.setStyle(style)
|
|
|
|
def setTranslation(self, index):
|
|
path = self.cmbTranslation.currentData()
|
|
# Save settings
|
|
sttgs = QSettings(qApp.organizationName(), qApp.applicationName())
|
|
sttgs.setValue("applicationTranslation", path)
|
|
|
|
# QMessageBox.information(self, "Warning", "You'll have to restart manuskript.")
|
|
|
|
def saveSettingsChanged(self):
|
|
if self.txtAutoSave.text() in ["", "0"]:
|
|
self.txtAutoSave.setText("1")
|
|
if self.txtAutoSaveNoChanges.text() in ["", "0"]:
|
|
self.txtAutoSaveNoChanges.setText("1")
|
|
|
|
sttgs = QSettings()
|
|
sttgs.setValue("autoLoad", True if self.chkAutoLoad.checkState() else False)
|
|
sttgs.sync()
|
|
|
|
settings.autoSave = True if self.chkAutoSave.checkState() else False
|
|
settings.autoSaveNoChanges = True if self.chkAutoSaveNoChanges.checkState() else False
|
|
settings.saveOnQuit = True if self.chkSaveOnQuit.checkState() else False
|
|
settings.saveToZip = True if self.chkSaveToZip.checkState() else False
|
|
settings.autoSaveDelay = int(self.txtAutoSave.text())
|
|
settings.autoSaveNoChangesDelay = int(self.txtAutoSaveNoChanges.text())
|
|
self.mw.saveTimer.setInterval(settings.autoSaveDelay * 60 * 1000)
|
|
self.mw.saveTimerNoChanges.setInterval(settings.autoSaveNoChangesDelay * 1000)
|
|
|
|
####################################################################################################
|
|
# REVISION #
|
|
####################################################################################################
|
|
|
|
def revisionsSettingsChanged(self):
|
|
opt = settings.revisions
|
|
opt["keep"] = True if self.chkRevisionsKeep.checkState() else False
|
|
opt["smartremove"] = self.chkRevisionRemove.isChecked()
|
|
opt["rules"][10 * 60] = 60 / self.spnRevisions10Mn.value()
|
|
opt["rules"][60 * 60] = 60 * 10 / self.spnRevisionsHour.value()
|
|
opt["rules"][60 * 60 * 24] = 60 * 60 / self.spnRevisionsDay.value()
|
|
opt["rules"][60 * 60 * 24 * 30] = 60 * 60 * 24 / self.spnRevisionsMonth.value()
|
|
opt["rules"][None] = 60 * 60 * 24 * 7 / self.spnRevisionsEternity.value()
|
|
|
|
####################################################################################################
|
|
# VIEWS #
|
|
####################################################################################################
|
|
|
|
def viewSettingsDatas(self):
|
|
return {
|
|
self.cmbTreeIcon: ("Tree", "Icon"),
|
|
self.cmbTreeText: ("Tree", "Text"),
|
|
self.cmbTreeBackground: ("Tree", "Background"),
|
|
self.cmbOutlineIcon: ("Outline", "Icon"),
|
|
self.cmbOutlineText: ("Outline", "Text"),
|
|
self.cmbOutlineBackground: ("Outline", "Background"),
|
|
self.cmbCorkIcon: ("Cork", "Icon"),
|
|
self.cmbCorkText: ("Cork", "Text"),
|
|
self.cmbCorkBackground: ("Cork", "Background"),
|
|
self.cmbCorkBorder: ("Cork", "Border"),
|
|
self.cmbCorkCorner: ("Cork", "Corner")
|
|
}
|
|
|
|
def viewSettingsChanged(self):
|
|
cmb = self.sender()
|
|
lst = ["Nothing", "POV", "Label", "Progress", "Compile"]
|
|
item, part = self.viewSettingsDatas()[cmb]
|
|
element = lst[cmb.currentIndex()]
|
|
self.mw.setViewSettings(item, part, element)
|
|
self.mw.generateViewMenu()
|
|
|
|
def outlineColumnsData(self):
|
|
return {
|
|
self.chkOutlineTitle: Outline.title.value,
|
|
self.chkOutlinePOV: Outline.POV.value,
|
|
self.chkOutlineLabel: Outline.label.value,
|
|
self.chkOutlineStatus: Outline.status.value,
|
|
self.chkOutlineCompile: Outline.compile.value,
|
|
self.chkOutlineWordCount: Outline.wordCount.value,
|
|
self.chkOutlineGoal: Outline.goal.value,
|
|
self.chkOutlinePercentage: Outline.goalPercentage.value,
|
|
}
|
|
|
|
def outlineColumnsChanged(self):
|
|
chk = self.sender()
|
|
val = True if chk.checkState() else False
|
|
col = self.outlineColumnsData()[chk]
|
|
if val and not col in settings.outlineViewColumns:
|
|
settings.outlineViewColumns.append(col)
|
|
elif not val and col in settings.outlineViewColumns:
|
|
settings.outlineViewColumns.remove(col)
|
|
|
|
# Update views
|
|
for w in findWidgetsOfClass(outlineView):
|
|
w.hideColumns()
|
|
|
|
def treeViewSettignsChanged(self):
|
|
for item, what, value in [
|
|
(self.rdoTreeItemCount, "InfoFolder", "Count"),
|
|
(self.rdoTreeWC, "InfoFolder", "WC"),
|
|
(self.rdoTreeProgress, "InfoFolder", "Progress"),
|
|
(self.rdoTreeSummary, "InfoFolder", "Summary"),
|
|
(self.rdoTreeNothing, "InfoFolder", "Nothing"),
|
|
(self.rdoTreeTextWC, "InfoText", "WC"),
|
|
(self.rdoTreeTextProgress, "InfoText", "Progress"),
|
|
(self.rdoTreeTextSummary, "InfoText", "Summary"),
|
|
(self.rdoTreeTextNothing, "InfoText", "Nothing"),
|
|
]:
|
|
if item.isChecked():
|
|
settings.viewSettings["Tree"][what] = value
|
|
|
|
self.mw.treeRedacOutline.viewport().update()
|
|
|
|
def setCorkColor(self):
|
|
color = QColor(settings.corkBackground["color"])
|
|
self.colorDialog = QColorDialog(color, self)
|
|
color = self.colorDialog.getColor(color)
|
|
if color.isValid():
|
|
settings.corkBackground["color"] = color.name()
|
|
self.updateCorkColor()
|
|
# Update Cork view
|
|
self.mw.mainEditor.updateCorkBackground()
|
|
|
|
def updateCorkColor(self):
|
|
self.btnCorkColor.setStyleSheet("background:{};".format(settings.corkBackground["color"]))
|
|
|
|
def setCorkBackground(self, i):
|
|
img = self.cmbCorkImage.itemData(i)
|
|
img = os.path.basename(img)
|
|
if img:
|
|
settings.corkBackground["image"] = img
|
|
else:
|
|
settings.corkBackground["image"] = ""
|
|
# Update Cork view
|
|
self.mw.mainEditor.updateCorkBackground()
|
|
|
|
def populatesCmbBackgrounds(self, cmb):
|
|
# self.cmbDelegate = cmbPixmapDelegate()
|
|
# self.cmbCorkImage.setItemDelegate(self.cmbDelegate)
|
|
|
|
paths = allPaths("resources/backgrounds")
|
|
cmb.clear()
|
|
cmb.addItem(QIcon.fromTheme("list-remove"), "", "")
|
|
for p in paths:
|
|
lst = os.listdir(p)
|
|
for l in lst:
|
|
if l.lower()[-4:] in [".jpg", ".png"] or \
|
|
l.lower()[-5:] in [".jpeg"]:
|
|
px = QPixmap(os.path.join(p, l)).scaled(128, 64, Qt.KeepAspectRatio)
|
|
cmb.addItem(QIcon(px), "", os.path.join(p, l))
|
|
|
|
cmb.setIconSize(QSize(128, 64))
|
|
|
|
def setCorkImageDefault(self):
|
|
if settings.corkBackground["image"] != "":
|
|
i = self.cmbCorkImage.findData(findBackground(settings.corkBackground["image"]))
|
|
if i != -1:
|
|
self.cmbCorkImage.setCurrentIndex(i)
|
|
|
|
####################################################################################################
|
|
# VIEWS / EDITOR
|
|
####################################################################################################
|
|
|
|
def updateEditorSettings(self):
|
|
# Store settings
|
|
f = self.cmbEditorFontFamily.currentFont()
|
|
f.setPointSize(self.spnEditorFontSize.value())
|
|
settings.textEditor["font"] = f.toString()
|
|
settings.textEditor["lineSpacing"] = \
|
|
100 if self.cmbEditorLineSpacing.currentIndex() == 0 else \
|
|
150 if self.cmbEditorLineSpacing.currentIndex() == 1 else \
|
|
200 if self.cmbEditorLineSpacing.currentIndex() == 2 else \
|
|
self.spnEditorLineSpacing.value()
|
|
self.spnEditorLineSpacing.setEnabled(self.cmbEditorLineSpacing.currentIndex() == 3)
|
|
settings.textEditor["tabWidth"] = self.spnEditorTabWidth.value()
|
|
settings.textEditor["indent"] = True if self.chkEditorIndent.checkState() else False
|
|
settings.textEditor["spacingAbove"] = self.spnEditorParaAbove.value()
|
|
settings.textEditor["spacingBelow"] = self.spnEditorParaBelow.value()
|
|
|
|
# Update font and defaultBlockFormat to all textEditView. Drastically.
|
|
for w in mainWindow().findChildren(textEditView, QRegExp(".*")):
|
|
w.loadFontSettings()
|
|
|
|
# Update background color in all tabSplitter (tabs)
|
|
for w in mainWindow().findChildren(tabSplitter, QRegExp(".*")):
|
|
w.updateStyleSheet()
|
|
|
|
def choseEditorFontColor(self):
|
|
color = settings.textEditor["fontColor"]
|
|
self.colorDialog = QColorDialog(QColor(color), self)
|
|
color = self.colorDialog.getColor(QColor(color))
|
|
if color.isValid():
|
|
settings.textEditor["fontColor"] = color.name()
|
|
self.setButtonColor(self.btnEditorFontColor, color.name())
|
|
self.updateEditorSettings()
|
|
|
|
def choseEditorMisspelledColor(self):
|
|
color = settings.textEditor["misspelled"]
|
|
self.colorDialog = QColorDialog(QColor(color), self)
|
|
color = self.colorDialog.getColor(QColor(color))
|
|
if color.isValid():
|
|
settings.textEditor["misspelled"] = color.name()
|
|
self.setButtonColor(self.btnEditorMisspelledColor, color.name())
|
|
self.updateEditorSettings()
|
|
|
|
def choseEditorBackgroundColor(self):
|
|
color = settings.textEditor["background"]
|
|
self.colorDialog = QColorDialog(QColor(color), self)
|
|
color = self.colorDialog.getColor(QColor(color))
|
|
if color.isValid():
|
|
settings.textEditor["background"] = color.name()
|
|
self.setButtonColor(self.btnEditorBackgroundColor, color.name())
|
|
self.updateEditorSettings()
|
|
|
|
####################################################################################################
|
|
# STATUS #
|
|
####################################################################################################
|
|
|
|
def addStatus(self):
|
|
self.mw.mdlStatus.appendRow(QStandardItem(self.tr("New status")))
|
|
|
|
def removeStatus(self):
|
|
for i in self.lstStatus.selectedIndexes():
|
|
self.mw.mdlStatus.removeRows(i.row(), 1)
|
|
|
|
####################################################################################################
|
|
# LABELS #
|
|
####################################################################################################
|
|
|
|
def updateLabelColor(self, index):
|
|
# px = QPixmap(64, 64)
|
|
# px.fill(iconColor(self.mw.mdlLabels.item(index.row()).icon()))
|
|
# self.btnLabelColor.setIcon(QIcon(px))
|
|
self.btnLabelColor.setStyleSheet(
|
|
"background:{};".format(iconColor(self.mw.mdlLabels.item(index.row()).icon()).name()))
|
|
self.btnLabelColor.setEnabled(True)
|
|
|
|
def addLabel(self):
|
|
px = QPixmap(32, 32)
|
|
px.fill(Qt.transparent)
|
|
self.mw.mdlLabels.appendRow(QStandardItem(QIcon(px), self.tr("New label")))
|
|
|
|
def removeLabel(self):
|
|
for i in self.lstLabels.selectedIndexes():
|
|
self.mw.mdlLabels.removeRows(i.row(), 1)
|
|
|
|
def setLabelColor(self):
|
|
index = self.lstLabels.currentIndex()
|
|
color = iconColor(self.mw.mdlLabels.item(index.row()).icon())
|
|
self.colorDialog = QColorDialog(color, self)
|
|
color = self.colorDialog.getColor(color)
|
|
if color.isValid():
|
|
px = QPixmap(32, 32)
|
|
px.fill(color)
|
|
self.mw.mdlLabels.item(index.row()).setIcon(QIcon(px))
|
|
self.updateLabelColor(index)
|
|
|
|
####################################################################################################
|
|
# FULLSCREEN #
|
|
####################################################################################################
|
|
|
|
def themeSelected(self, current, previous):
|
|
if current:
|
|
# UI updates
|
|
self.btnThemeEdit.setEnabled(current.data(Qt.UserRole + 1))
|
|
self.btnThemeRemove.setEnabled(current.data(Qt.UserRole + 1))
|
|
# Save settings
|
|
theme = current.data(Qt.UserRole)
|
|
settings.fullScreenTheme = os.path.splitext(os.path.split(theme)[1])[0]
|
|
else:
|
|
# UI updates
|
|
self.btnThemeEdit.setEnabled(False)
|
|
self.btnThemeRemove.setEnabled(False)
|
|
|
|
def newTheme(self):
|
|
path = writablePath("resources/themes")
|
|
name = self.tr("newtheme")
|
|
if os.path.exists(os.path.join(path, "{}.theme".format(name))):
|
|
i = 1
|
|
while os.path.exists(os.path.join(path, "{}_{}.theme".format(name, i))):
|
|
i += 1
|
|
name = os.path.join(path, "{}_{}.theme".format(name, i))
|
|
else:
|
|
name = os.path.join(path, "{}.theme".format(name))
|
|
|
|
settings = QSettings(name, QSettings.IniFormat)
|
|
settings.setValue("Name", self.tr("New theme"))
|
|
settings.sync()
|
|
|
|
self.populatesThemesList()
|
|
|
|
def editTheme(self):
|
|
item = self.lstThemes.currentItem()
|
|
theme = item.data(Qt.UserRole)
|
|
self.loadTheme(theme)
|
|
self.themeStack.setCurrentIndex(1)
|
|
|
|
def removeTheme(self):
|
|
item = self.lstThemes.currentItem()
|
|
theme = item.data(Qt.UserRole)
|
|
os.remove(theme)
|
|
self.populatesThemesList()
|
|
|
|
def populatesThemesList(self):
|
|
paths = allPaths("resources/themes")
|
|
current = settings.fullScreenTheme
|
|
self.lstThemes.clear()
|
|
|
|
for p in paths:
|
|
lst = [i for i in os.listdir(p) if os.path.splitext(i)[1] == ".theme"]
|
|
for t in lst:
|
|
theme = os.path.join(p, t)
|
|
editable = not appPath() in theme
|
|
n = getThemeName(theme)
|
|
|
|
item = QListWidgetItem(n)
|
|
item.setData(Qt.UserRole, theme)
|
|
item.setData(Qt.UserRole + 1, editable)
|
|
|
|
thumb = os.path.join(p, t.replace(".theme", ".jpg"))
|
|
px = QPixmap(200, 120)
|
|
px.fill(Qt.white)
|
|
if not os.path.exists(thumb):
|
|
currentScreen = qApp.desktop().screenNumber(self)
|
|
screenRect = qApp.desktop().screenGeometry(currentScreen)
|
|
thumb = createThemePreview(theme, screenRect)
|
|
|
|
icon = QPixmap(thumb).scaled(200, 120, Qt.KeepAspectRatio)
|
|
painter = QPainter(px)
|
|
painter.drawPixmap(px.rect().center() - icon.rect().center(), icon)
|
|
painter.end()
|
|
item.setIcon(QIcon(px))
|
|
|
|
self.lstThemes.addItem(item)
|
|
|
|
if current and current in t:
|
|
self.lstThemes.setCurrentItem(item)
|
|
current = None
|
|
|
|
self.lstThemes.setIconSize(QSize(200, 120))
|
|
|
|
if current: # the theme from settings wasn't found
|
|
# select the last from the list
|
|
self.lstThemes.setCurrentRow(self.lstThemes.count() - 1)
|
|
|
|
def loadTheme(self, theme):
|
|
self._editingTheme = theme
|
|
self._loadingTheme = True # So we don't generate preview while loading
|
|
|
|
# Load datas
|
|
self._themeData = loadThemeDatas(theme)
|
|
|
|
# Window Background
|
|
self.btnThemWindowBackgroundColor.clicked.connect(lambda: self.getThemeColor("Background/Color"))
|
|
try:
|
|
self.cmbThemeBackgroundImage.disconnect()
|
|
except:
|
|
pass
|
|
self.populatesCmbBackgrounds(self.cmbThemeBackgroundImage)
|
|
self.cmbThemeBackgroundImage.currentIndexChanged.connect(self.updateThemeBackground)
|
|
self.cmbThemBackgroundType.currentIndexChanged.connect(lambda i: self.setSetting("Background/Type", i))
|
|
|
|
# Text Background
|
|
self.btnThemeTextBackgroundColor.clicked.connect(lambda: self.getThemeColor("Foreground/Color"))
|
|
self.spnThemeTextBackgroundOpacity.valueChanged.connect(lambda v: self.setSetting("Foreground/Opacity", v))
|
|
self.spnThemeTextMargins.valueChanged.connect(lambda v: self.setSetting("Foreground/Margin", v))
|
|
self.spnThemeTextPadding.valueChanged.connect(lambda v: self.setSetting("Foreground/Padding", v))
|
|
self.cmbThemeTextPosition.currentIndexChanged.connect(lambda i: self.setSetting("Foreground/Position", i))
|
|
self.spnThemeTextRadius.valueChanged.connect(lambda v: self.setSetting("Foreground/Rounding", v))
|
|
self.spnThemeTextWidth.valueChanged.connect(lambda v: self.setSetting("Foreground/Width", v))
|
|
|
|
# Text Options
|
|
self.btnThemeTextColor.clicked.connect(lambda: self.getThemeColor("Text/Color"))
|
|
self.cmbThemeFont.currentFontChanged.connect(self.updateThemeFont)
|
|
try:
|
|
self.cmbThemeFontSize.currentIndexChanged.disconnect(self.updateThemeFont)
|
|
except:
|
|
pass
|
|
self.populatesFontSize()
|
|
self.cmbThemeFontSize.currentIndexChanged.connect(self.updateThemeFont)
|
|
self.btnThemeMisspelledColor.clicked.connect(lambda: self.getThemeColor("Text/Misspelled"))
|
|
|
|
# Paragraph Options
|
|
self.chkThemeIndent.stateChanged.connect(lambda v: self.setSetting("Spacings/IndendFirstLine", v != 0))
|
|
self.cmbThemeLineSpacing.currentIndexChanged.connect(self.updateLineSpacing)
|
|
self.cmbThemeLineSpacing.currentIndexChanged.connect(self.updateLineSpacing)
|
|
self.spnThemeLineSpacing.valueChanged.connect(lambda v: self.setSetting("Spacings/LineSpacing", v))
|
|
self.spnThemeParaAbove.valueChanged.connect(lambda v: self.setSetting("Spacings/ParagraphAbove", v))
|
|
self.spnThemeParaBelow.valueChanged.connect(lambda v: self.setSetting("Spacings/ParagraphBelow", v))
|
|
self.spnThemeTabWidth.valueChanged.connect(lambda v: self.setSetting("Spacings/TabWidth", v))
|
|
|
|
# Update UI
|
|
self.updateUIFromTheme()
|
|
|
|
# Generate preview
|
|
self._loadingTheme = False
|
|
self.updatePreview()
|
|
|
|
def setSetting(self, key, val):
|
|
self._themeData[key] = val
|
|
self.updatePreview()
|
|
|
|
def updateUIFromTheme(self):
|
|
self.txtThemeName.setText(self._themeData["Name"])
|
|
|
|
# Window Background
|
|
self.setButtonColor(self.btnThemWindowBackgroundColor, self._themeData["Background/Color"])
|
|
i = self.cmbThemeBackgroundImage.findData(self._themeData["Background/ImageFile"], flags=Qt.MatchContains)
|
|
if i != -1:
|
|
self.cmbThemeBackgroundImage.setCurrentIndex(i)
|
|
self.cmbThemBackgroundType.setCurrentIndex(self._themeData["Background/Type"])
|
|
|
|
# Text background
|
|
self.setButtonColor(self.btnThemeTextBackgroundColor, self._themeData["Foreground/Color"])
|
|
self.spnThemeTextBackgroundOpacity.setValue(self._themeData["Foreground/Opacity"])
|
|
self.spnThemeTextMargins.setValue(self._themeData["Foreground/Margin"])
|
|
self.spnThemeTextPadding.setValue(self._themeData["Foreground/Padding"])
|
|
self.cmbThemeTextPosition.setCurrentIndex(self._themeData["Foreground/Position"])
|
|
self.spnThemeTextRadius.setValue(self._themeData["Foreground/Rounding"])
|
|
self.spnThemeTextWidth.setValue(self._themeData["Foreground/Width"])
|
|
|
|
# Text Options
|
|
self.setButtonColor(self.btnThemeTextColor, self._themeData["Text/Color"])
|
|
f = QFont()
|
|
f.fromString(self._themeData["Text/Font"])
|
|
self.cmbThemeFont.setCurrentFont(f)
|
|
i = self.cmbThemeFontSize.findText(str(f.pointSize()))
|
|
if i != -1:
|
|
self.cmbThemeFontSize.setCurrentIndex(i)
|
|
else:
|
|
self.cmbThemeFontSize.addItem(str(f.pointSize()))
|
|
self.cmbThemeFontSize.setCurrentIndex(self.cmbThemeFontSize.count() - 1)
|
|
self.setButtonColor(self.btnThemeMisspelledColor, self._themeData["Text/Misspelled"])
|
|
|
|
# Paragraph Options
|
|
self.chkThemeIndent.setCheckState(Qt.Checked if self._themeData["Spacings/IndendFirstLine"] else Qt.Unchecked)
|
|
self.spnThemeLineSpacing.setEnabled(False)
|
|
if self._themeData["Spacings/LineSpacing"] == 100:
|
|
self.cmbThemeLineSpacing.setCurrentIndex(0)
|
|
elif self._themeData["Spacings/LineSpacing"] == 150:
|
|
self.cmbThemeLineSpacing.setCurrentIndex(1)
|
|
elif self._themeData["Spacings/LineSpacing"] == 200:
|
|
self.cmbThemeLineSpacing.setCurrentIndex(2)
|
|
else:
|
|
self.cmbThemeLineSpacing.setCurrentIndex(3)
|
|
self.spnThemeLineSpacing.setEnabled(True)
|
|
self.spnThemeLineSpacing.setValue(self._themeData["Spacings/LineSpacing"])
|
|
self.spnThemeParaAbove.setValue(self._themeData["Spacings/ParagraphAbove"])
|
|
self.spnThemeParaBelow.setValue(self._themeData["Spacings/ParagraphBelow"])
|
|
self.spnThemeTabWidth.setValue(self._themeData["Spacings/TabWidth"])
|
|
|
|
def populatesFontSize(self):
|
|
self.cmbThemeFontSize.clear()
|
|
s = list(range(6, 13)) + list(range(14, 29, 2)) + [36, 48, 72]
|
|
for i in s:
|
|
self.cmbThemeFontSize.addItem(str(i))
|
|
|
|
def updateThemeFont(self, v):
|
|
f = self.cmbThemeFont.currentFont()
|
|
s = self.cmbThemeFontSize.itemText(self.cmbThemeFontSize.currentIndex())
|
|
if s:
|
|
f.setPointSize(int(s))
|
|
|
|
self._themeData["Text/Font"] = f.toString()
|
|
self.updatePreview()
|
|
|
|
def updateLineSpacing(self, i):
|
|
if i == 0:
|
|
self._themeData["Spacings/LineSpacing"] = 100
|
|
elif i == 1:
|
|
self._themeData["Spacings/LineSpacing"] = 150
|
|
elif i == 2:
|
|
self._themeData["Spacings/LineSpacing"] = 200
|
|
elif i == 3:
|
|
self._themeData["Spacings/LineSpacing"] = self.spnThemeLineSpacing.value()
|
|
self.spnThemeLineSpacing.setEnabled(i == 3)
|
|
self.updatePreview()
|
|
|
|
def updateThemeBackground(self, i):
|
|
img = self.cmbCorkImage.itemData(i)
|
|
|
|
if img:
|
|
self._themeData["Background/ImageFile"] = os.path.split(img)[1]
|
|
else:
|
|
self._themeData["Background/ImageFile"] = ""
|
|
self.updatePreview()
|
|
|
|
def getThemeColor(self, key):
|
|
color = self._themeData[key]
|
|
self.colorDialog = QColorDialog(QColor(color), self)
|
|
color = self.colorDialog.getColor(QColor(color))
|
|
if color.isValid():
|
|
self._themeData[key] = color.name()
|
|
self.updateUIFromTheme()
|
|
self.updatePreview()
|
|
|
|
def updatePreview(self):
|
|
if self._loadingTheme:
|
|
return
|
|
|
|
currentScreen = qApp.desktop().screenNumber(self)
|
|
screen = qApp.desktop().screenGeometry(currentScreen)
|
|
|
|
px = createThemePreview(self._themeData, screen, self.lblPreview.size())
|
|
self.lblPreview.setPixmap(px)
|
|
|
|
def setButtonColor(self, btn, color):
|
|
btn.setStyleSheet("background:{};".format(color))
|
|
|
|
def saveTheme(self):
|
|
settings = QSettings(self._editingTheme, QSettings.IniFormat)
|
|
|
|
self._themeData["Name"] = self.txtThemeName.text()
|
|
for key in self._themeData:
|
|
settings.setValue(key, self._themeData[key])
|
|
|
|
settings.sync()
|
|
self.populatesThemesList()
|
|
self.themeStack.setCurrentIndex(0)
|
|
self._editingTheme = None
|
|
|
|
def cancelEdit(self):
|
|
self.themeStack.setCurrentIndex(0)
|
|
self._editingTheme = None
|
|
|
|
def resizeEvent(self, event):
|
|
QWidget.resizeEvent(self, event)
|
|
if self._editingTheme:
|
|
self.updatePreview()
|