From 826d53933f33fa674c4cf31d9e599611cbdbd2d2 Mon Sep 17 00:00:00 2001 From: Olivier Keshavjee Date: Tue, 5 Dec 2017 23:18:32 +0100 Subject: [PATCH] Adds #259: Focus Mode (poke #234) --- manuskript/settings.py | 2 + manuskript/settingsWindow.py | 9 +++ .../ui/highlighters/markdownHighlighter.py | 67 ++++++++++++++++++- manuskript/ui/settings_ui.py | 32 ++++++++- manuskript/ui/settings_ui.ui | 42 +++++++++++- manuskript/ui/views/MDEditCompleter.py | 1 + manuskript/ui/views/MDEditView.py | 1 + manuskript/ui/views/textEditView.py | 7 ++ 8 files changed, 155 insertions(+), 6 deletions(-) diff --git a/manuskript/settings.py b/manuskript/settings.py index 9f62710..4ba49de 100644 --- a/manuskript/settings.py +++ b/manuskript/settings.py @@ -75,6 +75,7 @@ textEditor = { "marginsTB": 20, "backgroundTransparent": False, "alwaysCenter": False, + "focusMode": False # "line", "paragraph" } revisions = { @@ -275,6 +276,7 @@ def load(string, fromString=False, protocol=None): "marginsTB": 20, "backgroundTransparent": False, # Added in 0.6.0 "alwaysCenter": False, # Added in 0.7.0 + "focusMode": False, } for k in added: diff --git a/manuskript/settingsWindow.py b/manuskript/settingsWindow.py index e61f86d..0ed49ea 100644 --- a/manuskript/settingsWindow.py +++ b/manuskript/settingsWindow.py @@ -204,6 +204,11 @@ class settingsWindow(QWidget, Ui_Settings): self.chkEditorNoBlinking.stateChanged.connect(self.setApplicationCursorBlinking) self.chkEditorTypeWriterMode.setChecked(opt["alwaysCenter"]) self.chkEditorTypeWriterMode.stateChanged.connect(self.updateEditorSettings) + self.cmbEditorFocusMode.setCurrentIndex( + 0 if not opt["focusMode"] else + 1 if opt["focusMode"] == "line" else + 2) + self.cmbEditorFocusMode.currentIndexChanged.connect(self.updateEditorSettings) # Text areas self.chkEditorMaxWidth.setChecked(opt["maxWidth"] != 0) self.chkEditorMaxWidth.stateChanged.connect(self.updateEditorSettings) @@ -497,6 +502,10 @@ class settingsWindow(QWidget, Ui_Settings): self.spnEditorCursorWidth.value() self.spnEditorCursorWidth.setEnabled(self.chkEditorCursorWidth.isChecked()) settings.textEditor["alwaysCenter"] = self.chkEditorTypeWriterMode.isChecked() + settings.textEditor["focusMode"] = \ + False if self.cmbEditorFocusMode.currentIndex() == 0 else \ + "line" if self.cmbEditorFocusMode.currentIndex() == 1 else \ + "paragraph" # Text area settings.textEditor["maxWidth"] = \ diff --git a/manuskript/ui/highlighters/markdownHighlighter.py b/manuskript/ui/highlighters/markdownHighlighter.py index 52b46a2..b5f3c74 100644 --- a/manuskript/ui/highlighters/markdownHighlighter.py +++ b/manuskript/ui/highlighters/markdownHighlighter.py @@ -68,6 +68,49 @@ class MarkdownHighlighter(BasicHighlighter): #f.setFamily("monospace") #self.document().setDefaultFont(f) + def transparentFormat(self, fmt, alpha=75): + """ + Takes a QTextCharFormat and modify it with colors made transparent + using alpha channel. For focus mode + """ + c = fmt.foreground().color() + c.setAlpha(alpha) + fmt.setForeground(QBrush(c)) + b = fmt.background() + if b.style() != Qt.NoBrush: + c = b.color() + c.setAlpha(alpha) + fmt.setBackground(QBrush(b)) + + def unfocusConditions(self): + """ + Returns: + - True if the text is suposed to be unfocused + - (start, end) if block is supposed to be unfocused except for that part. + """ + + if self.editor._noFocusMode or not settings.textEditor["focusMode"]: + return False + + if settings.textEditor["focusMode"] == "paragraph": + return not self.currentBlock().contains( + self.editor.textCursor().position()) + elif settings.textEditor["focusMode"] == "line": + if self.currentBlock().contains( + self.editor.textCursor().position()): + block = self.currentBlock() + # Position of cursor in block + pos = self.editor.textCursor().position() - block.position() + for i in range(block.layout().lineCount()): + line = block.layout().lineAt(i) + start = line.textStart() + end = line.textStart() + line.textLength() + if start <= pos < end: + return (start, end) + else: + return True + return False + def doHighlightBlock(self, text): """ Note: Never set the QTextBlockFormat for a QTextBlock from within @@ -85,7 +128,20 @@ class MarkdownHighlighter(BasicHighlighter): """ lastState = self.currentBlockState() - self.setFormat(0, len(text), self._defaultCharFormat) + # self.setFormat(0, len(text), self._defaultCharFormat) + + # Focus mode + unfocus = self.unfocusConditions() + if unfocus: + fmt = self.format(0) + fmt.setForeground(QBrush(self.defaultTextColor)) + self.transparentFormat(fmt) + if type(unfocus) != bool: + start, end = unfocus + self.setFormat(0, start, fmt) + self.setFormat(end, len(text), fmt) + else: + self.setFormat(0, len(text), fmt) if self.tokenizer != None: self.tokenizer.clear() @@ -389,6 +445,15 @@ class MarkdownHighlighter(BasicHighlighter): fmt, markupFormat) + # Focus mode + unfocus = self.unfocusConditions() + if unfocus: + if (type(unfocus) == bool + or token.position < unfocus[0] + or unfocus[1] < token.position): + self.transparentFormat(fmt) + self.transparentFormat(markupFormat) + # Format openning Markup self.setFormat(token.position, token.openingMarkupLength, markupFormat) diff --git a/manuskript/ui/settings_ui.py b/manuskript/ui/settings_ui.py index c757e1f..2cde4e7 100644 --- a/manuskript/ui/settings_ui.py +++ b/manuskript/ui/settings_ui.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'manuskript/ui/settings_ui.ui' # -# Created by: PyQt5 UI code generator 5.5.1 +# Created by: PyQt5 UI code generator 5.9 # # WARNING! All changes made in this file will be lost! @@ -1310,6 +1310,23 @@ class Ui_Settings(object): self.chkEditorTypeWriterMode.setFont(font) self.chkEditorTypeWriterMode.setObjectName("chkEditorTypeWriterMode") self.formLayout_10.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.chkEditorTypeWriterMode) + self.label_52 = QtWidgets.QLabel(self.groupBox_15) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + self.label_52.setFont(font) + self.label_52.setObjectName("label_52") + self.formLayout_10.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_52) + self.cmbEditorFocusMode = QtWidgets.QComboBox(self.groupBox_15) + font = QtGui.QFont() + font.setBold(False) + font.setWeight(50) + self.cmbEditorFocusMode.setFont(font) + self.cmbEditorFocusMode.setObjectName("cmbEditorFocusMode") + self.cmbEditorFocusMode.addItem("") + self.cmbEditorFocusMode.addItem("") + self.cmbEditorFocusMode.addItem("") + self.formLayout_10.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.cmbEditorFocusMode) self.verticalLayout_22.addWidget(self.groupBox_15) self.horizontalLayout_4.addLayout(self.verticalLayout_22) icon = QtGui.QIcon.fromTheme("view-text") @@ -1499,6 +1516,7 @@ class Ui_Settings(object): self.layoutWidget = QtWidgets.QWidget(self.splitter) self.layoutWidget.setObjectName("layoutWidget") self.verticalLayout_14 = QtWidgets.QVBoxLayout(self.layoutWidget) + self.verticalLayout_14.setContentsMargins(0, 0, 0, 0) self.verticalLayout_14.setObjectName("verticalLayout_14") self.cmbThemeEdit = QtWidgets.QComboBox(self.layoutWidget) self.cmbThemeEdit.setObjectName("cmbThemeEdit") @@ -1513,6 +1531,7 @@ class Ui_Settings(object): self.stackedWidgetPage1_2.setObjectName("stackedWidgetPage1_2") self.formLayout_4 = QtWidgets.QFormLayout(self.stackedWidgetPage1_2) self.formLayout_4.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout_4.setContentsMargins(0, 0, 0, 0) self.formLayout_4.setObjectName("formLayout_4") self.label_17 = QtWidgets.QLabel(self.stackedWidgetPage1_2) self.label_17.setObjectName("label_17") @@ -1544,6 +1563,7 @@ class Ui_Settings(object): self.stackedWidgetPage2_2.setObjectName("stackedWidgetPage2_2") self.formLayout_5 = QtWidgets.QFormLayout(self.stackedWidgetPage2_2) self.formLayout_5.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout_5.setContentsMargins(0, 0, 0, 0) self.formLayout_5.setObjectName("formLayout_5") self.label_20 = QtWidgets.QLabel(self.stackedWidgetPage2_2) self.label_20.setObjectName("label_20") @@ -1641,6 +1661,7 @@ class Ui_Settings(object): self.page_2.setObjectName("page_2") self.formLayout_7 = QtWidgets.QFormLayout(self.page_2) self.formLayout_7.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout_7.setContentsMargins(0, 0, 0, 0) self.formLayout_7.setObjectName("formLayout_7") self.label_29 = QtWidgets.QLabel(self.page_2) self.label_29.setObjectName("label_29") @@ -1690,6 +1711,7 @@ class Ui_Settings(object): self.stackedWidgetPage3_2.setObjectName("stackedWidgetPage3_2") self.formLayout_6 = QtWidgets.QFormLayout(self.stackedWidgetPage3_2) self.formLayout_6.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout_6.setContentsMargins(0, 0, 0, 0) self.formLayout_6.setObjectName("formLayout_6") self.label_26 = QtWidgets.QLabel(self.stackedWidgetPage3_2) self.label_26.setObjectName("label_26") @@ -1792,7 +1814,7 @@ class Ui_Settings(object): self.horizontalLayout_8.addWidget(self.stack) self.retranslateUi(Settings) - self.stack.setCurrentIndex(0) + self.stack.setCurrentIndex(2) self.tabViews.setCurrentIndex(3) self.themeStack.setCurrentIndex(1) self.themeEditStack.setCurrentIndex(3) @@ -1914,7 +1936,7 @@ class Ui_Settings(object): self.label_16.setText(_translate("Settings", "Image:")) self.groupBox_11.setTitle(_translate("Settings", "Style")) self.rdoCorkOldStyle.setText(_translate("Settings", "Old st&yle")) - self.rdoCorkNewStyle.setText(_translate("Settings", "Ne&w style")) + self.rdoCorkNewStyle.setText(_translate("Settings", "&New style")) self.groupBox_5.setTitle(_translate("Settings", "Item colors")) self.label_9.setText(_translate("Settings", "Icon color:")) self.cmbCorkIcon.setItemText(0, _translate("Settings", "Nothing")) @@ -1986,6 +2008,10 @@ class Ui_Settings(object): self.spnEditorCursorWidth.setSuffix(_translate("Settings", " px")) self.chkEditorNoBlinking.setText(_translate("Settings", "Disable blinking")) self.chkEditorTypeWriterMode.setText(_translate("Settings", "Typewriter mode")) + self.label_52.setText(_translate("Settings", "Focus mode")) + self.cmbEditorFocusMode.setItemText(0, _translate("Settings", "None")) + self.cmbEditorFocusMode.setItemText(1, _translate("Settings", "Line")) + self.cmbEditorFocusMode.setItemText(2, _translate("Settings", "Paragraph")) self.tabViews.setTabText(self.tabViews.indexOf(self.tab_4), _translate("Settings", "Text editor")) self.lblTitleLabels.setText(_translate("Settings", "Labels")) self.btnLabelColor.setShortcut(_translate("Settings", "Ctrl+S")) diff --git a/manuskript/ui/settings_ui.ui b/manuskript/ui/settings_ui.ui index 986f097..1fa5c70 100644 --- a/manuskript/ui/settings_ui.ui +++ b/manuskript/ui/settings_ui.ui @@ -54,7 +54,7 @@ - 0 + 2 @@ -1697,7 +1697,7 @@ - Ne&w style + &New style @@ -2653,6 +2653,44 @@ + + + + + 50 + false + + + + Focus mode + + + + + + + + 50 + false + + + + + None + + + + + Line + + + + + Paragraph + + + + diff --git a/manuskript/ui/views/MDEditCompleter.py b/manuskript/ui/views/MDEditCompleter.py index 93cdb96..5be00af 100644 --- a/manuskript/ui/views/MDEditCompleter.py +++ b/manuskript/ui/views/MDEditCompleter.py @@ -25,6 +25,7 @@ class MDEditCompleter(MDEditView): self.completer = None self.setMouseTracking(True) self.refRects = [] + self._noFocusMode = True self.textChanged.connect(self.getRefRects) self.document().documentLayoutChanged.connect(self.getRefRects) diff --git a/manuskript/ui/views/MDEditView.py b/manuskript/ui/views/MDEditView.py index d021bf8..447ec00 100644 --- a/manuskript/ui/views/MDEditView.py +++ b/manuskript/ui/views/MDEditView.py @@ -27,6 +27,7 @@ class MDEditView(textEditView): # Highlighter self._textFormat = "md" self._highlighterClass = MarkdownHighlighter + self._noFocusMode = False if index: # We have to setup things anew, for the highlighter notably diff --git a/manuskript/ui/views/textEditView.py b/manuskript/ui/views/textEditView.py index fd19fe3..330dcf9 100644 --- a/manuskript/ui/views/textEditView.py +++ b/manuskript/ui/views/textEditView.py @@ -67,6 +67,9 @@ class textEditView(QTextEdit): # self.document().contentsChanged.connect(lambda: print(self.objectName(), "Contents changed")) + # Focus mode + self.cursorPositionChanged.connect(self.cursorHasMoved) + self.setEnabled(False) if index: @@ -91,6 +94,10 @@ class textEditView(QTextEdit): self.highlighter = self._highlighterClass(self) self.highlighter.setDefaultBlockFormat(self._defaultBlockFormat) + def cursorHasMoved(self): + if self.highlighter: + self.highlighter.rehighlight() + def getDefaultLocale(self): default_locale = enchant.get_default_language() if default_locale is None: