OXYGENHUB
◆ main openmsx / src / imgui / ImGuiCheatFinder.cc
4.9 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "ImGuiCheatFinder.hh"
2
3
#include "ImGuiCpp.hh"
4
#include "ImGuiManager.hh"
5
#include "ImGuiUtils.hh"
6
7
#include "narrow.hh"
8
#include "stl.hh"
9
10
#include <ranges>
11
12
namespace openmsx {
13
14
using namespace std::literals;
15
16
void ImGuiCheatFinder::paint(MSXMotherBoard* /*motherBoard*/)
17
{
18
	if (!show) return;
19
20
	bool start = false;
21
	std::string searchExpr;
22
23
	ImGui::SetNextWindowSize(gl::vec2{35, 0} * ImGui::GetFontSize(), ImGuiCond_FirstUseEver);
24
	im::Window("Cheat Finder", &show, [&]{
25
		const auto& style = ImGui::GetStyle();
26
		auto tSize = ImGui::CalcTextSize("=="sv).x + 2.0f * style.FramePadding.x;
27
		auto bSpacing = 2.0f;
28
		auto height = 12.5f * ImGui::GetTextLineHeightWithSpacing();
29
		auto sWidth = 2.0f * (style.WindowBorderSize + style.WindowPadding.x)
30
		              + style.IndentSpacing + 6 * tSize + 5 * bSpacing;
31
		im::Child("search", {sWidth, height}, ImGuiChildFlags_Borders, [&]{
32
			ImGui::TextUnformatted("Search"sv);
33
			HelpMarker("OpenMSX cheat finder. See here for a quick tutorial:\n"
34
			           "  openMSX tutorial: Working with the Cheat Finder\n"
35
			           "  http://www.youtube.com/watch?v=F11ltfkCtKo\n"
36
			           "The UI has changed, but the ideas remain the same.");
37
			im::Disabled(searchResults.empty(), [&]{
38
				ImGui::TextUnformatted("Compare"sv);
39
				im::Indent([&]{
40
					auto bSize = ImVec2{tSize, 0.0f};
41
					if (ImGui::Button("<",  bSize)) searchExpr = "$new < $old";
42
					simpleToolTip("Search for memory locations with strictly decreased value");
43
					ImGui::SameLine(0.0f, bSpacing);
44
					if (ImGui::Button("<=", bSize)) searchExpr = "$new <= $old";
45
					simpleToolTip("Search for memory locations with decreased value");
46
					ImGui::SameLine(0.0f, bSpacing);
47
					if (ImGui::Button("!=", bSize)) searchExpr = "$new != $old";
48
					simpleToolTip("Search for memory locations with changed value");
49
					ImGui::SameLine(0.0f, bSpacing);
50
					if (ImGui::Button("==", bSize)) searchExpr = "$new == $old";
51
					simpleToolTip("Search for memory locations with unchanged value");
52
					ImGui::SameLine(0.0f, bSpacing);
53
					if (ImGui::Button(">=", bSize)) searchExpr = "$new >= $old";
54
					simpleToolTip("Search for memory locations with increased value");
55
					ImGui::SameLine(0.0f, bSpacing);
56
					if (ImGui::Button(">",  bSize)) searchExpr = "$new > $old";
57
					simpleToolTip("Search for memory locations with strictly increased value");
58
				});
59
				ImGui::TextUnformatted("Specific value"sv);
60
				im::Indent([&]{
61
					ImGui::SetNextItemWidth(3 * ImGui::GetFontSize());
62
					ImGui::InputScalar("##value", ImGuiDataType_U8, &searchValue);
63
					ImGui::SameLine();
64
					if (ImGui::Button("Go")) {
65
						searchExpr = strCat("$new == ", searchValue);
66
					}
67
					simpleToolTip("Search for memory locations with a specific value");
68
				});
69
			});
70
			start |= ImGui::Button("Restart search");
71
		});
72
73
		ImGui::SameLine();
74
		im::Child("result", {0.0f, height}, ImGuiChildFlags_Borders, [&]{
75
			auto num = searchResults.size();
76
			if (num == 0) {
77
				ImGui::TextUnformatted("Results: no remaining locations"sv);
78
				start |= ImGui::Button("Start a new search");
79
			} else {
80
				if (num == 1) {
81
					ImGui::TextUnformatted("Results: 1 remaining location"sv);
82
				} else {
83
					ImGui::Text("Results: %d remaining locations", narrow<int>(num));
84
				}
85
				int flags = ImGuiTableFlags_RowBg |
86
				            ImGuiTableFlags_BordersV |
87
				            ImGuiTableFlags_BordersOuter |
88
				            ImGuiTableFlags_ScrollY;
89
				im::Table("##table", 3, flags, [&]{
90
					ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
91
					ImGui::TableSetupColumn("Address");
92
					ImGui::TableSetupColumn("Previous");
93
					ImGui::TableSetupColumn("New value");
94
					ImGui::TableHeadersRow();
95
96
					im::ListClipper(searchResults.size(), [&](int i) {
97
						const auto& row = searchResults[i];
98
						if (ImGui::TableNextColumn()) { // addr
99
							ImGui::Text("0x%04x", row.address);
100
						}
101
						if (ImGui::TableNextColumn()) { // old
102
							ImGui::Text("%d", row.oldValue);
103
						}
104
						if (ImGui::TableNextColumn()) { // new
105
							ImGui::Text("%d", row.newValue);
106
						}
107
					});
108
				});
109
			}
110
		});
111
	});
112
113
	if (start) {
114
		manager.execute(TclObject("cheat_finder::start"));
115
		searchExpr = "1"; // could be optimized, but good enough
116
	}
117
	if (!searchExpr.empty()) {
118
		auto result = manager.execute(makeTclList("cheat_finder::search", searchExpr)).value_or(TclObject{});
119
		searchResults = to_vector(std::views::transform(xrange(result.size()), [&](size_t i) {
120
			auto line = result.getListIndexUnchecked(i);
121
			auto addr     = line.getListIndexUnchecked(0).getOptionalInt().value_or(0);
122
			auto oldValue = line.getListIndexUnchecked(1).getOptionalInt().value_or(0);
123
			auto newValue = line.getListIndexUnchecked(2).getOptionalInt().value_or(0);
124
			return SearchResult{.address = narrow_cast<uint16_t>(addr),
125
			                    .oldValue = narrow_cast<uint8_t>(oldValue),
126
			                    .newValue = narrow_cast<uint8_t>(newValue)};
127
		}));
128
	}
129
}
130
131
} // namespace openmsx