add shortcuts for split and workspace

This commit is contained in:
Le Tan 2020-12-22 19:54:48 +08:00
parent 0735764a34
commit d40248bb06
6 changed files with 174 additions and 52 deletions

View File

@ -25,6 +25,12 @@ namespace vnotex
OutlineDock, OutlineDock,
NavigationMode, NavigationMode,
LocateNode, LocateNode,
VerticalSplit,
HorizontalSplit,
MaximizeSplit,
DistributeSplits,
RemoveSplitAndWorkspace,
NewWorkspace,
MaxShortcut MaxShortcut
}; };
Q_ENUM(Shortcut) Q_ENUM(Shortcut)

View File

@ -18,7 +18,13 @@
"NavigationDock" : "Ctrl+G, 1", "NavigationDock" : "Ctrl+G, 1",
"OutlineDock" : "Ctrl+G, 2", "OutlineDock" : "Ctrl+G, 2",
"NavigationMode" : "Ctrl+G, W", "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 "toolbar_icon_size" : 16
}, },

View File

@ -34,7 +34,7 @@ ViewArea::ViewArea(QWidget *p_parent)
setAcceptDrops(true); setAcceptDrops(true);
setupGlobalShortcuts(); setupShortcuts();
connect(this, &ViewArea::viewSplitsCountChanged, connect(this, &ViewArea::viewSplitsCountChanged,
this, &ViewArea::handleViewSplitsCountChange); this, &ViewArea::handleViewSplitsCountChange);
@ -238,7 +238,7 @@ ViewSplit *ViewArea::createViewSplit(QWidget *p_parent)
}); });
connect(split, &ViewSplit::focused, connect(split, &ViewSplit::focused,
this, [this](ViewSplit *p_split) { this, [this](ViewSplit *p_split) {
setCurrentViewSplit(p_split); setCurrentViewSplit(p_split, false);
checkCurrentViewWindowChange(); checkCurrentViewWindowChange();
}); });
connect(split, &ViewSplit::currentViewWindowChanged, connect(split, &ViewSplit::currentViewWindowChanged,
@ -285,10 +285,11 @@ void ViewArea::addFirstViewSplit()
auto split = createViewSplit(this); auto split = createViewSplit(this);
m_splits.push_back(split); m_splits.push_back(split);
setCurrentViewSplit(split);
hideSceneWidget(); hideSceneWidget();
m_mainLayout->addWidget(m_currentSplit); m_mainLayout->addWidget(split);
setCurrentViewSplit(split, false);
emit viewSplitsCountChanged(); emit viewSplitsCountChanged();
checkCurrentViewWindowChange(); checkCurrentViewWindowChange();
@ -358,12 +359,12 @@ void ViewArea::removeViewSplit(ViewSplit *p_split, bool p_removeWorkspace)
// Show scene widget and update current split. // Show scene widget and update current split.
if (m_splits.isEmpty()) { if (m_splits.isEmpty()) {
Q_ASSERT(newCurrentSplit == nullptr); Q_ASSERT(newCurrentSplit == nullptr);
setCurrentViewSplit(newCurrentSplit); setCurrentViewSplit(newCurrentSplit, false);
showSceneWidget(); showSceneWidget();
m_fileCheckTimer->stop(); m_fileCheckTimer->stop();
} else if (m_currentSplit == p_split) { } else if (m_currentSplit == p_split) {
setCurrentViewSplit(newCurrentSplit); setCurrentViewSplit(newCurrentSplit, true);
} }
emit viewSplitsCountChanged(); emit viewSplitsCountChanged();
@ -385,9 +386,10 @@ void ViewArea::setCurrentViewWindow(ViewWindow *p_win)
auto split = p_win->getViewSplit(); auto split = p_win->getViewSplit();
Q_ASSERT(split); Q_ASSERT(split);
setCurrentViewSplit(split);
split->setCurrentViewWindow(p_win); split->setCurrentViewWindow(p_win);
setCurrentViewSplit(split, false);
checkCurrentViewWindowChange(); checkCurrentViewWindowChange();
} }
@ -396,7 +398,7 @@ ViewSplit *ViewArea::getCurrentViewSplit() const
return m_currentSplit; 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)); Q_ASSERT(!p_split || m_splits.contains(p_split));
if (p_split == m_currentSplit) { if (p_split == m_currentSplit) {
@ -410,6 +412,9 @@ void ViewArea::setCurrentViewSplit(ViewSplit *p_split)
m_currentSplit = p_split; m_currentSplit = p_split;
if (m_currentSplit) { if (m_currentSplit) {
m_currentSplit->setActive(true); 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); m_splits.push_back(newSplit);
setCurrentViewSplit(newSplit); setCurrentViewSplit(newSplit, true);
// Let Qt decide the size of splitter first. // Let Qt decide the size of splitter first.
QCoreApplication::sendPostedEvents(); QCoreApplication::sendPostedEvents();
@ -653,19 +658,20 @@ void ViewArea::newWorkspaceInViewSplit(ViewSplit *p_split)
m_workspaces.push_back(workspace); m_workspaces.push_back(workspace);
p_split->setWorkspace(workspace); p_split->setWorkspace(workspace);
setCurrentViewSplit(p_split, true);
} }
bool ViewArea::removeWorkspaceInViewSplit(ViewSplit *p_split, bool p_insertNew) bool ViewArea::removeWorkspaceInViewSplit(ViewSplit *p_split, bool p_insertNew)
{ {
// Close all the ViewWindows. // Close all the ViewWindows.
setCurrentViewSplit(p_split); setCurrentViewSplit(p_split, true);
bool stopped = !p_split->forEachViewWindow([this](ViewWindow *p_win) { auto wins = getAllViewWindows(p_split, [](ViewWindow *) {
bool ret = closeViewWindow(p_win, false, false); return true;
// User cancels closing this ViewWindow, thus cancals closing the ViewSplit.
return ret;
}); });
if (stopped) { for (const auto win : wins) {
return false; if (!closeViewWindow(win, false, false)) {
return false;
}
} }
Q_ASSERT(p_split->getViewWindowCount() == 0); Q_ASSERT(p_split->getViewWindowCount() == 0);
@ -723,7 +729,7 @@ void ViewArea::handleViewSplitsCountChange()
} }
} }
void ViewArea::forEachViewWindow(const std::function<bool(ViewWindow *)> &p_func) void ViewArea::forEachViewWindow(const ViewSplit::ViewWindowSelector &p_func)
{ {
for (auto split : m_splits) { for (auto split : m_splits) {
if (!split->forEachViewWindow(p_func)) { 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(); const auto &coreConfig = ConfigMgr::getInst().getCoreConfig();
@ -810,7 +816,7 @@ void ViewArea::checkCurrentViewWindowChange()
emit currentViewWindowChanged(); emit currentViewWindowChanged();
} }
bool ViewArea::closeIf(bool p_force, const std::function<bool(ViewWindow *)> &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. // Go through all hidden workspace. Use current split to show the workspace.
if (m_workspaces.size() > m_splits.size()) { if (m_workspaces.size() > m_splits.size()) {
@ -835,18 +841,14 @@ bool ViewArea::closeIf(bool p_force, const std::function<bool(ViewWindow *)> &p_
m_currentSplit->setWorkspace(ws); m_currentSplit->setWorkspace(ws);
// Go through this split. // Go through this split.
bool stopped = !m_currentSplit->forEachViewWindow([this, p_force, p_func](ViewWindow *p_win) { auto wins = getAllViewWindows(m_currentSplit, p_func);
if (p_func(p_win)) { for (const auto win : wins) {
// Do not remove the split even if it is empty. // Do not remove the split even if it is empty.
bool ret = closeViewWindow(p_win, p_force, false); bool ret = closeViewWindow(win, p_force, false);
return ret; if (!ret) {
} // User cancels the close of one ViewWindow. No need to restore the workspace.
return true; return false;
}); }
if (stopped) {
// User cancels the close of one ViewWindow. No need to restore the workspace.
return false;
} }
// Remove this workspace. // Remove this workspace.
@ -869,12 +871,8 @@ bool ViewArea::closeIf(bool p_force, const std::function<bool(ViewWindow *)> &p_
emptySplits.push_back(split); emptySplits.push_back(split);
continue; continue;
} }
split->forEachViewWindow([p_func, &wins](ViewWindow *p_win) {
if (p_func(p_win)) { wins.append(getAllViewWindows(split, p_func));
wins.push_back(p_win);
}
return true;
});
} }
if (!emptySplits.isEmpty()) { if (!emptySplits.isEmpty()) {
@ -901,9 +899,9 @@ bool ViewArea::closeIf(bool p_force, const std::function<bool(ViewWindow *)> &p_
void ViewArea::focus() void ViewArea::focus()
{ {
auto win = getCurrentViewWindow(); auto split = getCurrentViewSplit();
if (win) { if (split) {
win->setFocus(); split->focus();
} }
} }
@ -972,3 +970,15 @@ void ViewArea::dropEvent(QDropEvent *p_event)
QWidget::dropEvent(p_event); QWidget::dropEvent(p_event);
} }
QVector<ViewWindow *> ViewArea::getAllViewWindows(ViewSplit *p_split, const ViewSplit::ViewWindowSelector &p_func)
{
QVector<ViewWindow *> wins;
p_split->forEachViewWindow([p_func, &wins](ViewWindow *p_win) {
if (p_func(p_win)) {
wins.push_back(p_win);
}
return true;
});
return wins;
}

View File

@ -157,7 +157,7 @@ namespace vnotex
void setCurrentViewWindow(ViewWindow *p_win); void setCurrentViewWindow(ViewWindow *p_win);
ViewSplit *getCurrentViewSplit() const; ViewSplit *getCurrentViewSplit() const;
void setCurrentViewSplit(ViewSplit *p_split); void setCurrentViewSplit(ViewSplit *p_split, bool p_focus);
QSharedPointer<ViewWorkspace> createWorkspace(); QSharedPointer<ViewWorkspace> createWorkspace();
@ -182,18 +182,20 @@ namespace vnotex
// Iterate through all ViewWindows including both ViewSplits and Workspaces. // Iterate through all ViewWindows including both ViewSplits and Workspaces.
// Should NOT use this function to close ViewWindow. // Should NOT use this function to close ViewWindow.
void forEachViewWindow(const std::function<bool(ViewWindow *)> &p_func); void forEachViewWindow(const ViewSplit::ViewWindowSelector &p_func);
void setupGlobalShortcuts(); void setupShortcuts();
// Close all ViewWindows related to @p_node. // Close all ViewWindows related to @p_node.
bool close(Node *p_node, bool p_force); bool close(Node *p_node, bool p_force);
// Go through all ViewWindows and judge whether to close it by @p_func. // Go through all ViewWindows and judge whether to close it by @p_func.
bool closeIf(bool p_force, const std::function<bool(ViewWindow *)> &p_func); bool closeIf(bool p_force, const ViewSplit::ViewWindowSelector &p_func);
void checkCurrentViewWindowChange(); void checkCurrentViewWindowChange();
QVector<ViewWindow *> getAllViewWindows(ViewSplit *p_split, const ViewSplit::ViewWindowSelector &p_func);
QLayout *m_mainLayout = nullptr; QLayout *m_mainLayout = nullptr;
QWidget *m_sceneWidget = nullptr; QWidget *m_sceneWidget = nullptr;

View File

@ -9,6 +9,7 @@
#include <QTabBar> #include <QTabBar>
#include <QMimeData> #include <QMimeData>
#include <QFileInfo> #include <QFileInfo>
#include <QShortcut>
#include "viewwindow.h" #include "viewwindow.h"
#include "viewarea.h" #include "viewarea.h"
@ -49,6 +50,8 @@ ViewSplit::ViewSplit(const QVector<QSharedPointer<ViewWorkspace>> &p_allWorkspac
setupUI(); setupUI();
setupShortcuts();
setWorkspace(p_workspace); setWorkspace(p_workspace);
} }
@ -95,6 +98,8 @@ void ViewSplit::focusCurrentViewWindow()
auto win = getCurrentViewWindow(); auto win = getCurrentViewWindow();
if (win) { if (win) {
win->setFocus(); win->setFocus();
} else {
setFocus();
} }
} }
@ -409,6 +414,8 @@ void ViewSplit::updateWindowList(QMenu *p_menu)
void ViewSplit::updateMenu(QMenu *p_menu) void ViewSplit::updateMenu(QMenu *p_menu)
{ {
const auto &coreConfig = ConfigMgr::getInst().getCoreConfig();
p_menu->clear(); p_menu->clear();
const auto &themeMgr = VNoteX::getInst().getThemeMgr(); const auto &themeMgr = VNoteX::getInst().getThemeMgr();
@ -445,10 +452,14 @@ void ViewSplit::updateMenu(QMenu *p_menu)
} }
p_menu->addSeparator(); 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"), p_menu->addAction(tr("Remove Workspace"),
[this]() { [this]() {
@ -465,6 +476,7 @@ void ViewSplit::updateMenu(QMenu *p_menu)
[this]() { [this]() {
emit verticalSplitRequested(this); emit verticalSplitRequested(this);
}); });
WidgetUtils::addActionShortcutText(act, coreConfig.getShortcut(CoreConfig::VerticalSplit));
icon = themeMgr.getIconFile(QStringLiteral("horizontal_split.svg")); icon = themeMgr.getIconFile(QStringLiteral("horizontal_split.svg"));
act = p_menu->addAction(IconUtils::fetchIconWithDisabledState(icon), act = p_menu->addAction(IconUtils::fetchIconWithDisabledState(icon),
@ -472,16 +484,19 @@ void ViewSplit::updateMenu(QMenu *p_menu)
[this]() { [this]() {
emit horizontalSplitRequested(this); emit horizontalSplitRequested(this);
}); });
WidgetUtils::addActionShortcutText(act, coreConfig.getShortcut(CoreConfig::HorizontalSplit));
act = p_menu->addAction(tr("Maximize Split"), act = p_menu->addAction(tr("Maximize Split"),
[this]() { [this]() {
emit maximizeSplitRequested(this); emit maximizeSplitRequested(this);
}); });
WidgetUtils::addActionShortcutText(act, coreConfig.getShortcut(CoreConfig::MaximizeSplit));
act = p_menu->addAction(tr("Distribute Splits"), act = p_menu->addAction(tr("Distribute Splits"),
[this]() { [this]() {
emit distributeSplitsRequested(); emit distributeSplitsRequested();
}); });
WidgetUtils::addActionShortcutText(act, coreConfig.getShortcut(CoreConfig::DistributeSplits));
act = p_menu->addAction(tr("Remove Split"), act = p_menu->addAction(tr("Remove Split"),
[this]() { [this]() {
@ -492,6 +507,7 @@ void ViewSplit::updateMenu(QMenu *p_menu)
[this]() { [this]() {
emit removeSplitAndWorkspaceRequested(this); emit removeSplitAndWorkspaceRequested(this);
}); });
WidgetUtils::addActionShortcutText(act, coreConfig.getShortcut(CoreConfig::RemoveSplitAndWorkspace));
} }
} }
@ -588,7 +604,7 @@ void ViewSplit::mousePressEvent(QMouseEvent *p_event)
emit focused(this); emit focused(this);
} }
bool ViewSplit::forEachViewWindow(const std::function<bool(ViewWindow *)> &p_func) bool ViewSplit::forEachViewWindow(const ViewWindowSelector &p_func)
{ {
int cnt = getViewWindowCount(); int cnt = getViewWindowCount();
for (int i = 0; i < cnt; ++i) { for (int i = 0; i < cnt; ++i) {
@ -640,3 +656,79 @@ void ViewSplit::dropEvent(QDropEvent *p_event)
QTabWidget::dropEvent(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();
}

View File

@ -20,6 +20,8 @@ namespace vnotex
{ {
Q_OBJECT Q_OBJECT
public: public:
typedef std::function<bool(ViewWindow *)> ViewWindowSelector;
struct ViewWindowNavigationModeInfo struct ViewWindowNavigationModeInfo
{ {
// Top left position of the ViewWindow relative to the view split. // 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. // @p_func: return true if going well, return false to stop the iteration.
// Return false if there is a break. // Return false if there is a break.
bool forEachViewWindow(const std::function<bool(ViewWindow *)> &p_func); bool forEachViewWindow(const ViewWindowSelector &p_func);
QVector<ViewWindowNavigationModeInfo> getNavigationModeInfo() const; QVector<ViewWindowNavigationModeInfo> getNavigationModeInfo() const;
void focus();
signals: signals:
void viewWindowCloseRequested(ViewWindow *p_win); void viewWindowCloseRequested(ViewWindow *p_win);
@ -102,6 +106,8 @@ namespace vnotex
void setupTabBar(); void setupTabBar();
void setupShortcuts();
ViewWindow *getViewWindow(int p_idx) const; ViewWindow *getViewWindow(int p_idx) const;
void updateAndTakeCurrentWorkspace(); void updateAndTakeCurrentWorkspace();