#ifndef VCAPTAIN_H #define VCAPTAIN_H #include #include #include #include class QKeyEvent; class VNavigationMode; class QShortcut; // bool func(void *p_target, void *p_data); // Return true if the target needs to restore focus by the Captain. typedef std::function CaptainFunc; // Will be passed to CaptainFunc as the data. struct CaptainData { CaptainData(QWidget *p_focusWidgetBeforeCaptain) : m_focusWidgetBeforeCaptain(p_focusWidgetBeforeCaptain) { } QWidget *m_focusWidgetBeforeCaptain; }; class VCaptain : public QWidget { Q_OBJECT public: explicit VCaptain(QWidget *p_parent); // Register a target for Navigation mode. void registerNavigationTarget(VNavigationMode *p_target); // Register a target for Captain mode. bool registerCaptainTarget(const QString &p_name, const QString &p_key, void *p_target, CaptainFunc p_func); void setCaptainModeEnabled(bool p_enabled); void exitCaptainMode(); signals: // Emit when mode changed. void captainModeChanged(bool p_captainMode); protected: void keyPressEvent(QKeyEvent *p_event) Q_DECL_OVERRIDE; private slots: // Exit Navigation mode if focus lost. void handleFocusChanged(QWidget *p_old, QWidget *p_new); private: // A widget target for Navigation mode. struct NaviModeTarget { NaviModeTarget() : m_target(nullptr), m_available(false) { } NaviModeTarget(VNavigationMode *p_target, bool p_available) : m_target(p_target), m_available(p_available) { } VNavigationMode *m_target; bool m_available; }; // Modes. enum class CaptainMode { Normal = 0, Pending, Navigation }; struct CaptainModeTarget { CaptainModeTarget() : m_target(nullptr), m_function(nullptr) { } CaptainModeTarget(const QString &p_name, const QString &p_key, void *p_target, CaptainFunc p_func) : m_name(p_name), m_key(p_key), m_target(p_target), m_function(p_func) { } QString toString() const { return QString("Captain mode target %1 key[%2]").arg(m_name).arg(m_key); } // Name to display. QString m_name; // Key sequence to trigger this target. // This is the sub-sequence after leader key. QString m_key; // Target. void *m_target; // Function to call when this target is trigger. CaptainFunc m_function; }; // Restore the focus to m_widgetBeforeCaptain. void restoreFocus(); // Return true if finish handling the event; otherwise, let the base widget // to handle it. bool handleKeyPress(int p_key, Qt::KeyboardModifiers p_modifiers); // Handle key press event in Navigation mode. bool handleKeyPressNavigationMode(int p_key, Qt::KeyboardModifiers p_modifiers); // Handle key press event in Captain mode. bool handleKeyPressCaptainMode(int p_key, Qt::KeyboardModifiers p_modifiers); // Get next major key to use for Navigation mode. QChar getNextMajorKey(); // Trigger navigation mode to ask all targets show themselves. void triggerNavigationMode(); // Exit navigation mode to ask all targets hide themselves. void exitNavigationMode(); // Called to trigger the action of a Captain target which has // registered @p_key. void triggerCaptainTarget(const QString &p_key); void setMode(CaptainMode p_mode); bool checkMode(CaptainMode p_mode) const; void trigger(); void triggerCaptainMode(); static bool navigationModeByCaptain(void *p_target, void *p_data); // Used to indicate current mode. CaptainMode m_mode; // The widget which has the focus before entering Captain mode. QWidget *m_widgetBeforeCaptain; // Targets for Navigation mode. QVector m_naviTargets; QChar m_nextMajorKey; // Targets for Captain mode. // Key(lower) -> CaptainModeTarget. QHash m_captainTargets; // Ignore focus change during handling Captain and Navigation target actions. bool m_ignoreFocusChange; QShortcut *m_captainModeShortcut; }; inline void VCaptain::setMode(CaptainMode p_mode) { m_mode = p_mode; } inline bool VCaptain::checkMode(CaptainMode p_mode) const { return m_mode == p_mode; } #endif // VCAPTAIN_H