From d40248bb06811d30ace642f4506488970de16473 Mon Sep 17 00:00:00 2001 From: Le Tan Date: Tue, 22 Dec 2020 19:54:48 +0800 Subject: [PATCH] add shortcuts for split and workspace --- src/core/coreconfig.h | 6 +++ src/data/core/vnotex.json | 8 ++- src/widgets/viewarea.cpp | 92 +++++++++++++++++++--------------- src/widgets/viewarea.h | 10 ++-- src/widgets/viewsplit.cpp | 102 ++++++++++++++++++++++++++++++++++++-- src/widgets/viewsplit.h | 8 ++- 6 files changed, 174 insertions(+), 52 deletions(-) diff --git a/src/core/coreconfig.h b/src/core/coreconfig.h index 71d61806..67db9052 100644 --- a/src/core/coreconfig.h +++ b/src/core/coreconfig.h @@ -25,6 +25,12 @@ namespace vnotex OutlineDock, NavigationMode, LocateNode, + VerticalSplit, + HorizontalSplit, + MaximizeSplit, + DistributeSplits, + RemoveSplitAndWorkspace, + NewWorkspace, MaxShortcut }; Q_ENUM(Shortcut) diff --git a/src/data/core/vnotex.json b/src/data/core/vnotex.json index b7c6b761..500b3b7e 100644 --- a/src/data/core/vnotex.json +++ b/src/data/core/vnotex.json @@ -18,7 +18,13 @@ "NavigationDock" : "Ctrl+G, 1", "OutlineDock" : "Ctrl+G, 2", "NavigationMode" : "Ctrl+G, W", - "LocateNode" : "Ctrl+G, D" + "LocateNode" : "Ctrl+G, D", + "VerticalSplit" : "Ctrl+G, \\", + "HorizontalSplit" : "Ctrl+G, -", + "MaximizeSplit" : "Ctrl+G, Shift+\\", + "DistributeSplits" : "Ctrl+G, =", + "RemoveSplitAndWorkspace" : "Ctrl+G, R", + "NewWorkspace" : "Ctrl+G, N" }, "toolbar_icon_size" : 16 }, diff --git a/src/widgets/viewarea.cpp b/src/widgets/viewarea.cpp index 626f0439..1013b443 100644 --- a/src/widgets/viewarea.cpp +++ b/src/widgets/viewarea.cpp @@ -34,7 +34,7 @@ ViewArea::ViewArea(QWidget *p_parent) setAcceptDrops(true); - setupGlobalShortcuts(); + setupShortcuts(); connect(this, &ViewArea::viewSplitsCountChanged, this, &ViewArea::handleViewSplitsCountChange); @@ -238,7 +238,7 @@ ViewSplit *ViewArea::createViewSplit(QWidget *p_parent) }); connect(split, &ViewSplit::focused, this, [this](ViewSplit *p_split) { - setCurrentViewSplit(p_split); + setCurrentViewSplit(p_split, false); checkCurrentViewWindowChange(); }); connect(split, &ViewSplit::currentViewWindowChanged, @@ -285,10 +285,11 @@ void ViewArea::addFirstViewSplit() auto split = createViewSplit(this); m_splits.push_back(split); - setCurrentViewSplit(split); hideSceneWidget(); - m_mainLayout->addWidget(m_currentSplit); + m_mainLayout->addWidget(split); + + setCurrentViewSplit(split, false); emit viewSplitsCountChanged(); checkCurrentViewWindowChange(); @@ -358,12 +359,12 @@ void ViewArea::removeViewSplit(ViewSplit *p_split, bool p_removeWorkspace) // Show scene widget and update current split. if (m_splits.isEmpty()) { Q_ASSERT(newCurrentSplit == nullptr); - setCurrentViewSplit(newCurrentSplit); + setCurrentViewSplit(newCurrentSplit, false); showSceneWidget(); m_fileCheckTimer->stop(); } else if (m_currentSplit == p_split) { - setCurrentViewSplit(newCurrentSplit); + setCurrentViewSplit(newCurrentSplit, true); } emit viewSplitsCountChanged(); @@ -385,9 +386,10 @@ void ViewArea::setCurrentViewWindow(ViewWindow *p_win) auto split = p_win->getViewSplit(); Q_ASSERT(split); - setCurrentViewSplit(split); - split->setCurrentViewWindow(p_win); + + setCurrentViewSplit(split, false); + checkCurrentViewWindowChange(); } @@ -396,7 +398,7 @@ ViewSplit *ViewArea::getCurrentViewSplit() const return m_currentSplit; } -void ViewArea::setCurrentViewSplit(ViewSplit *p_split) +void ViewArea::setCurrentViewSplit(ViewSplit *p_split, bool p_focus) { Q_ASSERT(!p_split || m_splits.contains(p_split)); if (p_split == m_currentSplit) { @@ -410,6 +412,9 @@ void ViewArea::setCurrentViewSplit(ViewSplit *p_split) m_currentSplit = p_split; if (m_currentSplit) { m_currentSplit->setActive(true); + if (p_focus) { + m_currentSplit->focus(); + } } } @@ -506,7 +511,7 @@ void ViewArea::splitViewSplit(ViewSplit *p_split, SplitType p_type) } m_splits.push_back(newSplit); - setCurrentViewSplit(newSplit); + setCurrentViewSplit(newSplit, true); // Let Qt decide the size of splitter first. QCoreApplication::sendPostedEvents(); @@ -653,19 +658,20 @@ void ViewArea::newWorkspaceInViewSplit(ViewSplit *p_split) m_workspaces.push_back(workspace); p_split->setWorkspace(workspace); + setCurrentViewSplit(p_split, true); } bool ViewArea::removeWorkspaceInViewSplit(ViewSplit *p_split, bool p_insertNew) { // Close all the ViewWindows. - setCurrentViewSplit(p_split); - bool stopped = !p_split->forEachViewWindow([this](ViewWindow *p_win) { - bool ret = closeViewWindow(p_win, false, false); - // User cancels closing this ViewWindow, thus cancals closing the ViewSplit. - return ret; + setCurrentViewSplit(p_split, true); + auto wins = getAllViewWindows(p_split, [](ViewWindow *) { + return true; }); - if (stopped) { - return false; + for (const auto win : wins) { + if (!closeViewWindow(win, false, false)) { + return false; + } } Q_ASSERT(p_split->getViewWindowCount() == 0); @@ -723,7 +729,7 @@ void ViewArea::handleViewSplitsCountChange() } } -void ViewArea::forEachViewWindow(const std::function &p_func) +void ViewArea::forEachViewWindow(const ViewSplit::ViewWindowSelector &p_func) { for (auto split : m_splits) { if (!split->forEachViewWindow(p_func)) { @@ -750,7 +756,7 @@ bool ViewArea::close(bool p_force) }); } -void ViewArea::setupGlobalShortcuts() +void ViewArea::setupShortcuts() { const auto &coreConfig = ConfigMgr::getInst().getCoreConfig(); @@ -810,7 +816,7 @@ void ViewArea::checkCurrentViewWindowChange() emit currentViewWindowChanged(); } -bool ViewArea::closeIf(bool p_force, const std::function &p_func) +bool ViewArea::closeIf(bool p_force, const ViewSplit::ViewWindowSelector &p_func) { // Go through all hidden workspace. Use current split to show the workspace. if (m_workspaces.size() > m_splits.size()) { @@ -835,18 +841,14 @@ bool ViewArea::closeIf(bool p_force, const std::function &p_ m_currentSplit->setWorkspace(ws); // Go through this split. - bool stopped = !m_currentSplit->forEachViewWindow([this, p_force, p_func](ViewWindow *p_win) { - if (p_func(p_win)) { - // Do not remove the split even if it is empty. - bool ret = closeViewWindow(p_win, p_force, false); - return ret; - } - return true; - }); - - if (stopped) { - // User cancels the close of one ViewWindow. No need to restore the workspace. - return false; + auto wins = getAllViewWindows(m_currentSplit, p_func); + for (const auto win : wins) { + // Do not remove the split even if it is empty. + bool ret = closeViewWindow(win, p_force, false); + if (!ret) { + // User cancels the close of one ViewWindow. No need to restore the workspace. + return false; + } } // Remove this workspace. @@ -869,12 +871,8 @@ bool ViewArea::closeIf(bool p_force, const std::function &p_ emptySplits.push_back(split); continue; } - split->forEachViewWindow([p_func, &wins](ViewWindow *p_win) { - if (p_func(p_win)) { - wins.push_back(p_win); - } - return true; - }); + + wins.append(getAllViewWindows(split, p_func)); } if (!emptySplits.isEmpty()) { @@ -901,9 +899,9 @@ bool ViewArea::closeIf(bool p_force, const std::function &p_ void ViewArea::focus() { - auto win = getCurrentViewWindow(); - if (win) { - win->setFocus(); + auto split = getCurrentViewSplit(); + if (split) { + split->focus(); } } @@ -972,3 +970,15 @@ void ViewArea::dropEvent(QDropEvent *p_event) QWidget::dropEvent(p_event); } + +QVector ViewArea::getAllViewWindows(ViewSplit *p_split, const ViewSplit::ViewWindowSelector &p_func) +{ + QVector wins; + p_split->forEachViewWindow([p_func, &wins](ViewWindow *p_win) { + if (p_func(p_win)) { + wins.push_back(p_win); + } + return true; + }); + return wins; +} diff --git a/src/widgets/viewarea.h b/src/widgets/viewarea.h index b4864c33..afd073dd 100644 --- a/src/widgets/viewarea.h +++ b/src/widgets/viewarea.h @@ -157,7 +157,7 @@ namespace vnotex void setCurrentViewWindow(ViewWindow *p_win); ViewSplit *getCurrentViewSplit() const; - void setCurrentViewSplit(ViewSplit *p_split); + void setCurrentViewSplit(ViewSplit *p_split, bool p_focus); QSharedPointer createWorkspace(); @@ -182,18 +182,20 @@ namespace vnotex // Iterate through all ViewWindows including both ViewSplits and Workspaces. // Should NOT use this function to close ViewWindow. - void forEachViewWindow(const std::function &p_func); + void forEachViewWindow(const ViewSplit::ViewWindowSelector &p_func); - void setupGlobalShortcuts(); + void setupShortcuts(); // Close all ViewWindows related to @p_node. bool close(Node *p_node, bool p_force); // Go through all ViewWindows and judge whether to close it by @p_func. - bool closeIf(bool p_force, const std::function &p_func); + bool closeIf(bool p_force, const ViewSplit::ViewWindowSelector &p_func); void checkCurrentViewWindowChange(); + QVector getAllViewWindows(ViewSplit *p_split, const ViewSplit::ViewWindowSelector &p_func); + QLayout *m_mainLayout = nullptr; QWidget *m_sceneWidget = nullptr; diff --git a/src/widgets/viewsplit.cpp b/src/widgets/viewsplit.cpp index 8032473b..de2c6b9f 100644 --- a/src/widgets/viewsplit.cpp +++ b/src/widgets/viewsplit.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "viewwindow.h" #include "viewarea.h" @@ -49,6 +50,8 @@ ViewSplit::ViewSplit(const QVector> &p_allWorkspac setupUI(); + setupShortcuts(); + setWorkspace(p_workspace); } @@ -95,6 +98,8 @@ void ViewSplit::focusCurrentViewWindow() auto win = getCurrentViewWindow(); if (win) { win->setFocus(); + } else { + setFocus(); } } @@ -409,6 +414,8 @@ void ViewSplit::updateWindowList(QMenu *p_menu) void ViewSplit::updateMenu(QMenu *p_menu) { + const auto &coreConfig = ConfigMgr::getInst().getCoreConfig(); + p_menu->clear(); const auto &themeMgr = VNoteX::getInst().getThemeMgr(); @@ -445,10 +452,14 @@ void ViewSplit::updateMenu(QMenu *p_menu) } p_menu->addSeparator(); - p_menu->addAction(tr("New Workspace"), - [this]() { - emit newWorkspaceRequested(this); - }); + + { + auto act = p_menu->addAction(tr("New Workspace"), + [this]() { + emit newWorkspaceRequested(this); + }); + WidgetUtils::addActionShortcutText(act, coreConfig.getShortcut(CoreConfig::NewWorkspace)); + } p_menu->addAction(tr("Remove Workspace"), [this]() { @@ -465,6 +476,7 @@ void ViewSplit::updateMenu(QMenu *p_menu) [this]() { emit verticalSplitRequested(this); }); + WidgetUtils::addActionShortcutText(act, coreConfig.getShortcut(CoreConfig::VerticalSplit)); icon = themeMgr.getIconFile(QStringLiteral("horizontal_split.svg")); act = p_menu->addAction(IconUtils::fetchIconWithDisabledState(icon), @@ -472,16 +484,19 @@ void ViewSplit::updateMenu(QMenu *p_menu) [this]() { emit horizontalSplitRequested(this); }); + WidgetUtils::addActionShortcutText(act, coreConfig.getShortcut(CoreConfig::HorizontalSplit)); act = p_menu->addAction(tr("Maximize Split"), [this]() { emit maximizeSplitRequested(this); }); + WidgetUtils::addActionShortcutText(act, coreConfig.getShortcut(CoreConfig::MaximizeSplit)); act = p_menu->addAction(tr("Distribute Splits"), [this]() { emit distributeSplitsRequested(); }); + WidgetUtils::addActionShortcutText(act, coreConfig.getShortcut(CoreConfig::DistributeSplits)); act = p_menu->addAction(tr("Remove Split"), [this]() { @@ -492,6 +507,7 @@ void ViewSplit::updateMenu(QMenu *p_menu) [this]() { emit removeSplitAndWorkspaceRequested(this); }); + WidgetUtils::addActionShortcutText(act, coreConfig.getShortcut(CoreConfig::RemoveSplitAndWorkspace)); } } @@ -588,7 +604,7 @@ void ViewSplit::mousePressEvent(QMouseEvent *p_event) emit focused(this); } -bool ViewSplit::forEachViewWindow(const std::function &p_func) +bool ViewSplit::forEachViewWindow(const ViewWindowSelector &p_func) { int cnt = getViewWindowCount(); for (int i = 0; i < cnt; ++i) { @@ -640,3 +656,79 @@ void ViewSplit::dropEvent(QDropEvent *p_event) QTabWidget::dropEvent(p_event); } + +void ViewSplit::setupShortcuts() +{ + const auto &coreConfig = ConfigMgr::getInst().getCoreConfig(); + + // NewWorkspace. + { + auto shortcut = WidgetUtils::createShortcut(coreConfig.getShortcut(CoreConfig::NewWorkspace), this, Qt::WidgetWithChildrenShortcut); + if (shortcut) { + connect(shortcut, &QShortcut::activated, + this, [this]() { + emit newWorkspaceRequested(this); + }); + } + } + + // VerticalSplit. + { + auto shortcut = WidgetUtils::createShortcut(coreConfig.getShortcut(CoreConfig::VerticalSplit), this, Qt::WidgetWithChildrenShortcut); + if (shortcut) { + connect(shortcut, &QShortcut::activated, + this, [this]() { + emit verticalSplitRequested(this); + }); + } + } + + // HorizontalSplit. + { + auto shortcut = WidgetUtils::createShortcut(coreConfig.getShortcut(CoreConfig::HorizontalSplit), this, Qt::WidgetWithChildrenShortcut); + if (shortcut) { + connect(shortcut, &QShortcut::activated, + this, [this]() { + emit horizontalSplitRequested(this); + }); + } + } + + // MaximizeSplit. + { + auto shortcut = WidgetUtils::createShortcut(coreConfig.getShortcut(CoreConfig::MaximizeSplit), this, Qt::WidgetWithChildrenShortcut); + if (shortcut) { + connect(shortcut, &QShortcut::activated, + this, [this]() { + emit maximizeSplitRequested(this); + }); + } + } + + // DistributeSplits. + { + auto shortcut = WidgetUtils::createShortcut(coreConfig.getShortcut(CoreConfig::DistributeSplits), this, Qt::WidgetWithChildrenShortcut); + if (shortcut) { + connect(shortcut, &QShortcut::activated, + this, [this]() { + emit distributeSplitsRequested(); + }); + } + } + + // RemoveSplitAndWorkspace. + { + auto shortcut = WidgetUtils::createShortcut(coreConfig.getShortcut(CoreConfig::RemoveSplitAndWorkspace), this, Qt::WidgetWithChildrenShortcut); + if (shortcut) { + connect(shortcut, &QShortcut::activated, + this, [this]() { + emit removeSplitAndWorkspaceRequested(this); + }); + } + } +} + +void ViewSplit::focus() +{ + focusCurrentViewWindow(); +} diff --git a/src/widgets/viewsplit.h b/src/widgets/viewsplit.h index 71379781..f2526b41 100644 --- a/src/widgets/viewsplit.h +++ b/src/widgets/viewsplit.h @@ -20,6 +20,8 @@ namespace vnotex { Q_OBJECT public: + typedef std::function ViewWindowSelector; + struct ViewWindowNavigationModeInfo { // Top left position of the ViewWindow relative to the view split. @@ -54,10 +56,12 @@ namespace vnotex // @p_func: return true if going well, return false to stop the iteration. // Return false if there is a break. - bool forEachViewWindow(const std::function &p_func); + bool forEachViewWindow(const ViewWindowSelector &p_func); QVector getNavigationModeInfo() const; + void focus(); + signals: void viewWindowCloseRequested(ViewWindow *p_win); @@ -102,6 +106,8 @@ namespace vnotex void setupTabBar(); + void setupShortcuts(); + ViewWindow *getViewWindow(int p_idx) const; void updateAndTakeCurrentWorkspace();