mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
Add Navigation Mode to Captain Mode
In Captain Mode, W will trigger the Navigation Mode. In this mode, registered widgets will display some characters for hints and after user pressing the the keys, corresponding widget will take action as response. For now, only VNotebookSelector registers in the Navigation Mode.
This commit is contained in:
parent
f7f4bb1569
commit
6a5fecf8ef
@ -100,7 +100,8 @@ HEADERS += vmainwindow.h \
|
||||
dialog/vdeletenotebookdialog.h \
|
||||
dialog/vselectdialog.h \
|
||||
vcaptain.h \
|
||||
vopenedlistmenu.h
|
||||
vopenedlistmenu.h \
|
||||
vnavigationmode.h
|
||||
|
||||
RESOURCES += \
|
||||
vnote.qrc \
|
||||
|
@ -360,3 +360,10 @@ bool VUtils::realEqual(qreal p_a, qreal p_b)
|
||||
return std::abs(p_a - p_b) < 1e-8;
|
||||
}
|
||||
|
||||
QChar VUtils::keyToChar(int p_key)
|
||||
{
|
||||
if (p_key >= Qt::Key_A && p_key <= Qt::Key_Z) {
|
||||
return QChar('a' + p_key - Qt::Key_A);
|
||||
}
|
||||
return QChar();
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ public:
|
||||
static bool isImageURLText(const QString &p_url);
|
||||
static qreal calculateScaleFactor();
|
||||
static bool realEqual(qreal p_a, qreal p_b);
|
||||
static QChar keyToChar(int p_key);
|
||||
|
||||
private:
|
||||
// <value, name>
|
||||
|
@ -8,13 +8,14 @@
|
||||
#include "veditarea.h"
|
||||
#include "vedittab.h"
|
||||
#include "vfilelist.h"
|
||||
#include "vnavigationmode.h"
|
||||
|
||||
// 3s pending time after the leader keys.
|
||||
const int c_pendingTime = 3 * 1000;
|
||||
|
||||
VCaptain::VCaptain(VMainWindow *p_parent)
|
||||
: QWidget(p_parent), m_mainWindow(p_parent), m_mode(VCaptain::Normal),
|
||||
m_widgetBeforeCaptain(NULL)
|
||||
m_widgetBeforeCaptain(NULL), m_nextMajorKey('a')
|
||||
{
|
||||
m_pendingTimer = new QTimer(this);
|
||||
m_pendingTimer->setSingleShot(true);
|
||||
@ -38,6 +39,26 @@ VCaptain::VCaptain(VMainWindow *p_parent)
|
||||
resize(1, 1);
|
||||
}
|
||||
|
||||
QChar VCaptain::getNextMajorKey()
|
||||
{
|
||||
QChar ret = m_nextMajorKey;
|
||||
if (m_nextMajorKey == 'z') {
|
||||
m_nextMajorKey = QChar();
|
||||
} else if (!m_nextMajorKey.isNull()) {
|
||||
m_nextMajorKey = QChar(m_nextMajorKey.toLatin1() + 1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void VCaptain::registerNavigationTarget(VNavigationMode *p_target)
|
||||
{
|
||||
QChar key = getNextMajorKey();
|
||||
if (!key.isNull()) {
|
||||
p_target->registerNavigation(key);
|
||||
m_targets.append(NaviModeTarget(p_target, true));
|
||||
}
|
||||
}
|
||||
|
||||
// In pending mode, if user click other widgets, we need to exit Captain mode.
|
||||
void VCaptain::handleFocusChanged(QWidget *p_old, QWidget * /* p_now */)
|
||||
{
|
||||
@ -55,7 +76,7 @@ void VCaptain::pendingTimerTimeout()
|
||||
|
||||
void VCaptain::trigger()
|
||||
{
|
||||
if (m_mode == VCaptain::Pending) {
|
||||
if (m_mode != VCaptain::Normal) {
|
||||
return;
|
||||
}
|
||||
qDebug() << "trigger Captain mode";
|
||||
@ -73,7 +94,6 @@ void VCaptain::keyPressEvent(QKeyEvent *p_event)
|
||||
{
|
||||
int key = p_event->key();
|
||||
Qt::KeyboardModifiers modifiers = p_event->modifiers();
|
||||
qDebug() << "VCaptain key pressed" << key << modifiers;
|
||||
|
||||
if (m_mode == VCaptain::Normal) {
|
||||
// Should not in focus while in Normal mode.
|
||||
@ -83,7 +103,6 @@ void VCaptain::keyPressEvent(QKeyEvent *p_event)
|
||||
}
|
||||
|
||||
if (key == Qt::Key_Control || key == Qt::Key_Shift) {
|
||||
qDebug() << "VCaptain ignore key event";
|
||||
QWidget::keyPressEvent(p_event);
|
||||
return;
|
||||
}
|
||||
@ -97,7 +116,6 @@ void VCaptain::keyPressEvent(QKeyEvent *p_event)
|
||||
|
||||
bool VCaptain::handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers)
|
||||
{
|
||||
qDebug() << "handleKeyPress" << p_key << p_modifiers;
|
||||
bool ret = true;
|
||||
|
||||
if (p_key == Qt::Key_Escape
|
||||
@ -106,6 +124,10 @@ bool VCaptain::handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (m_mode == VCaptainMode::Navigation) {
|
||||
return handleKeyPressNavigationMode(p_key, p_modifiers);
|
||||
}
|
||||
|
||||
// In Captain mode, Ctrl key won't make a difference.
|
||||
switch (p_key) {
|
||||
case Qt::Key_1:
|
||||
@ -248,9 +270,13 @@ bool VCaptain::handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers)
|
||||
m_mainWindow->editArea->splitCurrentWindow();
|
||||
// Do not restore focus.
|
||||
m_widgetBeforeCaptain = NULL;
|
||||
|
||||
break;
|
||||
|
||||
case Qt::Key_W:
|
||||
// Enter navigation mode.
|
||||
triggerNavigationMode();
|
||||
return ret;
|
||||
|
||||
case Qt::Key_X:
|
||||
{
|
||||
// Close current tab.
|
||||
@ -273,9 +299,58 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool VCaptain::handleKeyPressNavigationMode(int p_key,
|
||||
Qt::KeyboardModifiers /* p_modifiers */)
|
||||
{
|
||||
Q_ASSERT(m_mode == VCaptainMode::Navigation);
|
||||
for (auto target : m_targets) {
|
||||
if (target.m_available) {
|
||||
bool succeed = false;
|
||||
bool consumed = target.m_target->handleKeyNavigation(p_key, succeed);
|
||||
if (consumed) {
|
||||
if (succeed) {
|
||||
// Exit.
|
||||
m_widgetBeforeCaptain = NULL;
|
||||
break;
|
||||
} else {
|
||||
// Consumed but not succeed. Need more keys.
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// Do not ask this target any more.
|
||||
target.m_available = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
exitCaptainMode();
|
||||
restoreFocus();
|
||||
return true;
|
||||
}
|
||||
|
||||
void VCaptain::triggerNavigationMode()
|
||||
{
|
||||
m_pendingTimer->stop();
|
||||
m_mode = VCaptainMode::Navigation;
|
||||
|
||||
for (auto target : m_targets) {
|
||||
target.m_available = true;
|
||||
target.m_target->showNavigation();
|
||||
}
|
||||
}
|
||||
|
||||
void VCaptain::exitNavigationMode()
|
||||
{
|
||||
m_mode = VCaptainMode::Normal;
|
||||
|
||||
for (auto target : m_targets) {
|
||||
target.m_available = true;
|
||||
target.m_target->hideNavigation();
|
||||
}
|
||||
}
|
||||
|
||||
bool VCaptain::eventFilter(QObject *p_obj, QEvent *p_event)
|
||||
{
|
||||
if (m_mode == VCaptain::Pending && p_event->type() == QEvent::Shortcut) {
|
||||
if (m_mode != VCaptain::Normal && p_event->type() == QEvent::Shortcut) {
|
||||
qDebug() << "filter" << p_event;
|
||||
QShortcutEvent *keyEve = dynamic_cast<QShortcutEvent *>(p_event);
|
||||
Q_ASSERT(keyEve);
|
||||
@ -303,6 +378,9 @@ void VCaptain::restoreFocus()
|
||||
|
||||
void VCaptain::exitCaptainMode()
|
||||
{
|
||||
if (m_mode == VCaptainMode::Navigation) {
|
||||
exitNavigationMode();
|
||||
}
|
||||
m_mode = VCaptain::Normal;
|
||||
m_pendingTimer->stop();
|
||||
|
||||
|
@ -2,11 +2,13 @@
|
||||
#define VCAPTAIN_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QList>
|
||||
|
||||
class QTimer;
|
||||
class QKeyEvent;
|
||||
class VMainWindow;
|
||||
class QEvent;
|
||||
class VNavigationMode;
|
||||
|
||||
class VCaptain : public QWidget
|
||||
{
|
||||
@ -17,6 +19,9 @@ public:
|
||||
// Trigger Captain mode.
|
||||
void trigger();
|
||||
|
||||
// Register a target for Navigation Mode.
|
||||
void registerNavigationTarget(VNavigationMode *p_target);
|
||||
|
||||
signals:
|
||||
void captainModeChanged(bool p_enabled);
|
||||
|
||||
@ -37,10 +42,16 @@ private:
|
||||
// Return true if finish handling the event; otherwise, let the base widget
|
||||
// to handle it.
|
||||
bool handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers);
|
||||
bool handleKeyPressNavigationMode(int p_key,
|
||||
Qt::KeyboardModifiers p_modifiers);
|
||||
QChar getNextMajorKey();
|
||||
void triggerNavigationMode();
|
||||
void exitNavigationMode();
|
||||
|
||||
enum VCaptainMode {
|
||||
Normal = 0,
|
||||
Pending
|
||||
Pending,
|
||||
Navigation
|
||||
};
|
||||
|
||||
VMainWindow *m_mainWindow;
|
||||
@ -48,6 +59,16 @@ private:
|
||||
int m_mode;
|
||||
// The widget which has the focus before entering Captain mode.
|
||||
QWidget* m_widgetBeforeCaptain;
|
||||
|
||||
struct NaviModeTarget {
|
||||
VNavigationMode *m_target;
|
||||
bool m_available;
|
||||
|
||||
NaviModeTarget(VNavigationMode *p_target, bool p_available)
|
||||
: m_target(p_target), m_available(p_available) {}
|
||||
};
|
||||
QList<NaviModeTarget> m_targets;
|
||||
QChar m_nextMajorKey;
|
||||
};
|
||||
|
||||
#endif // VCAPTAIN_H
|
||||
|
@ -49,6 +49,8 @@ void VMainWindow::initCaptain()
|
||||
m_captain = new VCaptain(this);
|
||||
connect(m_captain, &VCaptain::captainModeChanged,
|
||||
this, &VMainWindow::handleCaptainModeChanged);
|
||||
|
||||
m_captain->registerNavigationTarget(notebookSelector);
|
||||
}
|
||||
|
||||
void VMainWindow::setupUI()
|
||||
|
24
src/vnavigationmode.h
Normal file
24
src/vnavigationmode.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef VNAVIGATIONMODE_H
|
||||
#define VNAVIGATIONMODE_H
|
||||
|
||||
#include <QChar>
|
||||
|
||||
// Interface class for Navigation Mode in Captain Mode.
|
||||
class VNavigationMode
|
||||
{
|
||||
public:
|
||||
VNavigationMode() {};
|
||||
virtual ~VNavigationMode() {};
|
||||
|
||||
virtual void registerNavigation(QChar p_majorKey) = 0;
|
||||
virtual void showNavigation() = 0;
|
||||
virtual void hideNavigation() = 0;
|
||||
// Return true if this object could consume p_key.
|
||||
// p_succeed indicates whether the keys hit a target successfully.
|
||||
virtual bool handleKeyNavigation(int p_key, bool &p_succeed) = 0;
|
||||
|
||||
protected:
|
||||
QChar m_majorKey;
|
||||
};
|
||||
|
||||
#endif // VNAVIGATIONMODE_H
|
@ -102,6 +102,17 @@ void VNote::initPalette(QPalette palette)
|
||||
m_palette.append(QPair<QString, QString>("Purple7", "#7B1FA2"));
|
||||
m_palette.append(QPair<QString, QString>("Purple8", "#6A1B9A"));
|
||||
m_palette.append(QPair<QString, QString>("Purple9", "#4A148C"));
|
||||
|
||||
m_palette.append(QPair<QString, QString>("Red0", "#FFEBEE"));
|
||||
m_palette.append(QPair<QString, QString>("Red1", "#FFCDD2"));
|
||||
m_palette.append(QPair<QString, QString>("Red2", "#EF9A9A"));
|
||||
m_palette.append(QPair<QString, QString>("Red3", "#E57373"));
|
||||
m_palette.append(QPair<QString, QString>("Red4", "#EF5350"));
|
||||
m_palette.append(QPair<QString, QString>("Red5", "#F44336"));
|
||||
m_palette.append(QPair<QString, QString>("Red6", "#E53935"));
|
||||
m_palette.append(QPair<QString, QString>("Red7", "#D32F2F"));
|
||||
m_palette.append(QPair<QString, QString>("Red8", "#C62828"));
|
||||
m_palette.append(QPair<QString, QString>("Red9", "#B71C1C"));
|
||||
}
|
||||
|
||||
QString VNote::getColorFromPalette(const QString &p_name) const
|
||||
@ -160,3 +171,12 @@ QVector<VNotebook *> &VNote::getNotebooks()
|
||||
{
|
||||
return m_notebooks;
|
||||
}
|
||||
|
||||
const QString &VNote::getNavigationLabelStyle() const
|
||||
{
|
||||
static const QString stylesheet = QString("color: %1;"
|
||||
"font-size: %2;"
|
||||
"font: bold;").arg(getColorFromPalette("Red5"))
|
||||
.arg("18pt");
|
||||
return stylesheet;
|
||||
}
|
||||
|
@ -54,6 +54,8 @@ public:
|
||||
QString getColorFromPalette(const QString &p_name) const;
|
||||
inline VMainWindow *getMainWindow() const;
|
||||
|
||||
const QString &getNavigationLabelStyle() const;
|
||||
|
||||
public slots:
|
||||
void updateTemplate();
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <QMenu>
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
#include <QLabel>
|
||||
#include "vnotebook.h"
|
||||
#include "vconfigmanager.h"
|
||||
#include "dialog/vnewnotebookdialog.h"
|
||||
@ -19,12 +20,14 @@
|
||||
#include "vnofocusitemdelegate.h"
|
||||
|
||||
extern VConfigManager vconfig;
|
||||
extern VNote *g_vnote;
|
||||
|
||||
const int VNotebookSelector::c_notebookStartIdx = 1;
|
||||
|
||||
VNotebookSelector::VNotebookSelector(VNote *vnote, QWidget *p_parent)
|
||||
: QComboBox(p_parent), m_vnote(vnote), m_notebooks(m_vnote->getNotebooks()),
|
||||
m_editArea(NULL), m_lastValidIndex(-1)
|
||||
: QComboBox(p_parent), VNavigationMode(),
|
||||
m_vnote(vnote), m_notebooks(m_vnote->getNotebooks()),
|
||||
m_editArea(NULL), m_lastValidIndex(-1), m_naviLabel(NULL)
|
||||
{
|
||||
m_listWidget = new QListWidget(this);
|
||||
m_listWidget->setItemDelegate(new VNoFocusItemDelegate(this));
|
||||
@ -386,3 +389,41 @@ void VNotebookSelector::resizeListWidgetToContent()
|
||||
}
|
||||
m_listWidget->setMinimumSize(minWidth, minHeight);
|
||||
}
|
||||
|
||||
void VNotebookSelector::registerNavigation(QChar p_majorKey)
|
||||
{
|
||||
Q_ASSERT(!m_naviLabel);
|
||||
qDebug() << "VNotebookSelector register for navigation key" << p_majorKey;
|
||||
m_majorKey = p_majorKey;
|
||||
|
||||
m_naviLabel = new QLabel(m_majorKey, this);
|
||||
m_naviLabel->setStyleSheet(g_vnote->getNavigationLabelStyle());
|
||||
m_naviLabel->hide();
|
||||
}
|
||||
|
||||
void VNotebookSelector::showNavigation()
|
||||
{
|
||||
qDebug() << "VNotebookSelector show navigation";
|
||||
m_naviLabel->show();
|
||||
}
|
||||
|
||||
void VNotebookSelector::hideNavigation()
|
||||
{
|
||||
qDebug() << "VNotebookSelector hide navigation";
|
||||
m_naviLabel->hide();
|
||||
}
|
||||
|
||||
bool VNotebookSelector::handleKeyNavigation(int p_key, bool &p_succeed)
|
||||
{
|
||||
qDebug() << "VNotebookSelector handle key navigation" << p_key;
|
||||
bool ret = false;
|
||||
p_succeed = false;
|
||||
QChar keyChar = VUtils::keyToChar(p_key);
|
||||
if (keyChar == m_majorKey) {
|
||||
// Hit.
|
||||
p_succeed = true;
|
||||
showPopup();
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <QComboBox>
|
||||
#include <QVector>
|
||||
#include <QString>
|
||||
#include "vnavigationmode.h"
|
||||
|
||||
class VNotebook;
|
||||
class VNote;
|
||||
@ -11,8 +12,9 @@ class VEditArea;
|
||||
class QListWidget;
|
||||
class QAction;
|
||||
class QListWidgetItem;
|
||||
class QLabel;
|
||||
|
||||
class VNotebookSelector : public QComboBox
|
||||
class VNotebookSelector : public QComboBox, public VNavigationMode
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@ -23,6 +25,12 @@ public:
|
||||
bool locateNotebook(const VNotebook *p_notebook);
|
||||
void showPopup() Q_DECL_OVERRIDE;
|
||||
|
||||
// Implementations for VNavigationMode.
|
||||
void registerNavigation(QChar p_majorKey);
|
||||
void showNavigation();
|
||||
void hideNavigation();
|
||||
bool handleKeyNavigation(int p_key, bool &p_succeed);
|
||||
|
||||
signals:
|
||||
void curNotebookChanged(VNotebook *p_notebook);
|
||||
// Info of current notebook was changed.
|
||||
@ -76,6 +84,8 @@ private:
|
||||
// We will add several special action item in the combobox. This is the start index
|
||||
// of the real notebook items related to m_notebooks.
|
||||
static const int c_notebookStartIdx;
|
||||
|
||||
QLabel *m_naviLabel;
|
||||
};
|
||||
|
||||
inline void VNotebookSelector::setEditArea(VEditArea *p_editArea)
|
||||
|
Loading…
x
Reference in New Issue
Block a user