Aegisub/libaegisub/common/hotkey.cpp

189 lines
5.7 KiB
C++
Raw Normal View History

// Copyright (c) 2010, Amar Takhar <verm@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/// @file hotkey.cpp
/// @brief Hotkey handler
/// @ingroup hotkey menu event window
#include "libaegisub/hotkey.h"
#include "libaegisub/cajun/writer.h"
#include "libaegisub/io.h"
#include "libaegisub/json.h"
#include "libaegisub/log.h"
#include <algorithm>
2012-11-13 15:07:39 +01:00
#include <boost/algorithm/string/join.hpp>
#include <boost/range/adaptor/map.hpp>
#include <tuple>
2012-11-13 15:07:39 +01:00
namespace agi {
namespace hotkey {
std::string Combo::Str() const {
2012-11-13 15:07:39 +01:00
return boost::algorithm::join(key_map, "-");
}
std::string Combo::StrMenu() const {
return Str();
}
void Hotkey::ComboInsert(Combo const& combo) {
2012-11-13 15:07:39 +01:00
str_map.insert(make_pair(combo.Str(), combo));
cmd_map.insert(make_pair(combo.CmdName(), combo));
}
Hotkey::Hotkey(fs::path const& file, std::pair<const char *, size_t> default_config)
: config_file(file)
{
LOG_D("hotkey/init") << "Generating hotkeys.";
auto root = json_util::file(config_file, default_config);
for (auto const& hotkey_context : static_cast<json::Object const&>(root))
2012-11-13 15:07:39 +01:00
BuildHotkey(hotkey_context.first, hotkey_context.second);
}
2012-11-13 15:07:39 +01:00
void Hotkey::BuildHotkey(std::string const& context, json::Object const& hotkeys) {
for (auto const& command : hotkeys) {
const json::Array& command_hotkeys = command.second;
for (json::Object const& hotkey : command_hotkeys) {
std::vector<std::string> keys;
auto it = hotkey.find("modifiers");
if (it == end(hotkey)) {
LOG_E("agi/hotkey/load") << "Hotkey for command '" << command.first << "' is missing modifiers";
continue;
}
json::Array const& arr_mod = it->second;
keys.reserve(arr_mod.size() + 1);
copy(arr_mod.begin(), arr_mod.end(), back_inserter(keys));
it = hotkey.find("key");
if (it == end(hotkey)) {
LOG_E("agi/hotkey/load") << "Hotkey for command '" << command.first << "' is missing the key";
continue;
}
keys.push_back(it->second);
2012-11-13 15:07:39 +01:00
ComboInsert(Combo(context, command.first, keys));
}
}
}
std::string Hotkey::Scan(const std::string &context, const std::string &str, bool always) const {
std::string local, dfault;
HotkeyMap::const_iterator index, end;
2012-09-25 01:35:27 +02:00
for (std::tie(index, end) = str_map.equal_range(str); index != end; ++index) {
std::string const& ctext = index->second.Context();
if (always && ctext == "Always") {
LOG_D("agi/hotkey/found") << "Found: " << str << " Context (req/found): " << context << "/Always Command: " << index->second.CmdName();
return index->second.CmdName();
}
if (ctext == "Default")
dfault = index->second.CmdName();
else if (ctext == context)
local = index->second.CmdName();
}
if (!local.empty()) {
LOG_D("agi/hotkey/found") << "Found: " << str << " Context: " << context << " Command: " << local;
return local;
}
if (!dfault.empty()) {
LOG_D("agi/hotkey/found") << "Found: " << str << " Context (req/found): " << context << "/Default Command: " << dfault;
return dfault;
}
return "";
}
bool Hotkey::HasHotkey(const std::string &context, const std::string &str) const {
HotkeyMap::const_iterator index, end;
for (std::tie(index, end) = str_map.equal_range(str); index != end; ++index) {
std::string const& ctext = index->second.Context();
if (ctext == context)
return true;
}
return false;
}
std::vector<std::string> Hotkey::GetHotkeys(const std::string &context, const std::string &command) const {
std::vector<std::string> ret;
HotkeyMap::const_iterator it, end;
2012-09-25 01:35:27 +02:00
for (std::tie(it, end) = cmd_map.equal_range(command); it != end; ++it) {
std::string ctext = it->second.Context();
if (ctext == "Always" || ctext == "Default" || ctext == context)
ret.emplace_back(it->second.StrMenu());
}
sort(ret.begin(), ret.end());
ret.erase(unique(ret.begin(), ret.end()), ret.end());
return ret;
}
std::string Hotkey::GetHotkey(const std::string &context, const std::string &command) const {
std::string ret;
HotkeyMap::const_iterator it, end;
2012-09-25 01:35:27 +02:00
for (std::tie(it, end) = cmd_map.equal_range(command); it != end; ++it) {
std::string ctext = it->second.Context();
if (ctext == context) return it->second.StrMenu();
if (ctext == "Default")
ret = it->second.StrMenu();
else if (ret.empty() && ctext == "Always")
ret = it->second.StrMenu();
}
return ret;
}
void Hotkey::Flush() {
json::Object root;
2012-11-13 15:07:39 +01:00
for (auto const& combo : str_map | boost::adaptors::map_values) {
json::Object hotkey;
2012-11-13 15:07:39 +01:00
if (combo.Get().size()) {
hotkey["key"] = combo.Get().back();
json::Array& modifiers = hotkey["modifiers"];
2012-11-13 15:07:39 +01:00
modifiers.insert(modifiers.end(), combo.Get().begin(), combo.Get().end() - 1);
}
json::Object& context = root[combo.Context()];
json::Array& combo_array = context[combo.CmdName()];
2012-11-13 15:07:39 +01:00
combo_array.push_back(std::move(hotkey));
}
io::Save file(config_file);
JsonWriter::Write(root, file.Get());
}
void Hotkey::SetHotkeyMap(HotkeyMap const& new_map) {
cmd_map = new_map;
str_map.clear();
2012-11-13 15:07:39 +01:00
for (auto const& combo : cmd_map | boost::adaptors::map_values)
str_map.insert(make_pair(combo.Str(), combo));
Flush();
HotkeysChanged();
}
} // namespace toolbar
} // namespace agi