mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
vim-mode: add an indicator for Vim status in status bar
This commit is contained in:
parent
ffce4b9611
commit
d909091f46
@ -2,7 +2,8 @@
|
||||
<!-- Generator: Adobe Illustrator 16.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
|
||||
<path d="M184.7,413.1l2.1-1.8l156.5-136c5.3-4.6,8.6-11.5,8.6-19.2c0-7.7-3.4-14.6-8.6-19.2L187.1,101l-2.6-2.3
|
||||
C182,97,179,96,175.8,96c-8.7,0-15.8,7.4-15.8,16.6h0v286.8h0c0,9.2,7.1,16.6,15.8,16.6C179.1,416,182.2,414.9,184.7,413.1z"/>
|
||||
width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
|
||||
<g>
|
||||
<polygon points="128,320 256,192 384,320 "/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 725 B After Width: | Height: | Size: 542 B |
@ -17,6 +17,22 @@ QPushButton[CornerBtn="true"]::focus {
|
||||
background-color: @focus-color;
|
||||
}
|
||||
|
||||
QPushButton[StatusBtn="true"] {
|
||||
font: bold;
|
||||
padding: 0px 2px 0px 2px;
|
||||
margin: 0px;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
QPushButton[StatusBtn="true"]::hover {
|
||||
background-color: @hover-color;
|
||||
}
|
||||
|
||||
QPushButton[StatusBtn="true"]::focus {
|
||||
background-color: @focus-color;
|
||||
}
|
||||
|
||||
QPushButton[FlatBtn="true"] {
|
||||
padding: 4px;
|
||||
margin: 0px;
|
||||
|
@ -66,7 +66,9 @@ SOURCES += main.cpp\
|
||||
vmdtab.cpp \
|
||||
vhtmltab.cpp \
|
||||
utils/vvim.cpp \
|
||||
utils/veditutils.cpp
|
||||
utils/veditutils.cpp \
|
||||
vvimindicator.cpp \
|
||||
vbuttonwithwidget.cpp
|
||||
|
||||
HEADERS += vmainwindow.h \
|
||||
vdirectorytree.h \
|
||||
@ -119,7 +121,9 @@ HEADERS += vmainwindow.h \
|
||||
vmdtab.h \
|
||||
vhtmltab.h \
|
||||
utils/vvim.h \
|
||||
utils/veditutils.h
|
||||
utils/veditutils.h \
|
||||
vvimindicator.h \
|
||||
vbuttonwithwidget.h
|
||||
|
||||
RESOURCES += \
|
||||
vnote.qrc \
|
||||
|
@ -290,12 +290,16 @@ bool VVim::handleKeyPressEvent(QKeyEvent *p_event)
|
||||
goto accept;
|
||||
}
|
||||
|
||||
m_pendingKeys.append(keyInfo);
|
||||
|
||||
if (expectingRegisterName()) {
|
||||
// Expecting a register name.
|
||||
QChar reg = keyToRegisterName(keyInfo);
|
||||
if (!reg.isNull()) {
|
||||
resetState();
|
||||
m_regName = reg;
|
||||
// We should keep m_pendingKeys.
|
||||
m_keys.clear();
|
||||
m_tokens.clear();
|
||||
setRegister(reg);
|
||||
if (m_registers[reg].isNamedRegister()) {
|
||||
m_registers[reg].m_append = (modifiers == Qt::ShiftModifier);
|
||||
} else {
|
||||
@ -1281,6 +1285,7 @@ accept:
|
||||
|
||||
exit:
|
||||
m_resetPositionInBlock = resetPositionInBlock;
|
||||
emit vimStatusUpdated(this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1288,7 +1293,8 @@ void VVim::resetState()
|
||||
{
|
||||
m_keys.clear();
|
||||
m_tokens.clear();
|
||||
m_regName = c_unnamedRegister;
|
||||
m_pendingKeys.clear();
|
||||
setRegister(c_unnamedRegister);
|
||||
m_resetPositionInBlock = true;
|
||||
}
|
||||
|
||||
@ -1305,6 +1311,7 @@ void VVim::setMode(VimMode p_mode)
|
||||
resetState();
|
||||
|
||||
emit modeChanged(m_mode);
|
||||
emit vimStatusUpdated(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3380,3 +3387,28 @@ void VVim::message(const QString &p_msg)
|
||||
qDebug() << "vim msg:" << p_msg;
|
||||
emit vimMessage(p_msg);
|
||||
}
|
||||
|
||||
const QMap<QChar, VVim::Register> &VVim::getRegisters() const
|
||||
{
|
||||
return m_registers;
|
||||
}
|
||||
|
||||
QChar VVim::getCurrentRegisterName() const
|
||||
{
|
||||
return m_regName;
|
||||
}
|
||||
|
||||
QString VVim::getPendingKeys() const
|
||||
{
|
||||
QString str;
|
||||
for (auto const & key : m_pendingKeys) {
|
||||
str.append(keyToChar(key.m_key, key.m_modifiers));
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void VVim::setRegister(QChar p_reg)
|
||||
{
|
||||
m_regName = p_reg;
|
||||
}
|
||||
|
148
src/utils/vvim.h
148
src/utils/vvim.h
@ -4,7 +4,7 @@
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QTextCursor>
|
||||
#include <QHash>
|
||||
#include <QMap>
|
||||
#include <QDebug>
|
||||
#include "vutils.h"
|
||||
|
||||
@ -28,6 +28,69 @@ class VVim : public QObject
|
||||
public:
|
||||
explicit VVim(VEdit *p_editor);
|
||||
|
||||
struct Register
|
||||
{
|
||||
Register(QChar p_name, const QString &p_value)
|
||||
: m_name(p_name), m_value(p_value), m_append(false)
|
||||
{
|
||||
}
|
||||
|
||||
Register(QChar p_name)
|
||||
: m_name(p_name), m_append(false)
|
||||
{
|
||||
}
|
||||
|
||||
Register()
|
||||
: m_append(false)
|
||||
{
|
||||
}
|
||||
|
||||
// Register a-z.
|
||||
bool isNamedRegister() const
|
||||
{
|
||||
char ch = m_name.toLatin1();
|
||||
return ch >= 'a' && ch <= 'z';
|
||||
}
|
||||
|
||||
bool isUnnamedRegister() const
|
||||
{
|
||||
return m_name == c_unnamedRegister;
|
||||
}
|
||||
|
||||
bool isBlackHoleRegister() const
|
||||
{
|
||||
return m_name == c_blackHoleRegister;
|
||||
}
|
||||
|
||||
bool isSelectionRegister() const
|
||||
{
|
||||
return m_name == c_selectionRegister;
|
||||
}
|
||||
|
||||
bool isBlock() const
|
||||
{
|
||||
return m_value.endsWith('\n');
|
||||
}
|
||||
|
||||
// @p_value is the content to update.
|
||||
// If @p_value ends with \n, then it is a block.
|
||||
// When @p_value is a block, we need to add \n at the end if necessary.
|
||||
// If @m_append is true and @p_value is a block, we need to add \n between
|
||||
// them if necessary.
|
||||
void update(const QString &p_value);
|
||||
|
||||
// Read the value of this register.
|
||||
const QString &read();
|
||||
|
||||
QChar m_name;
|
||||
QString m_value;
|
||||
|
||||
// This is not info of Register itself, but a hint to the handling logics
|
||||
// whether we need to append the content to this register.
|
||||
// Only valid for a-z registers.
|
||||
bool m_append;
|
||||
};
|
||||
|
||||
// Handle key press event.
|
||||
// Returns true if the event is consumed and need no more handling.
|
||||
bool handleKeyPressEvent(QKeyEvent *p_event);
|
||||
@ -38,6 +101,18 @@ public:
|
||||
// Set current mode.
|
||||
void setMode(VimMode p_mode);
|
||||
|
||||
// Set current register.
|
||||
void setRegister(QChar p_reg);
|
||||
|
||||
// Get m_registers.
|
||||
const QMap<QChar, Register> &getRegisters() const;
|
||||
|
||||
QChar getCurrentRegisterName() const;
|
||||
|
||||
// Get pending keys.
|
||||
// Turn m_pendingKeys to a string.
|
||||
QString getPendingKeys() const;
|
||||
|
||||
signals:
|
||||
// Emit when current mode has been changed.
|
||||
void modeChanged(VimMode p_mode);
|
||||
@ -45,6 +120,9 @@ signals:
|
||||
// Emit when VVim want to display some messages.
|
||||
void vimMessage(const QString &p_msg);
|
||||
|
||||
// Emit when current status updated.
|
||||
void vimStatusUpdated(const VVim *p_vim);
|
||||
|
||||
private slots:
|
||||
// When user use mouse to select texts in Normal mode, we should change to
|
||||
// Visual mode.
|
||||
@ -265,69 +343,6 @@ private:
|
||||
Key m_key;
|
||||
};
|
||||
|
||||
struct Register
|
||||
{
|
||||
Register(QChar p_name, const QString &p_value)
|
||||
: m_name(p_name), m_value(p_value), m_append(false)
|
||||
{
|
||||
}
|
||||
|
||||
Register(QChar p_name)
|
||||
: m_name(p_name), m_append(false)
|
||||
{
|
||||
}
|
||||
|
||||
Register()
|
||||
: m_append(false)
|
||||
{
|
||||
}
|
||||
|
||||
// Register a-z.
|
||||
bool isNamedRegister() const
|
||||
{
|
||||
char ch = m_name.toLatin1();
|
||||
return ch >= 'a' && ch <= 'z';
|
||||
}
|
||||
|
||||
bool isUnnamedRegister() const
|
||||
{
|
||||
return m_name == c_unnamedRegister;
|
||||
}
|
||||
|
||||
bool isBlackHoleRegister() const
|
||||
{
|
||||
return m_name == c_blackHoleRegister;
|
||||
}
|
||||
|
||||
bool isSelectionRegister() const
|
||||
{
|
||||
return m_name == c_selectionRegister;
|
||||
}
|
||||
|
||||
bool isBlock() const
|
||||
{
|
||||
return m_value.endsWith('\n');
|
||||
}
|
||||
|
||||
// @p_value is the content to update.
|
||||
// If @p_value ends with \n, then it is a block.
|
||||
// When @p_value is a block, we need to add \n at the end if necessary.
|
||||
// If @m_append is true and @p_value is a block, we need to add \n between
|
||||
// them if necessary.
|
||||
void update(const QString &p_value);
|
||||
|
||||
// Read the value of this register.
|
||||
const QString &read();
|
||||
|
||||
QChar m_name;
|
||||
QString m_value;
|
||||
|
||||
// This is not info of Register itself, but a hint to the handling logics
|
||||
// whether we need to append the content to this register.
|
||||
// Only valid for a-z registers.
|
||||
bool m_append;
|
||||
};
|
||||
|
||||
// Reset all key state info.
|
||||
void resetState();
|
||||
|
||||
@ -468,10 +483,13 @@ private:
|
||||
QList<Key> m_keys;
|
||||
QList<Token> m_tokens;
|
||||
|
||||
// Keys for status indication.
|
||||
QList<Key> m_pendingKeys;
|
||||
|
||||
// Whether reset the position in block when moving cursor.
|
||||
bool m_resetPositionInBlock;
|
||||
|
||||
QHash<QChar, Register> m_registers;
|
||||
QMap<QChar, Register> m_registers;
|
||||
|
||||
// Currently used register.
|
||||
QChar m_regName;
|
||||
|
98
src/vbuttonwithwidget.cpp
Normal file
98
src/vbuttonwithwidget.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
#include "vbuttonwithwidget.h"
|
||||
|
||||
#include <QEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QRect>
|
||||
|
||||
VButtonWithWidget::VButtonWithWidget(QWidget *p_parent)
|
||||
: QPushButton(p_parent), m_popupWidget(NULL)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
VButtonWithWidget::VButtonWithWidget(const QString &p_text, QWidget *p_parent)
|
||||
: QPushButton(p_text, p_parent), m_popupWidget(NULL)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
VButtonWithWidget::VButtonWithWidget(const QIcon &p_icon,
|
||||
const QString &p_text,
|
||||
QWidget *p_parent)
|
||||
: QPushButton(p_icon, p_text, p_parent), m_popupWidget(NULL)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
VButtonWithWidget::~VButtonWithWidget()
|
||||
{
|
||||
if (m_popupWidget) {
|
||||
delete m_popupWidget;
|
||||
}
|
||||
}
|
||||
|
||||
void VButtonWithWidget::init()
|
||||
{
|
||||
connect(this, &QPushButton::clicked,
|
||||
this, &VButtonWithWidget::showPopupWidget);
|
||||
}
|
||||
|
||||
void VButtonWithWidget::setPopupWidget(QWidget *p_widget)
|
||||
{
|
||||
if (m_popupWidget) {
|
||||
delete m_popupWidget;
|
||||
}
|
||||
|
||||
m_popupWidget = p_widget;
|
||||
if (m_popupWidget) {
|
||||
m_popupWidget->hide();
|
||||
m_popupWidget->setParent(NULL);
|
||||
|
||||
Qt::WindowFlags flags = Qt::Popup;
|
||||
m_popupWidget->setWindowFlags(flags);
|
||||
m_popupWidget->setWindowModality(Qt::NonModal);
|
||||
|
||||
// Let popup widget to hide itself if focus lost.
|
||||
m_popupWidget->installEventFilter(this);
|
||||
}
|
||||
}
|
||||
|
||||
QWidget *VButtonWithWidget::getPopupWidget() const
|
||||
{
|
||||
return m_popupWidget;
|
||||
}
|
||||
|
||||
void VButtonWithWidget::showPopupWidget()
|
||||
{
|
||||
if (m_popupWidget->isVisible()) {
|
||||
m_popupWidget->hide();
|
||||
} else {
|
||||
emit popupWidgetAboutToShow(m_popupWidget);
|
||||
|
||||
// Calculate the position of the popup widget.
|
||||
QPoint btnPos = mapToGlobal(QPoint(0, 0));
|
||||
int btnWidth = width();
|
||||
|
||||
int popupWidth = btnWidth * 10;
|
||||
int popupHeight = height() * 10;
|
||||
int popupX = btnPos.x() + btnWidth - popupWidth;
|
||||
int popupY = btnPos.y() - popupHeight - 10;
|
||||
|
||||
m_popupWidget->setGeometry(popupX, popupY, popupWidth, popupHeight);
|
||||
m_popupWidget->show();
|
||||
}
|
||||
}
|
||||
|
||||
bool VButtonWithWidget::eventFilter(QObject *p_obj, QEvent *p_event)
|
||||
{
|
||||
if (p_event->type() == QEvent::MouseButtonRelease) {
|
||||
QMouseEvent *eve = dynamic_cast<QMouseEvent *>(p_event);
|
||||
QPoint clickPos = eve->pos();
|
||||
const QRect &rect = m_popupWidget->rect();
|
||||
if (!rect.contains(clickPos)) {
|
||||
m_popupWidget->hide();
|
||||
}
|
||||
}
|
||||
|
||||
return QPushButton::eventFilter(p_obj, p_event);
|
||||
}
|
42
src/vbuttonwithwidget.h
Normal file
42
src/vbuttonwithwidget.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef VBUTTONWITHWIDGET_H
|
||||
#define VBUTTONWITHWIDGET_H
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QString>
|
||||
#include <QIcon>
|
||||
|
||||
// A QPushButton with popup widget.
|
||||
class VButtonWithWidget : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
VButtonWithWidget(QWidget *p_parent = Q_NULLPTR);
|
||||
VButtonWithWidget(const QString &p_text, QWidget *p_parent = Q_NULLPTR);
|
||||
VButtonWithWidget(const QIcon &p_icon,
|
||||
const QString &p_text,
|
||||
QWidget *p_parent = Q_NULLPTR);
|
||||
~VButtonWithWidget();
|
||||
|
||||
// Set the widget which will transfer the ownership to VButtonWithWidget.
|
||||
void setPopupWidget(QWidget *p_widget);
|
||||
|
||||
QWidget *getPopupWidget() const;
|
||||
|
||||
signals:
|
||||
// Emit when popup widget is about to show.
|
||||
void popupWidgetAboutToShow(QWidget *p_widget);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *p_obj, QEvent *p_event) Q_DECL_OVERRIDE;
|
||||
|
||||
private slots:
|
||||
// Show the popup widget.
|
||||
void showPopupWidget();
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
QWidget *m_popupWidget;
|
||||
};
|
||||
|
||||
#endif // VBUTTONWITHWIDGET_H
|
@ -781,3 +781,12 @@ void VEdit::mouseMoveEvent(QMouseEvent *p_event)
|
||||
|
||||
QTextEdit::mouseMoveEvent(p_event);
|
||||
}
|
||||
|
||||
void VEdit::requestUpdateVimStatus()
|
||||
{
|
||||
if (m_editOps) {
|
||||
m_editOps->requestUpdateVimStatus();
|
||||
} else {
|
||||
emit vimStatusUpdated(NULL);
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
class VEditOperations;
|
||||
class QLabel;
|
||||
class QTimer;
|
||||
class VVim;
|
||||
|
||||
enum class SelectionId {
|
||||
CurrentLine = 0,
|
||||
@ -81,6 +82,9 @@ public:
|
||||
|
||||
VEditConfig &getConfig();
|
||||
|
||||
// Request to update Vim status.
|
||||
void requestUpdateVimStatus();
|
||||
|
||||
signals:
|
||||
void saveAndRead();
|
||||
void discardAndRead();
|
||||
@ -92,6 +96,9 @@ signals:
|
||||
// Emit when want to show message in status bar.
|
||||
void statusMessage(const QString &p_msg);
|
||||
|
||||
// Emit when Vim status updated.
|
||||
void vimStatusUpdated(const VVim *p_vim);
|
||||
|
||||
public slots:
|
||||
virtual void highlightCurrentLine();
|
||||
|
||||
|
@ -81,6 +81,8 @@ void VEditArea::insertSplitWindow(int idx)
|
||||
this, &VEditArea::handleCurHeaderChanged);
|
||||
connect(win, &VEditWindow::statusMessage,
|
||||
this, &VEditArea::handleWindowStatusMessage);
|
||||
connect(win, &VEditWindow::vimStatusUpdated,
|
||||
this, &VEditArea::handleWindowVimStatusUpdated);
|
||||
}
|
||||
|
||||
void VEditArea::handleEditWindowStatusChanged(const VFile *p_file,
|
||||
@ -99,6 +101,13 @@ void VEditArea::handleWindowStatusMessage(const QString &p_msg)
|
||||
}
|
||||
}
|
||||
|
||||
void VEditArea::handleWindowVimStatusUpdated(const VVim *p_vim)
|
||||
{
|
||||
if (splitter->widget(curWindowIndex) == sender()) {
|
||||
emit vimStatusUpdated(p_vim);
|
||||
}
|
||||
}
|
||||
|
||||
void VEditArea::removeSplitWindow(VEditWindow *win)
|
||||
{
|
||||
if (!win) {
|
||||
|
@ -20,6 +20,7 @@ class VFile;
|
||||
class VDirectory;
|
||||
class VFindReplaceDialog;
|
||||
class QLabel;
|
||||
class VVim;
|
||||
|
||||
class VEditArea : public QWidget, public VNavigationMode
|
||||
{
|
||||
@ -66,6 +67,9 @@ signals:
|
||||
// Emit when want to show message in status bar.
|
||||
void statusMessage(const QString &p_msg);
|
||||
|
||||
// Emit when Vim status updated.
|
||||
void vimStatusUpdated(const VVim *p_vim);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
|
||||
|
||||
@ -101,6 +105,9 @@ private slots:
|
||||
// Handle the statusMessage signal of VEditWindow.
|
||||
void handleWindowStatusMessage(const QString &p_msg);
|
||||
|
||||
// Handle the vimStatusUpdated signal of VEditWindow.
|
||||
void handleWindowVimStatusUpdated(const VVim *p_vim);
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
QVector<QPair<int, int> > findTabsByFile(const VFile *p_file);
|
||||
|
@ -20,6 +20,8 @@ VEditOperations::VEditOperations(VEdit *p_editor, VFile *p_file)
|
||||
this, &VEditOperations::handleVimModeChanged);
|
||||
connect(m_vim, &VVim::vimMessage,
|
||||
this, &VEditOperations::statusMessage);
|
||||
connect(m_vim, &VVim::vimStatusUpdated,
|
||||
this, &VEditOperations::vimStatusUpdated);
|
||||
}
|
||||
|
||||
void VEditOperations::insertTextAtCurPos(const QString &p_text)
|
||||
@ -80,3 +82,12 @@ void VEditOperations::handleVimModeChanged(VimMode p_mode)
|
||||
|
||||
updateCursorLineBg();
|
||||
}
|
||||
|
||||
void VEditOperations::requestUpdateVimStatus()
|
||||
{
|
||||
if (m_editConfig->m_enableVimMode) {
|
||||
emit vimStatusUpdated(m_vim);
|
||||
} else {
|
||||
emit vimStatusUpdated(NULL);
|
||||
}
|
||||
}
|
||||
|
@ -27,10 +27,16 @@ public:
|
||||
// processed.
|
||||
virtual bool handleKeyPressEvent(QKeyEvent *p_event) = 0;
|
||||
|
||||
// Request to propogate Vim status.
|
||||
void requestUpdateVimStatus();
|
||||
|
||||
signals:
|
||||
// Want to display a template message in status bar.
|
||||
void statusMessage(const QString &p_msg);
|
||||
|
||||
// Propogate Vim status.
|
||||
void vimStatusUpdated(const VVim *p_vim);
|
||||
|
||||
protected slots:
|
||||
// Handle the update of VEditConfig of the editor.
|
||||
virtual void handleEditConfigUpdated();
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <QPointer>
|
||||
#include "vtoc.h"
|
||||
#include "vfile.h"
|
||||
#include "utils/vvim.h"
|
||||
|
||||
class VEditArea;
|
||||
|
||||
@ -63,6 +64,9 @@ public:
|
||||
|
||||
virtual void clearSearchedWordHighlight() = 0;
|
||||
|
||||
// Request current tab to propogate its status about Vim.
|
||||
virtual void requestUpdateVimStatus() = 0;
|
||||
|
||||
public slots:
|
||||
// Enter edit mode
|
||||
virtual void editFile() = 0;
|
||||
@ -96,6 +100,8 @@ signals:
|
||||
// Emit when want to show message in status bar.
|
||||
void statusMessage(const QString &p_msg);
|
||||
|
||||
void vimStatusUpdated(const VVim *p_vim);
|
||||
|
||||
private slots:
|
||||
// Called when app focus changed.
|
||||
void handleFocusChanged(QWidget *p_old, QWidget *p_now);
|
||||
|
@ -270,6 +270,8 @@ int VEditWindow::openFileInTab(VFile *p_file, OpenFileMode p_mode)
|
||||
this, &VEditWindow::handleTabStatusChanged);
|
||||
connect(editor, &VEditTab::statusMessage,
|
||||
this, &VEditWindow::handleTabStatusMessage);
|
||||
connect(editor, &VEditTab::vimStatusUpdated,
|
||||
this, &VEditWindow::handleTabVimStatusUpdated);
|
||||
|
||||
int idx = appendEditTab(p_file, editor);
|
||||
return idx;
|
||||
@ -586,6 +588,14 @@ void VEditWindow::handleTabStatusMessage(const QString &p_msg)
|
||||
}
|
||||
}
|
||||
|
||||
void VEditWindow::handleTabVimStatusUpdated(const VVim *p_vim)
|
||||
{
|
||||
int idx = indexOf(dynamic_cast<QWidget *>(sender()));
|
||||
if (idx == currentIndex()) {
|
||||
emit vimStatusUpdated(p_vim);
|
||||
}
|
||||
}
|
||||
|
||||
void VEditWindow::updateFileInfo(const VFile *p_file)
|
||||
{
|
||||
if (!p_file) {
|
||||
|
@ -71,6 +71,9 @@ signals:
|
||||
// Emit when want to show message in status bar.
|
||||
void statusMessage(const QString &p_msg);
|
||||
|
||||
// Emit when Vim mode status changed.
|
||||
void vimStatusUpdated(const VVim *p_vim);
|
||||
|
||||
private slots:
|
||||
bool handleTabCloseRequest(int index);
|
||||
void splitWindow();
|
||||
@ -91,6 +94,9 @@ private slots:
|
||||
// Handle the statusMessage signal of VEditTab.
|
||||
void handleTabStatusMessage(const QString &p_msg);
|
||||
|
||||
// Handle the vimStatusUpdated() signal of VEditTab.
|
||||
void handleTabVimStatusUpdated(const VVim *p_vim);
|
||||
|
||||
private:
|
||||
void initTabActions();
|
||||
void setupCornerWidget();
|
||||
|
@ -41,6 +41,9 @@ void VHtmlTab::setupUI()
|
||||
this, &VHtmlTab::editFile);
|
||||
connect(m_editor, &VEdit::statusMessage,
|
||||
this, &VEditTab::statusMessage);
|
||||
connect(m_editor, &VEdit::vimStatusUpdated,
|
||||
this, &VEditTab::vimStatusUpdated);
|
||||
|
||||
m_editor->reloadFile();
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout();
|
||||
@ -250,3 +253,8 @@ void VHtmlTab::focusChild()
|
||||
{
|
||||
m_editor->setFocus();
|
||||
}
|
||||
|
||||
void VHtmlTab::requestUpdateVimStatus()
|
||||
{
|
||||
m_editor->requestUpdateVimStatus();
|
||||
}
|
||||
|
@ -46,6 +46,8 @@ public:
|
||||
|
||||
void clearSearchedWordHighlight() Q_DECL_OVERRIDE;
|
||||
|
||||
void requestUpdateVimStatus() Q_DECL_OVERRIDE;
|
||||
|
||||
public slots:
|
||||
// Enter edit mode.
|
||||
void editFile() Q_DECL_OVERRIDE;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "vwebview.h"
|
||||
#include "vexporter.h"
|
||||
#include "vmdtab.h"
|
||||
#include "vvimindicator.h"
|
||||
|
||||
extern VConfigManager vconfig;
|
||||
|
||||
@ -111,12 +112,17 @@ void VMainWindow::setupUI()
|
||||
this, &VMainWindow::handleCurTabStatusChanged);
|
||||
connect(editArea, &VEditArea::statusMessage,
|
||||
this, &VMainWindow::showStatusMessage);
|
||||
connect(editArea, &VEditArea::vimStatusUpdated,
|
||||
this, &VMainWindow::handleVimStatusUpdated);
|
||||
connect(m_findReplaceDialog, &VFindReplaceDialog::findTextChanged,
|
||||
this, &VMainWindow::handleFindDialogTextChanged);
|
||||
|
||||
setCentralWidget(mainSplitter);
|
||||
|
||||
// Create and show the status bar
|
||||
statusBar();
|
||||
m_vimIndicator = new VVimIndicator(this);
|
||||
m_vimIndicator->hide();
|
||||
statusBar()->addPermanentWidget(m_vimIndicator);
|
||||
}
|
||||
|
||||
QWidget *VMainWindow::setupDirectoryPanel()
|
||||
@ -1121,9 +1127,12 @@ void VMainWindow::handleCurTabStatusChanged(const VFile *p_file, const VEditTab
|
||||
title.append('#');
|
||||
}
|
||||
}
|
||||
|
||||
updateWindowTitle(title);
|
||||
m_curFile = const_cast<VFile *>(p_file);
|
||||
m_curTab = const_cast<VEditTab *>(p_editTab);
|
||||
|
||||
updateStatusInfo(p_editMode);
|
||||
}
|
||||
|
||||
void VMainWindow::onePanelView()
|
||||
@ -1496,3 +1505,22 @@ void VMainWindow::showStatusMessage(const QString &p_msg)
|
||||
const int timeout = 3000;
|
||||
statusBar()->showMessage(p_msg, timeout);
|
||||
}
|
||||
|
||||
void VMainWindow::updateStatusInfo(bool p_editMode)
|
||||
{
|
||||
if (!p_editMode || !m_curTab) {
|
||||
m_vimIndicator->hide();
|
||||
} else {
|
||||
m_curTab->requestUpdateVimStatus();
|
||||
}
|
||||
}
|
||||
|
||||
void VMainWindow::handleVimStatusUpdated(const VVim *p_vim)
|
||||
{
|
||||
if (!p_vim || !m_curTab) {
|
||||
m_vimIndicator->hide();
|
||||
} else {
|
||||
m_vimIndicator->update(p_vim);
|
||||
m_vimIndicator->show();
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ class VNotebookSelector;
|
||||
class VAvatar;
|
||||
class VFindReplaceDialog;
|
||||
class VCaptain;
|
||||
class VVimIndicator;
|
||||
|
||||
class VMainWindow : public QMainWindow
|
||||
{
|
||||
@ -88,6 +89,9 @@ private slots:
|
||||
// Show a temporary message in status bar.
|
||||
void showStatusMessage(const QString &p_msg);
|
||||
|
||||
// Handle Vim status updated.
|
||||
void handleVimStatusUpdated(const VVim *p_vim);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
|
||||
void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE;
|
||||
@ -127,6 +131,9 @@ private:
|
||||
void toggleOnePanelView();
|
||||
void closeCurrentFile();
|
||||
|
||||
// Update status bar information according to m_curTab and m_curFile.
|
||||
void updateStatusInfo(bool p_editMode);
|
||||
|
||||
// Wrapper to create a QAction.
|
||||
QAction *newAction(const QIcon &p_icon,
|
||||
const QString &p_text,
|
||||
@ -150,6 +157,7 @@ private:
|
||||
VOutline *outline;
|
||||
VAvatar *m_avatar;
|
||||
VFindReplaceDialog *m_findReplaceDialog;
|
||||
VVimIndicator *m_vimIndicator;
|
||||
|
||||
// Whether it is one panel or two panles.
|
||||
bool m_onePanel;
|
||||
|
@ -53,6 +53,8 @@ VMdEdit::VMdEdit(VFile *p_file, VDocument *p_vdoc, MarkdownConverterType p_type,
|
||||
|
||||
connect(m_editOps, &VEditOperations::statusMessage,
|
||||
this, &VEdit::statusMessage);
|
||||
connect(m_editOps, &VEditOperations::vimStatusUpdated,
|
||||
this, &VEdit::vimStatusUpdated);
|
||||
|
||||
connect(this, &VMdEdit::cursorPositionChanged,
|
||||
this, &VMdEdit::updateCurHeader);
|
||||
|
@ -60,6 +60,8 @@ void VMdTab::setupUI()
|
||||
this, &VMdTab::discardAndRead);
|
||||
connect(m_editor, &VEdit::statusMessage,
|
||||
this, &VEditTab::statusMessage);
|
||||
connect(m_editor, &VEdit::vimStatusUpdated,
|
||||
this, &VEditTab::vimStatusUpdated);
|
||||
|
||||
m_editor->reloadFile();
|
||||
m_stacks->addWidget(m_editor);
|
||||
@ -643,3 +645,12 @@ void VMdTab::focusChild()
|
||||
{
|
||||
m_stacks->currentWidget()->setFocus();
|
||||
}
|
||||
|
||||
void VMdTab::requestUpdateVimStatus()
|
||||
{
|
||||
if (m_editor) {
|
||||
m_editor->requestUpdateVimStatus();
|
||||
} else {
|
||||
emit vimStatusUpdated(NULL);
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,8 @@ public:
|
||||
|
||||
MarkdownConverterType getMarkdownConverterType() const;
|
||||
|
||||
void requestUpdateVimStatus() Q_DECL_OVERRIDE;
|
||||
|
||||
public slots:
|
||||
// Enter edit mode.
|
||||
void editFile() Q_DECL_OVERRIDE;
|
||||
|
@ -66,7 +66,6 @@
|
||||
<file>resources/icons/dir_item.svg</file>
|
||||
<file>resources/icons/notebook_item.svg</file>
|
||||
<file>resources/icons/arrow_dropdown.svg</file>
|
||||
<file>resources/icons/current_tab.svg</file>
|
||||
<file>resources/icons/vnote.png</file>
|
||||
<file>resources/icons/insert_image.svg</file>
|
||||
<file>resources/icons/import_note.svg</file>
|
||||
@ -108,5 +107,6 @@
|
||||
<file>utils/markdown-it/markdown-it-sub.min.js</file>
|
||||
<file>utils/markdown-it/markdown-it-sup.min.js</file>
|
||||
<file>utils/markdown-it/markdown-it-footnote.min.js</file>
|
||||
<file>resources/icons/arrow_dropup.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
174
src/vvimindicator.cpp
Normal file
174
src/vvimindicator.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
#include "vvimindicator.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QHBoxLayout>
|
||||
#include <QTreeWidget>
|
||||
#include <QStringList>
|
||||
#include <QFontMetrics>
|
||||
#include <QFont>
|
||||
#include <QHeaderView>
|
||||
|
||||
#include "vconfigmanager.h"
|
||||
#include "vbuttonwithwidget.h"
|
||||
|
||||
extern VConfigManager vconfig;
|
||||
|
||||
VVimIndicator::VVimIndicator(QWidget *parent)
|
||||
: QWidget(parent), m_vim(NULL)
|
||||
{
|
||||
setupUI();
|
||||
}
|
||||
|
||||
void VVimIndicator::setupUI()
|
||||
{
|
||||
m_modeLabel = new QLabel(this);
|
||||
|
||||
m_regBtn = new VButtonWithWidget(QIcon(":/resources/icons/arrow_dropup.svg"),
|
||||
"\"",
|
||||
this);
|
||||
m_regBtn->setProperty("StatusBtn", true);
|
||||
m_regBtn->setFocusPolicy(Qt::NoFocus);
|
||||
QTreeWidget *regTree = new QTreeWidget(this);
|
||||
regTree->setColumnCount(2);
|
||||
regTree->header()->setStretchLastSection(true);
|
||||
regTree->header()->setProperty("RegisterTree", true);
|
||||
QStringList headers;
|
||||
headers << tr("Register") << tr("Value");
|
||||
regTree->setHeaderLabels(headers);
|
||||
m_regBtn->setPopupWidget(regTree);
|
||||
connect(m_regBtn, &VButtonWithWidget::popupWidgetAboutToShow,
|
||||
this, &VVimIndicator::updateRegistersTree);
|
||||
|
||||
m_keyLabel = new QLabel(this);
|
||||
QFontMetrics metric(font());
|
||||
m_keyLabel->setMinimumWidth(metric.width('A') * 5);
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout(this);
|
||||
mainLayout->addWidget(m_modeLabel);
|
||||
mainLayout->addWidget(m_regBtn);
|
||||
mainLayout->addWidget(m_keyLabel);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
setLayout(mainLayout);
|
||||
}
|
||||
|
||||
QString VVimIndicator::modeToString(VimMode p_mode) const
|
||||
{
|
||||
QString str;
|
||||
|
||||
switch (p_mode) {
|
||||
case VimMode::Normal:
|
||||
str = tr("Normal");
|
||||
break;
|
||||
|
||||
case VimMode::Insert:
|
||||
str = tr("Insert");
|
||||
break;
|
||||
|
||||
case VimMode::Visual:
|
||||
str = tr("Visual");
|
||||
break;
|
||||
|
||||
case VimMode::VisualLine:
|
||||
str = tr("VisualLine");
|
||||
break;
|
||||
|
||||
case VimMode::Replace:
|
||||
str = tr("Replace");
|
||||
break;
|
||||
|
||||
default:
|
||||
str = tr("Unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static QString modeBackgroundColor(VimMode p_mode)
|
||||
{
|
||||
QString color;
|
||||
|
||||
switch (p_mode) {
|
||||
case VimMode::Normal:
|
||||
color = vconfig.getEditorVimNormalBg();
|
||||
break;
|
||||
|
||||
case VimMode::Insert:
|
||||
color = vconfig.getEditorVimInsertBg();
|
||||
break;
|
||||
|
||||
case VimMode::Visual:
|
||||
color = vconfig.getEditorVimVisualBg();
|
||||
break;
|
||||
|
||||
case VimMode::VisualLine:
|
||||
color = vconfig.getEditorVimVisualBg();
|
||||
break;
|
||||
|
||||
case VimMode::Replace:
|
||||
color = vconfig.getEditorVimReplaceBg();
|
||||
break;
|
||||
|
||||
default:
|
||||
color = "red";
|
||||
break;
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
static void fillTreeItemsWithRegisters(QTreeWidget *p_tree,
|
||||
const QMap<QChar, VVim::Register> &p_regs)
|
||||
{
|
||||
p_tree->clear();
|
||||
for (auto const ® : p_regs) {
|
||||
if (reg.m_value.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QStringList itemStr;
|
||||
itemStr << reg.m_name << reg.m_value;
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem(p_tree, itemStr);
|
||||
item->setFlags(item->flags() | Qt::ItemIsSelectable | Qt::ItemIsEditable);
|
||||
}
|
||||
|
||||
p_tree->resizeColumnToContents(0);
|
||||
p_tree->resizeColumnToContents(1);
|
||||
}
|
||||
|
||||
void VVimIndicator::update(const VVim *p_vim)
|
||||
{
|
||||
if (!p_vim) {
|
||||
m_vim = p_vim;
|
||||
return;
|
||||
}
|
||||
|
||||
m_vim = p_vim;
|
||||
|
||||
VimMode mode = p_vim->getMode();
|
||||
QChar curRegName = p_vim->getCurrentRegisterName();
|
||||
|
||||
QString style = QString("QLabel { padding: 0px 2px 0px 2px; font: bold; background-color: %1; }")
|
||||
.arg(modeBackgroundColor(mode));
|
||||
m_modeLabel->setStyleSheet(style);
|
||||
m_modeLabel->setText(modeToString(mode));
|
||||
|
||||
m_regBtn->setText(curRegName);
|
||||
|
||||
QString keyText = QString("<span style=\"font-weight:bold;\">%1</span>")
|
||||
.arg(p_vim->getPendingKeys());
|
||||
m_keyLabel->setText(keyText);
|
||||
}
|
||||
|
||||
void VVimIndicator::updateRegistersTree(QWidget *p_widget)
|
||||
{
|
||||
QTreeWidget *regTree = dynamic_cast<QTreeWidget *>(p_widget);
|
||||
if (!m_vim) {
|
||||
regTree->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
const QMap<QChar, VVim::Register> ®s = m_vim->getRegisters();
|
||||
fillTreeItemsWithRegisters(regTree, regs);
|
||||
}
|
40
src/vvimindicator.h
Normal file
40
src/vvimindicator.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef VVIMINDICATOR_H
|
||||
#define VVIMINDICATOR_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "utils/vvim.h"
|
||||
|
||||
class QLabel;
|
||||
class VButtonWithWidget;
|
||||
|
||||
class VVimIndicator : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VVimIndicator(QWidget *parent = 0);
|
||||
|
||||
public slots:
|
||||
void update(const VVim *p_vim);
|
||||
|
||||
private slots:
|
||||
void updateRegistersTree(QWidget *p_widget);
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
|
||||
QString modeToString(VimMode p_mode) const;
|
||||
|
||||
// Indicate the mode.
|
||||
QLabel *m_modeLabel;
|
||||
|
||||
// Indicate the registers.
|
||||
VButtonWithWidget *m_regBtn;
|
||||
|
||||
// Indicate the pending keys.
|
||||
QLabel *m_keyLabel;
|
||||
|
||||
const VVim *m_vim;
|
||||
};
|
||||
|
||||
#endif // VVIMINDICATOR_H
|
Loading…
x
Reference in New Issue
Block a user