diff --git a/src/resources/vnote.ini b/src/resources/vnote.ini index 7d03b02c..fa482d81 100644 --- a/src/resources/vnote.ini +++ b/src/resources/vnote.ini @@ -300,6 +300,8 @@ FlashPage=Ctrl+Alt+L OpenViaDefaultProgram=F12 ; Full screen FullScreen=F11 +; Universal Entry +UniversalEntry=Ctrl+G [captain_mode_shortcuts] ; Define shortcuts in Captain mode here. diff --git a/src/src.pro b/src/src.pro index 5b63bce3..40472ed8 100644 --- a/src/src.pro +++ b/src/src.pro @@ -117,7 +117,8 @@ SOURCES += main.cpp\ vsearcher.cpp \ vsearch.cpp \ vsearchresulttree.cpp \ - vsearchengine.cpp + vsearchengine.cpp \ + vuniversalentry.cpp HEADERS += vmainwindow.h \ vdirectorytree.h \ @@ -224,7 +225,8 @@ HEADERS += vmainwindow.h \ vsearchresulttree.h \ isearchengine.h \ vsearchconfig.h \ - vsearchengine.h + vsearchengine.h \ + vuniversalentry.h RESOURCES += \ vnote.qrc \ diff --git a/src/vcaptain.cpp b/src/vcaptain.cpp index 916d5e21..6fda6ccd 100644 --- a/src/vcaptain.cpp +++ b/src/vcaptain.cpp @@ -29,10 +29,10 @@ VCaptain::VCaptain(QWidget *p_parent) // Register Captain mode leader key. // This can fix the Input Method blocking issue. - QShortcut *shortcut = new QShortcut(QKeySequence(g_config->getShortcutKeySequence("CaptainMode")), - this); - shortcut->setContext(Qt::ApplicationShortcut); - connect(shortcut, &QShortcut::activated, + m_captainModeShortcut = new QShortcut(QKeySequence(g_config->getShortcutKeySequence("CaptainMode")), + this); + m_captainModeShortcut->setContext(Qt::ApplicationShortcut); + connect(m_captainModeShortcut, &QShortcut::activated, this, &VCaptain::trigger); // Register Navigation mode as Captain mode target. @@ -280,3 +280,8 @@ bool VCaptain::handleKeyPressCaptainMode(int p_key, return true; } + +void VCaptain::setCaptainModeEnabled(bool p_enabled) +{ + m_captainModeShortcut->setEnabled(p_enabled); +} diff --git a/src/vcaptain.h b/src/vcaptain.h index 15d4670f..48416180 100644 --- a/src/vcaptain.h +++ b/src/vcaptain.h @@ -43,6 +43,8 @@ public: void *p_target, CaptainFunc p_func); + void setCaptainModeEnabled(bool p_enabled); + signals: // Emit when mode changed. void captainModeChanged(bool p_captainMode); @@ -171,6 +173,8 @@ private: // Ignore focus change during handling Captain and Navigation target actions. bool m_ignoreFocusChange; + + QShortcut *m_captainModeShortcut; }; inline void VCaptain::setMode(CaptainMode p_mode) @@ -182,5 +186,4 @@ inline bool VCaptain::checkMode(CaptainMode p_mode) const { return m_mode == p_mode; } - #endif // VCAPTAIN_H diff --git a/src/veditarea.cpp b/src/veditarea.cpp index 71099606..605a529f 100644 --- a/src/veditarea.cpp +++ b/src/veditarea.cpp @@ -1105,3 +1105,14 @@ void VEditArea::handleFileTimerTimeout() } } } + +QRect VEditArea::editAreaRect() const +{ + QRect rt = rect(); + int nrWin = splitter->count(); + if (nrWin > 0) { + rt.setTopLeft(QPoint(0, getWindow(0)->tabBarHeight())); + } + + return rt; +} diff --git a/src/veditarea.h b/src/veditarea.h index e8b0dc46..165dab70 100644 --- a/src/veditarea.h +++ b/src/veditarea.h @@ -83,6 +83,9 @@ public: // Record a closed file in the stack. void recordClosedFile(const VFileSessionInfo &p_file); + // Return the rect not containing the tab bar. + QRect editAreaRect() const; + signals: // Emit when current window's tab status updated. void tabStatusUpdated(const VEditTabInfo &p_info); diff --git a/src/veditwindow.cpp b/src/veditwindow.cpp index ecac0f27..5467cb9f 100644 --- a/src/veditwindow.cpp +++ b/src/veditwindow.cpp @@ -1191,3 +1191,8 @@ void VEditWindow::tabRequestToClose(VEditTab *p_tab) p_tab->deleteLater(); } } + +int VEditWindow::tabBarHeight() const +{ + return tabBar()->height(); +} diff --git a/src/veditwindow.h b/src/veditwindow.h index 0226b100..e9e406e4 100644 --- a/src/veditwindow.h +++ b/src/veditwindow.h @@ -83,6 +83,8 @@ public: // Auto save file. void saveAll(); + int tabBarHeight() const; + protected: void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; diff --git a/src/vmainwindow.cpp b/src/vmainwindow.cpp index f3091783..d359f6f0 100644 --- a/src/vmainwindow.cpp +++ b/src/vmainwindow.cpp @@ -39,6 +39,7 @@ #include "vcart.h" #include "dialog/vexportdialog.h" #include "vsearcher.h" +#include "vuniversalentry.h" extern VConfigManager *g_config; @@ -64,7 +65,8 @@ VMainWindow::VMainWindow(VSingleInstanceGuard *p_guard, QWidget *p_parent) m_guard(p_guard), m_windowOldState(Qt::WindowNoState), m_requestQuit(false), - m_printer(NULL) + m_printer(NULL), + m_ue(NULL) { qsrand(QDateTime::currentDateTime().toTime_t()); @@ -145,7 +147,7 @@ void VMainWindow::registerCaptainAndNavigationTargets() m_captain->registerNavigationTarget(notebookSelector); m_captain->registerNavigationTarget(directoryTree); m_captain->registerNavigationTarget(m_fileList); - m_captain->registerNavigationTarget(editArea); + m_captain->registerNavigationTarget(m_editArea); m_captain->registerNavigationTarget(m_toolBox); m_captain->registerNavigationTarget(outline); m_captain->registerNavigationTarget(m_snippetList); @@ -205,11 +207,11 @@ void VMainWindow::setupUI() m_fileList = new VFileList(); m_fileList->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); - editArea = new VEditArea(); - editArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - m_findReplaceDialog = editArea->getFindReplaceDialog(); - m_fileList->setEditArea(editArea); - directoryTree->setEditArea(editArea); + m_editArea = new VEditArea(); + m_editArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + m_findReplaceDialog = m_editArea->getFindReplaceDialog(); + m_fileList->setEditArea(m_editArea); + directoryTree->setEditArea(m_editArea); // Main Splitter m_mainSplitter = new QSplitter(); @@ -217,7 +219,7 @@ void VMainWindow::setupUI() m_mainSplitter->addWidget(directoryPanel); m_mainSplitter->addWidget(m_fileList); setTabOrder(directoryTree, m_fileList->getContentWidget()); - m_mainSplitter->addWidget(editArea); + m_mainSplitter->addWidget(m_editArea); m_mainSplitter->setStretchFactor(0, 0); m_mainSplitter->setStretchFactor(1, 0); m_mainSplitter->setStretchFactor(2, 1); @@ -226,10 +228,10 @@ void VMainWindow::setupUI() connect(directoryTree, &VDirectoryTree::currentDirectoryChanged, m_fileList, &VFileList::setDirectory); connect(directoryTree, &VDirectoryTree::directoryUpdated, - editArea, &VEditArea::handleDirectoryUpdated); + m_editArea, &VEditArea::handleDirectoryUpdated); connect(notebookSelector, &VNotebookSelector::notebookUpdated, - editArea, &VEditArea::handleNotebookUpdated); + m_editArea, &VEditArea::handleNotebookUpdated); connect(notebookSelector, &VNotebookSelector::notebookCreated, directoryTree, [this](const QString &p_name, bool p_import) { Q_UNUSED(p_name); @@ -239,16 +241,16 @@ void VMainWindow::setupUI() }); connect(m_fileList, &VFileList::fileClicked, - editArea, &VEditArea::openFile); + m_editArea, &VEditArea::openFile); connect(m_fileList, &VFileList::fileCreated, - editArea, &VEditArea::openFile); + m_editArea, &VEditArea::openFile); connect(m_fileList, &VFileList::fileUpdated, - editArea, &VEditArea::handleFileUpdated); - connect(editArea, &VEditArea::tabStatusUpdated, + m_editArea, &VEditArea::handleFileUpdated); + connect(m_editArea, &VEditArea::tabStatusUpdated, this, &VMainWindow::handleAreaTabStatusUpdated); - connect(editArea, &VEditArea::statusMessage, + connect(m_editArea, &VEditArea::statusMessage, this, &VMainWindow::showStatusMessage); - connect(editArea, &VEditArea::vimStatusUpdated, + connect(m_editArea, &VEditArea::vimStatusUpdated, this, &VMainWindow::handleVimStatusUpdated); connect(m_findReplaceDialog, &VFindReplaceDialog::findTextChanged, this, &VMainWindow::handleFindDialogTextChanged); @@ -705,7 +707,7 @@ void VMainWindow::initFileToolBar(QSize p_iconSize) VUtils::fixTextWithCaptainShortcut(m_discardExitAct, "DiscardAndRead"); m_discardExitAct->setStatusTip(tr("Discard changes and exit edit mode")); connect(m_discardExitAct, &QAction::triggered, - editArea, &VEditArea::readFile); + m_editArea, &VEditArea::readFile); updateEditReadAct(NULL); @@ -720,7 +722,7 @@ void VMainWindow::initFileToolBar(QSize p_iconSize) } connect(saveNoteAct, &QAction::triggered, - editArea, &VEditArea::saveFile); + m_editArea, &VEditArea::saveFile); newRootDirAct->setEnabled(false); newNoteAct->setEnabled(false); @@ -778,7 +780,7 @@ void VMainWindow::initHelpMenu() this, [this](){ QString docFile = VUtils::getDocFile(VNote::c_markdownGuideDocFile); VFile *file = vnote->getOrphanFile(docFile, false, true); - editArea->openFile(file, OpenFileMode::Read); + m_editArea->openFile(file, OpenFileMode::Read); }); QAction *docAct = new QAction(tr("&Documentation"), this); @@ -1306,12 +1308,12 @@ void VMainWindow::initToolsDock() // Outline tree. outline = new VOutline(this); - connect(editArea, &VEditArea::outlineChanged, + connect(m_editArea, &VEditArea::outlineChanged, outline, &VOutline::updateOutline); - connect(editArea, &VEditArea::currentHeaderChanged, + connect(m_editArea, &VEditArea::currentHeaderChanged, outline, &VOutline::updateCurrentHeader); connect(outline, &VOutline::outlineItemActivated, - editArea, &VEditArea::scrollToHeader); + m_editArea, &VEditArea::scrollToHeader); // Snippets. m_snippetList = new VSnippetList(this); @@ -2196,7 +2198,7 @@ void VMainWindow::closeEvent(QCloseEvent *event) QVector fileInfos; QVector tabs; if (saveOpenedNotes) { - tabs = editArea->getAllTabsInfo(); + tabs = m_editArea->getAllTabsInfo(); fileInfos.reserve(tabs.size()); @@ -2215,7 +2217,7 @@ void VMainWindow::closeEvent(QCloseEvent *event) } } - if (!editArea->closeAllFiles(false)) { + if (!m_editArea->closeAllFiles(false)) { // Fail to close all the opened files, cancel closing app. event->ignore(); return; @@ -2380,7 +2382,7 @@ void VMainWindow::handleFindDialogTextChanged(const QString &p_text, uint /* p_o void VMainWindow::openFindDialog() { - m_findReplaceDialog->openDialog(editArea->getSelectedText()); + m_findReplaceDialog->openDialog(m_editArea->getSelectedText()); } void VMainWindow::viewSettings() @@ -2392,7 +2394,7 @@ void VMainWindow::viewSettings() void VMainWindow::closeCurrentFile() { if (m_curFile) { - editArea->closeFile(m_curFile, false); + m_editArea->closeFile(m_curFile, false); } } @@ -2454,7 +2456,7 @@ void VMainWindow::shortcutsHelp() { QString docFile = VUtils::getDocFile(VNote::c_shortcutsDocFile); VFile *file = vnote->getOrphanFile(docFile, false, true); - editArea->openFile(file, OpenFileMode::Read); + m_editArea->openFile(file, OpenFileMode::Read); } void VMainWindow::printNote() @@ -2549,7 +2551,7 @@ bool VMainWindow::tryOpenInternalFile(const QString &p_filePath) VFile *file = vnote->getInternalFile(p_filePath); if (file) { - editArea->openFile(file, OpenFileMode::Read); + m_editArea->openFile(file, OpenFileMode::Read); return true; } } @@ -2572,7 +2574,7 @@ void VMainWindow::openFiles(const QStringList &p_files, file = vnote->getOrphanFile(p_files[i], true); } - editArea->openFile(file, p_mode, p_forceMode); + m_editArea->openFile(file, p_mode, p_forceMode); } } @@ -2667,7 +2669,7 @@ void VMainWindow::openStartupPages() { QVector files = g_config->getLastOpenedFiles(); qDebug() << "open" << files.size() << "last opened files"; - editArea->openFiles(files); + m_editArea->openFiles(files); break; } @@ -2788,7 +2790,7 @@ bool VMainWindow::closeFileByCaptain(void *p_target, void *p_data) VMainWindow *obj = static_cast(p_target); obj->closeCurrentFile(); - QWidget *nextFocus = obj->editArea->getCurrentTab(); + QWidget *nextFocus = obj->m_editArea->getCurrentTab(); if (nextFocus) { nextFocus->setFocus(); } else { @@ -2846,6 +2848,15 @@ void VMainWindow::initShortcuts() connect(closeNoteShortcut, &QShortcut::activated, this, &VMainWindow::closeCurrentFile); } + + keySeq = g_config->getShortcutKeySequence("UniversalEntry"); + qDebug() << "set UniversalEntry shortcut to" << keySeq; + if (!keySeq.isEmpty()) { + QShortcut *ueShortcut = new QShortcut(QKeySequence(keySeq), this); + ueShortcut->setContext(Qt::WidgetWithChildrenShortcut); + connect(ueShortcut, &QShortcut::activated, + this, &VMainWindow::activateUniversalEntry); + } } void VMainWindow::openFlashPage() @@ -3091,10 +3102,10 @@ void VMainWindow::toggleEditReadMode() if (m_curTab->isEditMode()) { // Save changes and read. - editArea->saveAndReadFile(); + m_editArea->saveAndReadFile(); } else { // Edit. - editArea->editFile(); + m_editArea->editFile(); } } @@ -3154,3 +3165,34 @@ VNotebook *VMainWindow::getCurrentNotebook() const { return notebookSelector->currentNotebook(); } + +void VMainWindow::activateUniversalEntry() +{ + if (!m_ue) { + m_ue = new VUniversalEntry(this); + m_ue->hide(); + m_ue->setWindowFlags(Qt::Popup + | Qt::FramelessWindowHint + | Qt::NoDropShadowWindowHint); + connect(m_ue, &VUniversalEntry::exited, + this, [this]() { + m_captain->setCaptainModeEnabled(true); + }); + } + + m_captain->setCaptainModeEnabled(false); + + // Move it to the top left corner of edit area. + QPoint topLeft = m_editArea->mapToGlobal(QPoint(0, 0)); + QRect eaRect = m_editArea->editAreaRect(); + topLeft += eaRect.topLeft(); + + // Use global position. + m_ue->move(topLeft); + + eaRect.moveTop(0); + m_ue->setAvailableRect(eaRect); + + m_ue->show(); + m_ue->raise(); +} diff --git a/src/vmainwindow.h b/src/vmainwindow.h index a74c2a52..2e61bed4 100644 --- a/src/vmainwindow.h +++ b/src/vmainwindow.h @@ -41,6 +41,7 @@ class VSnippetList; class VCart; class VSearcher; class QPrinter; +class VUniversalEntry; enum class PanelViewState { @@ -182,6 +183,9 @@ private slots: void toggleEditReadMode(); + // Activate Universal Entry. + void activateUniversalEntry(); + protected: void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE; @@ -231,6 +235,7 @@ private: void initEditorLineNumberMenu(QMenu *p_menu); void initEditorStyleMenu(QMenu *p_emnu); + void updateWindowTitle(const QString &str); void initVimCmd(); @@ -323,7 +328,7 @@ private: // Move directory and file panel in one compact vertical split. QSplitter *m_naviSplitter; - VEditArea *editArea; + VEditArea *m_editArea; QDockWidget *m_toolDock; @@ -433,6 +438,8 @@ private: QPrinter *m_printer; + VUniversalEntry *m_ue; + // Interval of the shared memory timer in ms. static const int c_sharedMemTimerInterval; }; @@ -444,7 +451,7 @@ inline VFileList *VMainWindow::getFileList() const inline VEditArea *VMainWindow::getEditArea() const { - return editArea; + return m_editArea; } inline VCaptain *VMainWindow::getCaptain() const diff --git a/src/vuniversalentry.cpp b/src/vuniversalentry.cpp new file mode 100644 index 00000000..689c1763 --- /dev/null +++ b/src/vuniversalentry.cpp @@ -0,0 +1,58 @@ +#include "vuniversalentry.h" + +#include +#include +#include +#include +#include + +#include "vlineedit.h" +#include "utils/vutils.h" + +#define MINIMUM_WIDTH 200 + +VUniversalEntry::VUniversalEntry(QWidget *p_parent) + : QWidget(p_parent), + m_availableRect(0, 0, MINIMUM_WIDTH, MINIMUM_WIDTH) +{ + m_minimumWidth = MINIMUM_WIDTH * VUtils::calculateScaleFactor() + 0.5; + setupUI(); +} + +void VUniversalEntry::setupUI() +{ + m_cmdEdit = new VLineEdit(this); + m_cmdEdit->setPlaceholderText(tr("Welcome to Universal Entry")); + + m_layout = new QVBoxLayout(); + m_layout->addWidget(m_cmdEdit); + + m_layout->setContentsMargins(0, 0, 0, 0); + + setLayout(m_layout); + + setMinimumWidth(m_minimumWidth); +} + +void VUniversalEntry::hideEvent(QHideEvent *p_event) +{ + QWidget::hideEvent(p_event); + emit exited(); +} + +void VUniversalEntry::showEvent(QShowEvent *p_event) +{ + QWidget::showEvent(p_event); + + m_cmdEdit->setFocus(); + m_cmdEdit->selectAll(); +} + +void VUniversalEntry::setAvailableRect(const QRect &p_rect) +{ + m_availableRect = p_rect; + + if (m_availableRect.width() < m_minimumWidth) { + m_availableRect.setWidth(m_minimumWidth); + } +} diff --git a/src/vuniversalentry.h b/src/vuniversalentry.h new file mode 100644 index 00000000..55d60b65 --- /dev/null +++ b/src/vuniversalentry.h @@ -0,0 +1,43 @@ +#ifndef VUNIVERSALENTRY_H +#define VUNIVERSALENTRY_H + +#include +#include + +class VLineEdit; +class QVBoxLayout; +class QHideEvent; +class QShowEvent; + +class VUniversalEntry : public QWidget +{ + Q_OBJECT +public: + explicit VUniversalEntry(QWidget *p_parent = nullptr); + + // Set the availabel width and height. + void setAvailableRect(const QRect &p_rect); + +signals: + // Exit Universal Entry. + void exited(); + +protected: + void hideEvent(QHideEvent *p_event) Q_DECL_OVERRIDE; + + void showEvent(QShowEvent *p_event) Q_DECL_OVERRIDE; + +private: + void setupUI(); + + VLineEdit *m_cmdEdit; + + QVBoxLayout *m_layout; + + // Rect availabel for the UE to use. + QRect m_availableRect; + + int m_minimumWidth; +}; + +#endif // VUNIVERSALENTRY_H