OXYGENHUB
◆ main openmsx / src / imgui / Shortcuts.cc
7.4 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "Shortcuts.hh"
2
3
#include "narrow.hh"
4
#include "one_of.hh"
5
6
#include "imgui_internal.h"
7
8
#include <algorithm>
9
#include <array>
10
#include <utility>
11
12
namespace openmsx {
13
14
// When adding a new shortcut:
15
// * Add a new value in 'enum Shortcuts::ID'
16
// * Add a single line in this table
17
struct AllShortcutInfo {
18
	Shortcuts::ID id;
19
	ImGuiKeyChord keyChord;
20
	Shortcuts::Type type;
21
	bool repeat;
22
	zstring_view name;        // used in settings.xml
23
	zstring_view description; // shown in GUI
24
};
25
using enum Shortcuts::ID;
26
using enum Shortcuts::Type;
27
static constexpr auto allShortcutInfo = std::to_array<AllShortcutInfo>({
28
	{HEX_GOTO_ADDR,           ImGuiKey_G | ImGuiMod_Ctrl,   ALWAYS_LOCAL, false, "hex_editor_goto_address", "Go to address in hex viewer"},
29
30
	{DEBUGGER_STEP_IN,        ImGuiKey_F7,                  LOCAL,        true,  "step-in",                 "Debugger: step-in"},
31
	{DEBUGGER_STEP_OVER,      ImGuiKey_F8,                  LOCAL,        true,  "step-over",               "Debugger: step-over"},
32
	{DEBUGGER_STEP_OUT,       ImGuiKey_F7 | ImGuiMod_Shift, LOCAL,        true,  "step-out",                "Debugger: step-out"},
33
	{DEBUGGER_STEP_BACK,      ImGuiKey_F8 | ImGuiMod_Shift, LOCAL,        true,  "step-back",               "Debugger: step-back"},
34
	{DEBUGGER_BREAK_CONTINUE, ImGuiKey_F5,                  LOCAL,        false, "break-continue",          "Debugger: toggle break / continue"},
35
36
	{DISASM_GOTO_ADDR,        ImGuiMod_Ctrl | ImGuiKey_G,   ALWAYS_LOCAL, false, "disasm_goto_address",     "Scroll to address in disassembler"},
37
	{DISASM_RUN_TO_ADDR,      ImGuiMod_Ctrl | ImGuiKey_R,   ALWAYS_LOCAL, false, "disasm_run_to_address",   "Debugger: run to a specific address"},
38
	{DISASM_TOGGLE_BREAKPOINT,ImGuiMod_Ctrl | ImGuiKey_B,   ALWAYS_LOCAL, false, "disasm_toggle_breakpoint","Debugger: toggle breakpoint at current address"},
39
40
	{TRACE_ZOOM_TO_FIT,       ImGuiMod_Ctrl | ImGuiKey_0,    LOCAL,       false, "trace_zoom_to_fit",       "Trace Viewer: zoom to fit all events"},
41
	{TRACE_ZOOM_IN,           ImGuiMod_Ctrl | ImGuiKey_Equal,LOCAL,       false, "trace_zoom_in",           "Trace Viewer: zoom in"},
42
	{TRACE_ZOOM_OUT,          ImGuiMod_Ctrl | ImGuiKey_Minus,LOCAL,       false, "trace_zoom_out",          "Trace Viewer: zoom out"},
43
	{TRACE_PREV_NEG_EDGE,     ImGuiMod_Ctrl | ImGuiKey_A,    LOCAL,       false, "trace_prev_neg_edge",     "Trace Viewer: goto previous negative edge"},
44
	{TRACE_PREV_POS_EDGE,     ImGuiMod_Ctrl | ImGuiKey_S,    LOCAL,       false, "trace_prev_pos_edge",     "Trace Viewer: goto previous positive edge"},
45
	{TRACE_PREV_EDGE,         ImGuiMod_Ctrl | ImGuiKey_D,    LOCAL,       false, "trace_prev_edge",         "Trace Viewer: goto previous edge"},
46
	{TRACE_NEXT_EDGE,         ImGuiMod_Ctrl | ImGuiKey_F,    LOCAL,       false, "trace_next_edge",         "Trace Viewer: goto next edge"},
47
	{TRACE_NEXT_POS_EDGE,     ImGuiMod_Ctrl | ImGuiKey_G,    LOCAL,       false, "trace_next_pos_edge",     "Trace Viewer: goto next positive edge"},
48
	{TRACE_NEXT_NEG_EDGE,     ImGuiMod_Ctrl | ImGuiKey_H,    LOCAL,       false, "trace_next_neg_edge",     "Trace Viewer: goto next negative edge"},
49
	{TRACE_ALT_PREV_NEG_EDGE, ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_A, LOCAL, false, "trace_alt_prev_neg_edge", "Trace Viewer: secondary goto previous negative edge"},
50
	{TRACE_ALT_PREV_POS_EDGE, ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_S, LOCAL, false, "trace_alt_prev_pos_edge", "Trace Viewer: secondary goto previous positive edge"},
51
	{TRACE_ALT_PREV_EDGE,     ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_D, LOCAL, false, "trace_alt_prev_edge",     "Trace Viewer: secondary goto previous edge"},
52
	{TRACE_ALT_NEXT_EDGE,     ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_F, LOCAL, false, "trace_alt_next_edge",     "Trace Viewer: secondary goto next edge"},
53
	{TRACE_ALT_NEXT_POS_EDGE, ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_G, LOCAL, false, "trace_alt_next_pos_edge", "Trace Viewer: secondary goto next positive edge"},
54
	{TRACE_ALT_NEXT_NEG_EDGE, ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_H, LOCAL, false, "trace_alt_next_neg_edge", "Trace Viewer: secondary goto next negative edge"},
55
	{TRACE_SHOW_MENU_BAR,     ImGuiMod_Ctrl | ImGuiKey_M,    LOCAL,       false, "trace_show_menu_bar",     "Trace Viewer: show/hide menu bar"},
56
});
57
static_assert(narrow<int>(allShortcutInfo.size()) == std::to_underlying(Shortcuts::ID::NUM));
58
59
static constexpr auto defaultShortcuts = []{
60
	array_with_enum_index<Shortcuts::ID, Shortcuts::Shortcut> result = {};
61
	for (auto i : xrange(std::to_underlying(Shortcuts::ID::NUM))) {
62
		const auto& all = allShortcutInfo[i];
63
		auto id = static_cast<Shortcuts::ID>(i);
64
		assert(all.id == id); // verify that rows are in-order
65
		result[id].keyChord = all.keyChord;
66
		result[id].type = all.type;
67
	}
68
	return result;
69
}();
70
71
static constexpr auto shortcutRepeats = []{
72
	array_with_enum_index<Shortcuts::ID, bool> result = {};
73
	for (auto i : xrange(std::to_underlying(Shortcuts::ID::NUM))) {
74
		auto id = static_cast<Shortcuts::ID>(i);
75
		result[id] = allShortcutInfo[i].repeat;
76
	}
77
	return result;
78
}();
79
80
static constexpr auto shortcutNames = []{
81
	array_with_enum_index<Shortcuts::ID, zstring_view> result = {};
82
	for (auto i : xrange(std::to_underlying(Shortcuts::ID::NUM))) {
83
		auto id = static_cast<Shortcuts::ID>(i);
84
		result[id] = allShortcutInfo[i].name;
85
	}
86
	return result;
87
}();
88
89
static constexpr auto shortcutDescriptions = []{
90
	array_with_enum_index<Shortcuts::ID, zstring_view> result = {};
91
	for (auto i : xrange(std::to_underlying(Shortcuts::ID::NUM))) {
92
		auto id = static_cast<Shortcuts::ID>(i);
93
		result[id] = allShortcutInfo[i].description;
94
	}
95
	return result;
96
}();
97
98
Shortcuts::Shortcuts()
99
{
100
	setDefaultShortcuts();
101
}
102
103
void Shortcuts::setDefaultShortcuts()
104
{
105
	shortcuts = defaultShortcuts; // this can overwrite the 'type' field
106
}
107
108
const Shortcuts::Shortcut& Shortcuts::getDefaultShortcut(Shortcuts::ID id)
109
{
110
	return defaultShortcuts[id];
111
}
112
113
const Shortcuts::Shortcut& Shortcuts::getShortcut(Shortcuts::ID id) const
114
{
115
	return shortcuts[id];
116
}
117
118
void Shortcuts::setShortcut(ID id, const Shortcut& shortcut)
119
{
120
	auto oldType = shortcuts[id].type;
121
	shortcuts[id] = shortcut;
122
	if (oldType == one_of(Type::ALWAYS_LOCAL, Type::ALWAYS_GLOBAL)) {
123
		// cannot change this
124
		shortcuts[id].type = oldType;
125
	}
126
}
127
128
bool Shortcuts::getShortcutRepeat(ID id)
129
{
130
	return shortcutRepeats[id];
131
}
132
133
zstring_view Shortcuts::getShortcutName(Shortcuts::ID id)
134
{
135
	return shortcutNames[id];
136
}
137
138
std::optional<Shortcuts::ID> Shortcuts::parseShortcutName(std::string_view name)
139
{
140
	auto it = std::ranges::find(shortcutNames, name);
141
	if (it == shortcutNames.end()) return {};
142
	return static_cast<Shortcuts::ID>(std::distance(shortcutNames.begin(), it));
143
}
144
145
std::optional<Shortcuts::Type> Shortcuts::parseType(std::string_view name)
146
{
147
	if (name == "global") return GLOBAL;
148
	if (name == "local") return LOCAL;
149
	return {};
150
}
151
152
zstring_view Shortcuts::getShortcutDescription(ID id)
153
{
154
	return shortcutDescriptions[id];
155
}
156
157
bool Shortcuts::checkShortcut(const ShortcutWithRepeat& shortcut) const
158
{
159
	assert(shortcut.keyChord != ImGuiKey_None);
160
	auto flags = (shortcut.type == one_of(GLOBAL, ALWAYS_GLOBAL) ? (ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteUnlessBgFocused) : 0)
161
	           | (shortcut.repeat ? ImGuiInputFlags_Repeat : 0);
162
	return ImGui::Shortcut(shortcut.keyChord, flags, 0);
163
}
164
165
bool Shortcuts::checkShortcut(ID id) const
166
{
167
	const auto& shortcut = shortcuts[id];
168
	if (shortcut.keyChord == ImGuiKey_None) return false;
169
	return checkShortcut({shortcut.keyChord, shortcut.type, getShortcutRepeat(id)});
170
}
171
172
} // namespace openmsx