aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/common/Base.hpp13
-rw-r--r--include/cru/common/Event.hpp4
-rw-r--r--include/cru/ui/ShortcutHub.hpp36
-rw-r--r--src/ui/ShortcutHub.cpp53
4 files changed, 98 insertions, 8 deletions
diff --git a/include/cru/common/Base.hpp b/include/cru/common/Base.hpp
index a5a9421d..560f83bb 100644
--- a/include/cru/common/Base.hpp
+++ b/include/cru/common/Base.hpp
@@ -1,8 +1,8 @@
#pragma once
#include "PreConfig.hpp"
+#include <exception>
#include <gsl/gsl>
-
#include <stdexcept>
#define CRU_UNUSED(entity) static_cast<void>(entity);
@@ -42,12 +42,17 @@ struct Interface {
virtual ~Interface() = default;
};
-[[noreturn]] inline void UnreachableCode() {
- throw std::runtime_error("Unreachable code.");
-}
+[[noreturn]] inline void UnreachableCode() { std::terminate(); }
using Index = gsl::index;
+// https://www.boost.org/doc/libs/1_54_0/doc/html/hash/reference.html#boost.hash_combine
+template <class T>
+inline void hash_combine(std::size_t& s, const T& v) {
+ std::hash<T> h;
+ s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
+}
+
#define CRU_DEFINE_CLASS_LOG_TAG(tag) \
private: \
constexpr static std::u16string_view log_tag = tag;
diff --git a/include/cru/common/Event.hpp b/include/cru/common/Event.hpp
index 6417bc78..93ab9b7a 100644
--- a/include/cru/common/Event.hpp
+++ b/include/cru/common/Event.hpp
@@ -232,6 +232,10 @@ class EventRevokerListGuard {
return *this;
}
+ void Clear() { event_revoker_guard_list_.clear(); }
+
+ bool IsEmpty() const { return event_revoker_guard_list_.empty(); }
+
private:
std::vector<EventRevokerGuard> event_revoker_guard_list_;
};
diff --git a/include/cru/ui/ShortcutHub.hpp b/include/cru/ui/ShortcutHub.hpp
index 9995a4e1..7a75e4a1 100644
--- a/include/cru/ui/ShortcutHub.hpp
+++ b/include/cru/ui/ShortcutHub.hpp
@@ -1,12 +1,17 @@
#pragma once
#include "Base.hpp"
+#include "cru/common/Base.hpp"
+#include "cru/common/Event.hpp"
#include "cru/platform/native/Keyboard.hpp"
+#include <cstddef>
#include <functional>
+#include <memory>
#include <optional>
#include <string>
#include <string_view>
+#include <unordered_map>
#include <vector>
namespace cru::ui {
@@ -42,8 +47,23 @@ class ShortcutKeyBind {
platform::native::KeyCode key_;
platform::native::KeyModifier modifier_;
};
+} // namespace cru::ui
+
+namespace std {
+template <>
+struct hash<cru::ui::ShortcutKeyBind> {
+ std::size_t operator()(const cru::ui::ShortcutKeyBind& value) const {
+ std::size_t result = 0;
+ cru::hash_combine(result, value.GetKey());
+ cru::hash_combine(result, value.GetModifier());
+ return result;
+ }
+};
+} // namespace std
+namespace cru::ui {
struct ShortcutInfo {
+ int id;
std::u16string name;
ShortcutKeyBind key_bind;
std::function<bool()> handler;
@@ -51,15 +71,16 @@ struct ShortcutInfo {
class ShortcutHub : public Object {
public:
- ShortcutHub();
+ ShortcutHub() = default;
CRU_DELETE_COPY(ShortcutHub)
CRU_DELETE_MOVE(ShortcutHub)
- ~ShortcutHub() override;
+ ~ShortcutHub() override = default;
// Handler return true if it consumes the shortcut. Or return false if it does
- // not handle the shortcut. Name is just for debug.
+ // not handle the shortcut. Name is just for debug. Return an id used for
+ // unregistering.
int RegisterShortcut(std::u16string name, ShortcutKeyBind bind,
std::function<bool()> handler);
@@ -67,12 +88,19 @@ class ShortcutHub : public Object {
std::vector<ShortcutInfo> GetAllShortcuts() const;
std::optional<ShortcutInfo> GetShortcut(int id) const;
- std::vector<ShortcutInfo> GetShortcutByKeyBind(
+ const std::vector<ShortcutInfo>& GetShortcutByKeyBind(
const ShortcutKeyBind& key_bind) const;
void Install(Control* control);
void Uninstall();
private:
+ std::unordered_map<ShortcutKeyBind, std::vector<ShortcutInfo>> map_;
+
+ const std::vector<ShortcutInfo> empty_list_;
+
+ int current_id_ = 1;
+
+ EventRevokerListGuard event_guard_;
};
} // namespace cru::ui
diff --git a/src/ui/ShortcutHub.cpp b/src/ui/ShortcutHub.cpp
index 2246b6eb..e5847f8c 100644
--- a/src/ui/ShortcutHub.cpp
+++ b/src/ui/ShortcutHub.cpp
@@ -1,5 +1,58 @@
#include "cru/ui/ShortcutHub.hpp"
+#include <algorithm>
+#include <iterator>
+#include <optional>
namespace cru::ui {
+int ShortcutHub::RegisterShortcut(std::u16string name, ShortcutKeyBind bind,
+ std::function<bool()> handler) {
+ const int id = current_id_++;
+ ShortcutInfo info{id, std::move(name), bind, std::move(handler)};
+ map_[bind].push_back(std::move(info));
+ return id;
+}
+
+void ShortcutHub::UnregisterShortcut(int id) {
+ if (id <= 0) return;
+ for (auto& pair : map_) {
+ auto& list = pair.second;
+ auto result =
+ std::find_if(list.cbegin(), list.cend(),
+ [id](const ShortcutInfo& info) { return info.id == id; });
+ if (result != list.cend()) {
+ list.erase(result);
+ }
+ }
+}
+
+std::vector<ShortcutInfo> ShortcutHub::GetAllShortcuts() const {
+ std::vector<ShortcutInfo> result;
+
+ for (const auto& pair : map_) {
+ std::copy(pair.second.cbegin(), pair.second.cend(),
+ std::back_inserter(result));
+ }
+
+ return result;
+}
+
+std::optional<ShortcutInfo> ShortcutHub::GetShortcut(int id) const {
+ for (auto& pair : map_) {
+ auto& list = pair.second;
+ auto result =
+ std::find_if(list.cbegin(), list.cend(),
+ [id](const ShortcutInfo& info) { return info.id == id; });
+ if (result != list.cend()) {
+ return *result;
+ }
+ }
+ return std::nullopt;
+}
+const std::vector<ShortcutInfo>& ShortcutHub::GetShortcutByKeyBind(
+ const ShortcutKeyBind& key_bind) const {
+ auto result = map_.find(key_bind);
+ if (result != map_.cend()) return result->second;
+ return empty_list_;
}
+} // namespace cru::ui