Browse Source

VTextDocumentLayout: support cursor line block background

Le Tan 8 years ago
parent
commit
49811cabc0

+ 18 - 0
src/utils/vvim.cpp

@@ -12,6 +12,7 @@
 #include "veditor.h"
 #include "utils/veditutils.h"
 #include "vconstants.h"
+#include "vmdeditor.h"
 
 extern VConfigManager *g_config;
 
@@ -2269,9 +2270,14 @@ void VVim::setMode(VimMode p_mode, bool p_clearSelection, int p_position)
         m_mode = p_mode;
         resetState();
 
+        VMdEditor *mdEditor = dynamic_cast<VMdEditor *>(m_editor);
         switch (m_mode) {
         case VimMode::Insert:
             m_editor->setCursorBlockModeW(CursorBlock::None);
+            if (mdEditor) {
+                mdEditor->setHighlightCursorLineBlockEnabled(false);
+            }
+
             break;
 
         case VimMode::Visual:
@@ -2280,6 +2286,18 @@ void VVim::setMode(VimMode p_mode, bool p_clearSelection, int p_position)
 
         default:
             m_editor->setCursorBlockModeW(CursorBlock::RightSide);
+            if (mdEditor) {
+                QString color;
+                if (m_mode == VimMode::Normal) {
+                    color = g_config->getEditorVimNormalBg();
+                } else {
+                    color = g_config->getEditorVimVisualBg();
+                }
+
+                mdEditor->setCursorLineBlockBg(color);
+                mdEditor->setHighlightCursorLineBlockEnabled(true);
+            }
+
             break;
         }
 

+ 2 - 1
src/vedittab.cpp

@@ -81,9 +81,10 @@ void VEditTab::wheelEvent(QWheelEvent *p_event)
     p_event->ignore();
 }
 
-VEditTabInfo VEditTab::fetchTabInfo() const
+VEditTabInfo VEditTab::fetchTabInfo(VEditTabInfo::InfoType p_type) const
 {
     VEditTabInfo info;
+    info.m_type = p_type;
     info.m_editTab = const_cast<VEditTab *>(this);
 
     return info;

+ 1 - 1
src/vedittab.h

@@ -80,7 +80,7 @@ public:
     }
 
     // Create a filled VEditTabInfo.
-    virtual VEditTabInfo fetchTabInfo() const;
+    virtual VEditTabInfo fetchTabInfo(VEditTabInfo::InfoType p_type = VEditTabInfo::InfoType::All) const;
 
     const VTableOfContent &getOutline() const;
 

+ 14 - 1
src/vedittabinfo.h

@@ -5,8 +5,18 @@ class VEditTab;
 
 struct VEditTabInfo
 {
+    enum InfoType
+    {
+        // Update all information.
+        All = 0,
+
+        // Update only cursor information.
+        Cursor
+    };
+
     VEditTabInfo()
-        : m_editTab(NULL),
+        : m_type(InfoType::All),
+          m_editTab(NULL),
           m_cursorBlockNumber(-1),
           m_cursorPositionInBlock(-1),
           m_blockCount(-1),
@@ -16,6 +26,7 @@ struct VEditTabInfo
 
     void clear()
     {
+        m_type = InfoType::All;
         m_editTab = NULL;
         m_cursorBlockNumber = -1;
         m_cursorPositionInBlock = -1;
@@ -23,6 +34,8 @@ struct VEditTabInfo
         m_headerIndex = -1;
     }
 
+    InfoType m_type;
+
     VEditTab *m_editTab;
 
     // Cursor information. -1 for invalid info.

+ 4 - 2
src/veditwindow.cpp

@@ -766,8 +766,10 @@ void VEditWindow::handleTabStatusUpdated(const VEditTabInfo &p_info)
 {
     int idx = indexOf(dynamic_cast<QWidget *>(sender()));
 
-    updateTabInfo(idx);
-    updateAllTabsSequence();
+    if (p_info.m_type == VEditTabInfo::InfoType::All) {
+        updateTabInfo(idx);
+        updateAllTabsSequence();
+    }
 
     if (idx == currentIndex()) {
         // Current tab. Propogate its status.

+ 24 - 19
src/vmainwindow.cpp

@@ -1880,32 +1880,35 @@ void VMainWindow::handleAreaTabStatusUpdated(const VEditTabInfo &p_info)
         m_curFile = NULL;
     }
 
-    updateActionsStateFromTab(m_curTab);
+    if (p_info.m_type == VEditTabInfo::InfoType::All) {
+        updateActionsStateFromTab(m_curTab);
 
-    m_attachmentList->setFile(dynamic_cast<VNoteFile *>(m_curFile.data()));
+        m_attachmentList->setFile(dynamic_cast<VNoteFile *>(m_curFile.data()));
 
-    QString title;
-    if (m_curFile) {
-        m_findReplaceDialog->updateState(m_curFile->getDocType(),
-                                         m_curTab->isEditMode());
+        QString title;
+        if (m_curFile) {
+            m_findReplaceDialog->updateState(m_curFile->getDocType(),
+                                             m_curTab->isEditMode());
 
-        if (m_curFile->getType() == FileType::Note) {
-            const VNoteFile *tmpFile = dynamic_cast<const VNoteFile *>((VFile *)m_curFile);
-            title = QString("[%1] %2").arg(tmpFile->getNotebookName()).arg(tmpFile->fetchPath());
-        } else {
-            title = QString("%1").arg(m_curFile->fetchPath());
-        }
+            if (m_curFile->getType() == FileType::Note) {
+                const VNoteFile *tmpFile = dynamic_cast<const VNoteFile *>((VFile *)m_curFile);
+                title = QString("[%1] %2").arg(tmpFile->getNotebookName()).arg(tmpFile->fetchPath());
+            } else {
+                title = QString("%1").arg(m_curFile->fetchPath());
+            }
 
-        if (!m_curFile->isModifiable()) {
-            title.append('#');
-        }
+            if (!m_curFile->isModifiable()) {
+                title.append('#');
+            }
 
-        if (m_curTab->isModified()) {
-            title.append('*');
+            if (m_curTab->isModified()) {
+                title.append('*');
+            }
         }
+
+        updateWindowTitle(title);
     }
 
-    updateWindowTitle(title);
     updateStatusInfo(p_info);
 }
 
@@ -2418,7 +2421,9 @@ void VMainWindow::updateStatusInfo(const VEditTabInfo &p_info)
         m_tabIndicator->show();
 
         if (m_curTab->isEditMode()) {
-            m_curTab->requestUpdateVimStatus();
+            if (p_info.m_type == VEditTabInfo::InfoType::All) {
+                m_curTab->requestUpdateVimStatus();
+            }
         } else {
             m_vimIndicator->hide();
         }

+ 8 - 3
src/vmdtab.cpp

@@ -423,7 +423,7 @@ void VMdTab::setupMarkdownEditor()
     connect(m_editor, &VMdEditor::textChanged,
             this, &VMdTab::updateStatus);
     connect(m_editor, &VMdEditor::cursorPositionChanged,
-            this, &VMdTab::updateStatus);
+            this, &VMdTab::updateCursorStatus);
     connect(g_mainWin, &VMainWindow::editorConfigUpdated,
             m_editor, &VMdEditor::updateConfig);
     connect(m_editor->object(), &VEditorObject::saveAndRead,
@@ -702,9 +702,9 @@ void VMdTab::requestUpdateVimStatus()
     }
 }
 
-VEditTabInfo VMdTab::fetchTabInfo() const
+VEditTabInfo VMdTab::fetchTabInfo(VEditTabInfo::InfoType p_type) const
 {
-    VEditTabInfo info = VEditTab::fetchTabInfo();
+    VEditTabInfo info = VEditTab::fetchTabInfo(p_type);
 
     if (m_editor) {
         QTextCursor cursor = m_editor->textCursor();
@@ -972,3 +972,8 @@ bool VMdTab::checkPreviousBackupFile()
 
     return true;
 }
+
+void VMdTab::updateCursorStatus()
+{
+    emit statusUpdated(fetchTabInfo(VEditTabInfo::InfoType::Cursor));
+}

+ 4 - 1
src/vmdtab.h

@@ -69,7 +69,7 @@ public:
     void decorateText(TextDecoration p_decoration, int p_level = -1) Q_DECL_OVERRIDE;
 
     // Create a filled VEditTabInfo.
-    VEditTabInfo fetchTabInfo() const Q_DECL_OVERRIDE;
+    VEditTabInfo fetchTabInfo(VEditTabInfo::InfoType p_type = VEditTabInfo::InfoType::All) const Q_DECL_OVERRIDE;
 
     // Enable or disable heading sequence.
     void enableHeadingSequence(bool p_enabled);
@@ -179,6 +179,9 @@ private:
     // Return true if we could continue.
     bool checkPreviousBackupFile();
 
+    // updateStatus() with only cursor position information.
+    void updateCursorStatus();
+
     VMdEditor *m_editor;
     VWebView *m_webViewer;
     VDocument *m_document;

+ 31 - 2
src/vtextdocumentlayout.cpp

@@ -34,7 +34,10 @@ VTextDocumentLayout::VTextDocumentLayout(QTextDocument *p_doc,
       m_imageLineColor("#9575CD"),
       m_cursorBlockMode(CursorBlock::None),
       m_virtualCursorBlockWidth(8),
-      m_lastCursorBlockWidth(-1)
+      m_lastCursorBlockWidth(-1),
+      m_highlightCursorLineBlock(false),
+      m_cursorLineBlockBg("#C0C0C0"),
+      m_cursorLineBlockNumber(-1)
 {
 }
 
@@ -219,7 +222,11 @@ void VTextDocumentLayout::draw(QPainter *p_painter, const PaintContext &p_contex
         QTextBlockFormat blockFormat = block.blockFormat();
         QBrush bg = blockFormat.background();
         if (bg != Qt::NoBrush) {
-            fillBackground(p_painter, rect, bg);
+            int x = offset.x();
+            int y = offset.y();
+            fillBackground(p_painter,
+                           rect.adjusted(x, y, x, y),
+                           bg);
         }
 
         auto selections = formatRangeFromSelection(block, p_context.selections);
@@ -252,6 +259,16 @@ void VTextDocumentLayout::draw(QPainter *p_painter, const PaintContext &p_contex
             }
         }
 
+        // Draw cursor line block.
+        if (m_highlightCursorLineBlock
+            && m_cursorLineBlockNumber == block.blockNumber()) {
+            int x = offset.x();
+            int y = offset.y();
+            fillBackground(p_painter,
+                           rect.adjusted(x, y, x, y),
+                           m_cursorLineBlockBg);
+        }
+
         layout->draw(p_painter,
                      offset,
                      selections,
@@ -1090,3 +1107,15 @@ int VTextDocumentLayout::getTextWidthWithinTextLine(const QTextLayout *p_layout,
     Q_ASSERT(p_pos + p_length <= line.textStart() + line.textLength());
     return line.cursorToX(p_pos + p_length) - line.cursorToX(p_pos);
 }
+
+void VTextDocumentLayout::updateBlockByNumber(int p_blockNumber)
+{
+    if (p_blockNumber == -1) {
+        return;
+    }
+
+    QTextBlock block = document()->findBlockByNumber(p_blockNumber);
+    if (block.isValid()) {
+        emit updateBlock(block);
+    }
+}

+ 51 - 0
src/vtextdocumentlayout.h

@@ -61,6 +61,15 @@ public:
 
     void clearLastCursorBlockWidth();
 
+    void setHighlightCursorLineBlockEnabled(bool p_enabled);
+
+    void setCursorLineBlockBg(const QColor &p_bg);
+
+    void setCursorLineBlockNumber(int p_blockNumber);
+
+    // Request update block by block number.
+    void updateBlockByNumber(int p_blockNumber);
+
 signals:
     // Emit to update current cursor block width if m_cursorBlockMode is enabled.
     void cursorBlockWidthUpdated(int p_width);
@@ -287,6 +296,15 @@ private:
     int m_virtualCursorBlockWidth;
 
     int m_lastCursorBlockWidth;
+
+    // Whether highlight the block containing the cursor line.
+    bool m_highlightCursorLineBlock;
+
+    // The cursor line's block background color.
+    QColor m_cursorLineBlockBg;
+
+    // The block containing the cursor.
+    int m_cursorLineBlockNumber;
 };
 
 inline qreal VTextDocumentLayout::getLineLeading() const
@@ -320,4 +338,37 @@ inline void VTextDocumentLayout::clearLastCursorBlockWidth()
 {
     m_lastCursorBlockWidth = -1;
 }
+
+inline void VTextDocumentLayout::setHighlightCursorLineBlockEnabled(bool p_enabled)
+{
+    if (m_highlightCursorLineBlock != p_enabled) {
+        m_highlightCursorLineBlock = p_enabled;
+        if (!m_highlightCursorLineBlock) {
+            int pre = m_cursorLineBlockNumber;
+            m_cursorLineBlockNumber = -1;
+            updateBlockByNumber(pre);
+        }
+    }
+}
+
+inline void VTextDocumentLayout::setCursorLineBlockBg(const QColor &p_bg)
+{
+    if (p_bg != m_cursorLineBlockBg) {
+        m_cursorLineBlockBg = p_bg;
+        updateBlockByNumber(m_cursorLineBlockNumber);
+    }
+}
+
+inline void VTextDocumentLayout::setCursorLineBlockNumber(int p_blockNumber)
+{
+    if (p_blockNumber != m_cursorLineBlockNumber) {
+        int pre = m_cursorLineBlockNumber;
+        m_cursorLineBlockNumber = p_blockNumber;
+
+        if (m_highlightCursorLineBlock) {
+            updateBlockByNumber(pre);
+            updateBlockByNumber(m_cursorLineBlockNumber);
+        }
+    }
+}
 #endif // VTEXTDOCUMENTLAYOUT_H

+ 28 - 1
src/vtextedit.cpp

@@ -51,6 +51,8 @@ void VTextEdit::init()
 
     m_cursorBlockMode = CursorBlock::None;
 
+    m_highlightCursorLineBlock = false;
+
     m_imageMgr = new VImageResourceManager2();
 
     QTextDocument *doc = document();
@@ -80,7 +82,14 @@ void VTextEdit::init()
     connect(verticalScrollBar(), &QScrollBar::valueChanged,
             this, &VTextEdit::updateLineNumberArea);
     connect(this, &QTextEdit::cursorPositionChanged,
-            this, &VTextEdit::updateLineNumberArea);
+            this, [this]() {
+                if (m_highlightCursorLineBlock) {
+                    QTextCursor cursor = textCursor();
+                    getLayout()->setCursorLineBlockNumber(cursor.block().blockNumber());
+                }
+
+                updateLineNumberArea();
+            });
 }
 
 VTextDocumentLayout *VTextEdit::getLayout() const
@@ -356,3 +365,21 @@ void VTextEdit::setCursorBlockMode(CursorBlock p_mode)
                                                               : 1);
     }
 }
+
+void VTextEdit::setHighlightCursorLineBlockEnabled(bool p_enabled)
+{
+    if (m_highlightCursorLineBlock != p_enabled) {
+        auto layout = getLayout();
+        m_highlightCursorLineBlock = p_enabled;
+        layout->setHighlightCursorLineBlockEnabled(p_enabled);
+        if (m_highlightCursorLineBlock) {
+            QTextCursor cursor = textCursor();
+            layout->setCursorLineBlockNumber(cursor.block().blockNumber());
+        }
+    }
+}
+
+void VTextEdit::setCursorLineBlockBg(const QColor &p_bg)
+{
+    getLayout()->setCursorLineBlockBg(p_bg);
+}

+ 6 - 0
src/vtextedit.h

@@ -59,6 +59,10 @@ public:
 
     void setCursorBlockMode(CursorBlock p_mode);
 
+    void setHighlightCursorLineBlockEnabled(bool p_enabled);
+
+    void setCursorLineBlockBg(const QColor &p_bg);
+
 protected:
     void resizeEvent(QResizeEvent *p_event) Q_DECL_OVERRIDE;
 
@@ -83,6 +87,8 @@ private:
     bool m_blockImageEnabled;
 
     CursorBlock m_cursorBlockMode;
+
+    bool m_highlightCursorLineBlock;
 };
 
 inline void VTextEdit::setLineNumberType(LineNumberType p_type)