aboutsummaryrefslogtreecommitdiff
path: root/src/ui/helper/ShortcutHub.cpp
blob: 823072f271de75c213237713b0242e90af67b5e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include "cru/ui/helper/ShortcutHub.hpp"

#include "cru/common/Logger.hpp"
#include "cru/ui/DebugFlags.hpp"
#include "cru/ui/controls/Control.hpp"

#include <algorithm>
#include <functional>
#include <iterator>
#include <optional>

namespace cru::ui::helper {
int ShortcutHub::RegisterShortcut(Shortcut shortcut) {
  const int id = current_id_++;
  map_[shortcut.key_bind].push_back({id, std::move(shortcut.name),
                                     shortcut.key_bind,
                                     std::move(shortcut.handler)});
  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_;
}

void ShortcutHub::Install(controls::Control* control) {
  if (!event_guard_.IsEmpty()) {
    log::Error(u"Shortcut hub is already installed. Failed to install.");
    return;
  }

  event_guard_ += control->KeyDownEvent()->Bubble()->AddHandler(
      std::bind(&ShortcutHub::OnKeyDown, this, std::placeholders::_1));
}

void ShortcutHub::Uninstall() {
  if (event_guard_.IsEmpty()) {
    log::Warn(u"Shortcut hub is not installed. Failed to uninstall.");
    return;
  }

  event_guard_.Clear();
}

void ShortcutHub::OnKeyDown(event::KeyEventArgs& event) {
  ShortcutKeyBind key_bind(event.GetKeyCode(), event.GetKeyModifier());
  const auto& shortcut_list = this->GetShortcutByKeyBind(key_bind);

  if constexpr (debug_flags::shortcut) {
    if (shortcut_list.empty()) {
      log::Debug(u"No shortcut for key bind {}.", key_bind.ToString());
    }
    log::Debug(u"Begin to handle shortcut for key bind {}.",
               key_bind.ToString());
  }

  for (const auto& shortcut : shortcut_list) {
    auto is_handled = shortcut.handler();
    if (is_handled) {
      if constexpr (debug_flags::shortcut) {
        log::Debug(u"Handle {} handled it.", shortcut.name);
      }

      event.SetHandled();

      break;
    } else {
      if constexpr (debug_flags::shortcut) {
        log::Debug(u"Handle {} disdn't handle it.", shortcut.name);
      }
    }
  }

  if constexpr (debug_flags::shortcut) {
    if (!shortcut_list.empty()) {
      log::Debug(u"End handling shortcut for key bind {}.",
                 key_bind.ToString());
    }
  }
}
}  // namespace cru::ui::helper