diff --git a/src/resources/themes/v_white/v_white.qss b/src/resources/themes/v_white/v_white.qss index 73fc2ec2..82ddfeef 100644 --- a/src/resources/themes/v_white/v_white.qss +++ b/src/resources/themes/v_white/v_white.qss @@ -412,6 +412,15 @@ QLabel[ColorTealLabel="true"] { border-radius: 2px; background-color: #00796B; } + +QLabel[MenuSeparator="true"] { + padding-top: 5px; + padding-bottom: 5px; + margin-top: 3px; + font: italic; + border-top: 1px solid @menu_separator_bg +} + /* End QLabel */ /* QLineEdit */ diff --git a/src/utils/veditutils.cpp b/src/utils/veditutils.cpp index 4fa85e91..e683a32a 100644 --- a/src/utils/veditutils.cpp +++ b/src/utils/veditutils.cpp @@ -851,6 +851,7 @@ void VEditUtils::insertTitleMark(QTextCursor &p_cursor, // Remove all the prefix. QRegExp prefixReg(VUtils::c_headerPrefixRegExp); bool preMatched = prefixReg.exactMatch(text); + Q_UNUSED(preMatched); Q_ASSERT(preMatched); length = prefixReg.cap(1).length(); } diff --git a/src/vbuttonmenuitem.cpp b/src/vbuttonmenuitem.cpp index e51e4c99..a0914b1c 100644 --- a/src/vbuttonmenuitem.cpp +++ b/src/vbuttonmenuitem.cpp @@ -1,15 +1,36 @@ #include "vbuttonmenuitem.h" #include +#include +#include +#include +#include VButtonMenuItem::VButtonMenuItem(QAction *p_action, QWidget *p_parent) - : QPushButton(p_parent), m_action(p_action) + : QPushButton(p_parent), + m_action(p_action), + m_decorationWidth(0) { init(); } VButtonMenuItem::VButtonMenuItem(QAction *p_action, const QString &p_text, QWidget *p_parent) - : QPushButton(p_text, p_parent), m_action(p_action) + : QPushButton(p_text, p_parent), + m_action(p_action), + m_decorationWidth(0) +{ + init(); +} + +VButtonMenuItem::VButtonMenuItem(QAction *p_action, + const QIcon &p_icon, + const QString &p_text, + const QString &p_decorationText, + QWidget *p_parent) + : QPushButton(p_icon, p_text, p_parent), + m_action(p_action), + m_decorationText(p_decorationText), + m_decorationWidth(0) { init(); } @@ -19,3 +40,32 @@ void VButtonMenuItem::init() connect(this, &QPushButton::clicked, m_action, &QAction::triggered); } + +void VButtonMenuItem::paintEvent(QPaintEvent *p_event) +{ + QPushButton::paintEvent(p_event); + + if (m_decorationWidth > 0) { + Q_ASSERT(!m_decorationText.isEmpty()); + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + QFont font = painter.font(); + font.setItalic(true); + painter.setFont(font); + + QRect re = rect(); + re.adjust(re.width() - m_decorationWidth, 0, 0, 0); + painter.drawText(re, Qt::AlignCenter, m_decorationText); + } +} + +QSize VButtonMenuItem::sizeHint() const +{ + QSize size = QPushButton::sizeHint(); + if (!m_decorationText.isEmpty()) { + const_cast(this)->m_decorationWidth = 5 + fontMetrics().width(m_decorationText); + size.rwidth() += m_decorationWidth; + } + + return size; +} diff --git a/src/vbuttonmenuitem.h b/src/vbuttonmenuitem.h index a7e53055..4324b130 100644 --- a/src/vbuttonmenuitem.h +++ b/src/vbuttonmenuitem.h @@ -4,6 +4,7 @@ #include class QAction; +class QPaintEvent; class VButtonMenuItem : public QPushButton @@ -14,10 +15,27 @@ public: VButtonMenuItem(QAction *p_action, const QString &p_text, QWidget *p_parent = nullptr); + VButtonMenuItem(QAction *p_action, + const QIcon &p_icon, + const QString &p_text, + const QString &p_decorationText = QString(), + QWidget *p_parent = nullptr); + + QSize sizeHint() const Q_DECL_OVERRIDE; + +protected: + void paintEvent(QPaintEvent *p_event) Q_DECL_OVERRIDE; + private: void init(); QAction *m_action; + + // Decoration text drawn at the right end. + QString m_decorationText; + + // Width in pixels of the decoration text. + int m_decorationWidth; }; #endif // VBUTTONMENUITEM_H diff --git a/src/veditwindow.cpp b/src/veditwindow.cpp index 656a0848..8381625f 100644 --- a/src/veditwindow.cpp +++ b/src/veditwindow.cpp @@ -702,6 +702,7 @@ void VEditWindow::tabListJump(VFile *p_file) int idx = findTabByFile(p_file); Q_ASSERT(idx >= 0); setCurrentIndex(idx); + focusWindow(); updateTabStatus(idx); } @@ -1004,8 +1005,10 @@ bool VEditWindow::showOpenedFileList() if (count() == 0) { return false; } + leftBtn->showMenu(); - return true; + VOpenedListMenu *menu = dynamic_cast(leftBtn->menu()); + return menu->isAccepted(); } bool VEditWindow::activateTab(int p_sequence) diff --git a/src/vopenedlistmenu.cpp b/src/vopenedlistmenu.cpp index df8eb38c..7dce1878 100644 --- a/src/vopenedlistmenu.cpp +++ b/src/vopenedlistmenu.cpp @@ -6,12 +6,16 @@ #include #include #include +#include +#include #include "veditwindow.h" #include "vnotefile.h" #include "vedittab.h" #include "vdirectory.h" #include "utils/vutils.h" +#include "vbuttonmenuitem.h" +#include "utils/vimnavigationforwidget.h" static const int c_cmdTime = 1 * 1000; @@ -51,14 +55,11 @@ static bool fileComp(const VOpenedListMenu::ItemInfo &a, } VOpenedListMenu::VOpenedListMenu(VEditWindow *p_editWin) - : QMenu(p_editWin), m_editWin(p_editWin), m_cmdNum(0) + : QMenu(p_editWin), + m_editWin(p_editWin), + m_cmdNum(0), + m_accepted(false) { - // Force to display separator text on Windows and macOS. - setStyle(QStyleFactory::create("Fusion")); - int separatorHeight = 20 * VUtils::calculateScaleFactor(); - QString style = QString("::separator { color: #009688; height: %1px; padding-top: 3px; }").arg(separatorHeight); - setStyleSheet(style); - setToolTipsVisible(true); m_cmdTimer = new QTimer(this); @@ -78,6 +79,7 @@ void VOpenedListMenu::updateOpenedList() // Regenerate the opened list. m_seqActionMap.clear(); clear(); + m_accepted = false; int curTab = m_editWin->currentIndex(); int nrTab = m_editWin->count(); @@ -87,12 +89,12 @@ void VOpenedListMenu::updateOpenedList() files[i].index = i; } + Q_ASSERT(!files.isEmpty()); + std::sort(files.begin(), files.end(), fileComp); QString notebook; const VDirectory *directory = NULL; - QFont sepFont; - sepFont.setItalic(true); for (int i = 0; i < nrTab; ++i) { QPointer file = files[i].file; int index = files[i].index; @@ -108,6 +110,7 @@ void VOpenedListMenu::updateOpenedList() curNotebook = "EXTERNAL_FILES"; } + QString separatorText; if (curNotebook != notebook || curDirectory != directory) { notebook = curNotebook; @@ -117,28 +120,42 @@ void VOpenedListMenu::updateOpenedList() dirName = directory->getName(); } - QString text; if (dirName.isEmpty()) { - text = QString("[%1]").arg(notebook); + separatorText = QString("[%1]").arg(notebook); } else { - text = QString("[%1] %2").arg(notebook).arg(dirName); + separatorText = QString("[%1] %2").arg(notebook).arg(dirName); } - QAction *sepAct = addSection(text); - sepAct->setFont(sepFont); + // Add label as separator. + QWidgetAction *wact = new QWidgetAction(this); + QLabel *label = new QLabel(separatorText); + label->setProperty("MenuSeparator", true); + wact->setDefaultWidget(label); + wact->setSeparator(true); + addAction(wact); } - QAction *action = new QAction(m_editWin->tabIcon(index), - m_editWin->tabText(index)); - action->setToolTip(generateDescription(file)); - action->setData(QVariant::fromValue(file)); + // Append the separator text to the end of the first item as well. + QWidgetAction *wact = new QWidgetAction(this); + wact->setData(QVariant::fromValue(file)); + VButtonMenuItem *w = new VButtonMenuItem(wact, + m_editWin->tabIcon(index), + m_editWin->tabText(index), + separatorText, + this); + w->setToolTip(generateDescription(file)); + wact->setDefaultWidget(w); + if (index == curTab) { - QFont boldFont; + QFont boldFont = w->font(); boldFont.setBold(true); - action->setFont(boldFont); + w->setFont(boldFont); + + w->setFocus(); } - addAction(action); - m_seqActionMap[index + c_tabSequenceBase] = action; + + addAction(wact); + m_seqActionMap[index + c_tabSequenceBase] = wact; } } @@ -159,17 +176,27 @@ QString VOpenedListMenu::generateDescription(const VFile *p_file) const void VOpenedListMenu::handleItemTriggered(QAction *p_action) { - if (!p_action) { - return; + if (p_action) { + QPointer file = p_action->data().value>(); + if (file) { + m_accepted = true; + emit fileTriggered(file); + } } - QPointer file = p_action->data().value>(); - emit fileTriggered(file); + + hide(); } void VOpenedListMenu::keyPressEvent(QKeyEvent *p_event) { + if (VimNavigationForWidget::injectKeyPressEventForVim(this, + p_event)) { + m_cmdTimer->stop(); + m_cmdNum = 0; + return; + } + int key = p_event->key(); - int modifiers = p_event->modifiers(); switch (key) { case Qt::Key_0: case Qt::Key_1: @@ -186,93 +213,6 @@ void VOpenedListMenu::keyPressEvent(QKeyEvent *p_event) return; } - case Qt::Key_BracketLeft: - { - m_cmdTimer->stop(); - m_cmdNum = 0; - if (modifiers == Qt::ControlModifier) { - hide(); - return; - } - - break; - } - - case Qt::Key_J: - { - m_cmdTimer->stop(); - m_cmdNum = 0; - if (VUtils::isControlModifierForVim(modifiers)) { - QList acts = actions(); - if (acts.size() == 0) { - return; - } - int idx = 0; - QAction *act = activeAction(); - if (act) { - for (int i = 0; i < acts.size(); ++i) { - if (acts.at(i) == act) { - idx = i + 1; - break; - } - } - } - while (true) { - if (idx >= acts.size()) { - idx = 0; - } - act = acts.at(idx); - if (act->isSeparator() || !act->isVisible()) { - ++idx; - } else { - break; - } - } - setActiveAction(act); - return; - } - - break; - } - - case Qt::Key_K: - { - m_cmdTimer->stop(); - m_cmdNum = 0; - if (VUtils::isControlModifierForVim(modifiers)) { - QList acts = actions(); - if (acts.size() == 0) { - return; - } - - int idx = acts.size() - 1; - QAction *act = activeAction(); - if (act) { - for (int i = 0; i < acts.size(); ++i) { - if (acts.at(i) == act) { - idx = i - 1; - break; - } - } - } - while (true) { - if (idx < 0) { - idx = acts.size() - 1; - } - act = acts.at(idx); - if (act->isSeparator() || !act->isVisible()) { - --idx; - } else { - break; - } - } - setActiveAction(act); - return; - } - - break; - } - default: m_cmdTimer->stop(); m_cmdNum = 0; @@ -304,13 +244,8 @@ void VOpenedListMenu::addDigit(int p_digit) m_cmdNum = 0; return; } - // Set active action to the candidate. - auto it = m_seqActionMap.find(m_cmdNum); - if (it != m_seqActionMap.end()) { - QAction *act = it.value(); - setActiveAction(act); - } } + m_cmdTimer->start(); } diff --git a/src/vopenedlistmenu.h b/src/vopenedlistmenu.h index 2efc02e5..4084cf70 100644 --- a/src/vopenedlistmenu.h +++ b/src/vopenedlistmenu.h @@ -21,6 +21,8 @@ public: explicit VOpenedListMenu(VEditWindow *p_editWin); + bool isAccepted() const; + protected: void keyPressEvent(QKeyEvent *p_event) Q_DECL_OVERRIDE; @@ -39,10 +41,19 @@ private: void triggerItem(int p_seq); VEditWindow *m_editWin; + // The number user pressed. int m_cmdNum; + QTimer *m_cmdTimer; QMap m_seqActionMap; + + // Whether the menu is accepted or rejected. + bool m_accepted; }; +inline bool VOpenedListMenu::isAccepted() const +{ + return m_accepted; +} #endif // VOPENEDLISTMENU_H