OXYGENHUB
◆ main openmsx / src / imgui / ImGuiManager.hh
9.9 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef IMGUI_MANAGER_HH
2
#define IMGUI_MANAGER_HH
3
4
#include "ImGuiPartInterface.hh"
5
#include "ImGuiUtils.hh"
6
#include "Shortcuts.hh"
7
#include "freetype_utils.hh"
8
9
#include "EmuTime.hh"
10
#include "EventListener.hh"
11
#include "FilenameSetting.hh"
12
#include "IntegerSetting.hh"
13
#include "Reactor.hh"
14
#include "RomTypes.hh"
15
#include "TclObject.hh"
16
17
#include "Observer.hh"
18
#include "StringReplacer.hh"
19
#include "strCat.hh"
20
21
#include <algorithm>
22
#include <functional>
23
#include <optional>
24
#include <string_view>
25
#include <vector>
26
27
struct ImFont;
28
struct ImGuiTextBuffer;
29
30
namespace openmsx {
31
32
class CliComm;
33
class ImGuiBreakPoints;
34
class ImGuiCheatFinder;
35
class ImGuiConnector;
36
class ImGuiConsole;
37
class ImGuiDebugger;
38
class ImGuiDiskManipulator;
39
class ImGuiHelp;
40
class ImGuiIoPorts;
41
class ImGuiKeyboard;
42
class ImGuiMachine;
43
class ImGuiMedia;
44
class ImGuiMessages;
45
class ImGuiMsxMusicViewer;
46
class ImGuiOpenFile;
47
class ImGuiOsdIcons;
48
class ImGuiPalette;
49
class ImGuiPlotterViewer;
50
class ImGuiRasterViewer;
51
class ImGuiReverseBar;
52
class ImGuiSCCViewer;
53
class ImGuiSettings;
54
class ImGuiSlotMap;
55
class ImGuiSoundChip;
56
class ImGuiSymbols;
57
class ImGuiTools;
58
class ImGuiTraceViewer;
59
class ImGuiTrainer;
60
class ImGuiVdpRegs;
61
class ImGuiWatchExpr;
62
class ImGuiWaveViewer;
63
class RomInfo;
64
class SettingsConfig;
65
66
class ImGuiManager final : public ImGuiPartInterface, private EventListener, private Observer<Setting>
67
{
68
public:
69
	explicit ImGuiManager(Reactor& reactor_);
70
	ImGuiManager(const ImGuiManager&) = delete;
71
	ImGuiManager(ImGuiManager&&) = delete;
72
	ImGuiManager& operator=(const ImGuiManager&) = delete;
73
	ImGuiManager& operator=(ImGuiManager&&) = delete;
74
	~ImGuiManager();
75
76
	void   registerPart(ImGuiPartInterface* part);
77
	void unregisterPart(ImGuiPartInterface* part);
78
79
	[[nodiscard]] Reactor& getReactor() { return reactor; }
80
	[[nodiscard]] Shortcuts& getShortcuts() { return reactor.getShortcuts(); }
81
	[[nodiscard]] Interpreter& getInterpreter();
82
	[[nodiscard]] CliComm& getCliComm();
83
	std::optional<TclObject> execute(TclObject command);
84
	void executeDelayed(std::function<void()> action);
85
	void executeDelayed(TclObject command,
86
	                    const std::function<void(const TclObject&)>& ok,
87
	                    const std::function<void(const std::string&)>& error);
88
	void executeDelayed(TclObject command,
89
	                    const std::function<void(const TclObject&)>& ok = {});
90
91
	void printError(std::string_view message);
92
	template<typename... Ts> void printError(Ts&&... ts) {
93
		printError(static_cast<std::string_view>(tmpStrCat(std::forward<Ts>(ts)...)));
94
	}
95
96
	void preNewFrame();
97
	void paintImGui(bool msxDisplayAreaFocused);
98
99
	void storeWindowPosition(gl::ivec2 pos) { windowPos = pos; }
100
	[[nodiscard]] gl::ivec2 retrieveWindowPosition() const { return windowPos; }
101
102
	void configStatusBarVisibilityItems();
103
104
	std::string getFontDisplayName(const std::span<const uint8_t>& fontData, long faceIndex,
105
	                               std::string_view fontFile)
106
	{
107
		return openmsx::getFontDisplayName(freeTypeLibrary, fontData, faceIndex, fontFile);
108
	}
109
110
private:
111
	void initializeImGui();
112
	[[nodiscard]] std::tuple<ImFont*, std::string> addFont(
113
		zstring_view filename, int fontSize, int faceIndex);
114
	void loadFont();
115
	void reloadFont();
116
	void drawStatusBar(MSXMotherBoard* motherBoard);
117
118
	// ImGuiPartInterface
119
	[[nodiscard]] zstring_view iniName() const override { return "manager"; }
120
	void save(ImGuiTextBuffer& buf) override;
121
	void loadLine(std::string_view name, zstring_view value) override;
122
	void loadEnd() override;
123
124
	// EventListener
125
	bool signalEvent(const Event& event) override;
126
127
	// Observer<Setting>
128
	void update(const Setting& setting) noexcept override;
129
130
	// ini handler callbacks
131
	void iniReadInit();
132
	void* iniReadOpen(std::string_view name);
133
	void loadLine(void* entry, const char* line) const;
134
	void iniApplyAll();
135
	void iniWriteAll(ImGuiTextBuffer& buf);
136
137
	void updateParts();
138
139
private:
140
	Reactor& reactor;
141
	std::vector<ImGuiPartInterface*> parts;
142
	std::vector<ImGuiPartInterface*> toBeAddedParts;
143
	bool removeParts = false;
144
145
public:
146
	FreeTypeLibrary freeTypeLibrary;
147
	FilenameSetting fontPropFilename;
148
	FilenameSetting fontMonoFilename;
149
	IntegerSetting fontPropIndex;
150
	IntegerSetting fontMonoIndex;
151
	IntegerSetting fontPropSize;
152
	IntegerSetting fontMonoSize;
153
	ImFont* fontProp = nullptr;
154
	ImFont* fontMono = nullptr;
155
	std::string fontPropName; // calculated via getFontDisplayName()
156
	std::string fontMonoName;
157
158
	std::unique_ptr<ImGuiMachine> machine;
159
	std::unique_ptr<ImGuiDebugger> debugger;
160
	std::unique_ptr<ImGuiBreakPoints> breakPoints;
161
	std::unique_ptr<ImGuiSymbols> symbols;
162
	std::unique_ptr<ImGuiWatchExpr> watchExpr;
163
	std::unique_ptr<ImGuiTraceViewer> traceViewer;
164
	std::unique_ptr<ImGuiIoPorts> ioPorts;
165
	std::unique_ptr<ImGuiVdpRegs> vdpRegs;
166
	std::unique_ptr<ImGuiPalette> palette;
167
	std::unique_ptr<ImGuiPlotterViewer> plotterViewer;
168
	std::unique_ptr<ImGuiRasterViewer> rasterViewer;
169
	std::unique_ptr<ImGuiReverseBar> reverseBar;
170
	std::unique_ptr<ImGuiHelp> help;
171
	std::unique_ptr<ImGuiOsdIcons> osdIcons;
172
	std::unique_ptr<ImGuiOpenFile> openFile;
173
	std::unique_ptr<ImGuiMedia> media;
174
	std::unique_ptr<ImGuiConnector> connector;
175
	std::unique_ptr<ImGuiTools> tools;
176
	std::unique_ptr<ImGuiTrainer> trainer;
177
	std::unique_ptr<ImGuiSCCViewer> sccViewer;
178
	std::unique_ptr<ImGuiMsxMusicViewer> msxMusicViewer;
179
	std::unique_ptr<ImGuiWaveViewer> waveViewer;
180
	std::unique_ptr<ImGuiCheatFinder> cheatFinder;
181
	std::unique_ptr<ImGuiSlotMap> slotMap;
182
	std::unique_ptr<ImGuiDiskManipulator> diskManipulator;
183
	std::unique_ptr<ImGuiSettings> settings;
184
	std::unique_ptr<ImGuiSoundChip> soundChip;
185
	std::unique_ptr<ImGuiKeyboard> keyboard;
186
	std::unique_ptr<ImGuiConsole> console;
187
	std::unique_ptr<ImGuiMessages> messages;
188
189
	bool menuFade = true;
190
	bool needReloadFont = false;
191
	bool statusBarVisible = false;
192
	bool statusBarItemVisibilityFps = true;
193
	bool statusBarItemVisibilityScreenModeInfo = true;
194
	bool statusBarItemVisibilityTime = true;
195
	bool statusBarItemVisibilityActualSpeed = true;
196
	bool statusBarItemVisibilityMachine = true;
197
	bool statusBarItemVisibilityRunningSoftware = true;
198
199
	std::string loadIniFile;
200
201
private:
202
	std::vector<std::function<void()>> delayedActionQueue;
203
	std::vector<std::function<void()>> delayedActionQueue2;
204
	float menuAlpha = 1.0f;
205
206
	std::string droppedFile;
207
	std::string insertedInfo;
208
	std::vector<std::string> selectList;
209
	std::string selectedMedia;
210
	const RomInfo* romInfo = nullptr;
211
	RomType selectedRomType = RomType::UNKNOWN;
212
	float insertedInfoTimeout = 0.0f;
213
	gl::ivec2 windowPos;
214
	bool mainMenuBarUndocked = false;
215
	bool handleDropped = false;
216
	bool openInsertedInfo = false;
217
	bool guiActive = false;
218
219
	EmuTime prevBoardTime = EmuTime::zero();
220
	float speedDrawTimeOut = 0.0f;
221
	float fpsDrawTimeOut = 0.0f;
222
	float fps = 0.0f;
223
	float speed = 0.0f;
224
225
	static constexpr auto persistentElements = std::tuple{
226
		PersistentElement{"mainMenuBarUndocked", &ImGuiManager::mainMenuBarUndocked},
227
		PersistentElement{"mainMenuBarFade",     &ImGuiManager::menuFade},
228
		PersistentElement{"windowPos",           &ImGuiManager::windowPos},
229
		PersistentElement{"statusBarVisible",    &ImGuiManager::statusBarVisible},
230
		PersistentElement{"statusBarItemvisibility.fps",                 &ImGuiManager::statusBarItemVisibilityFps},
231
		PersistentElement{"statusBarItemVisibility.screenModeInfo",      &ImGuiManager::statusBarItemVisibilityScreenModeInfo},
232
		PersistentElement{"statusBarItemVisibility.time",                &ImGuiManager::statusBarItemVisibilityTime},
233
		PersistentElement{"statusBarItemVisibility.actualSpeed",         &ImGuiManager::statusBarItemVisibilityActualSpeed},
234
		PersistentElement{"statusBarItemVisibility.machine",             &ImGuiManager::statusBarItemVisibilityMachine},
235
		PersistentElement{"statusBarItemVisibility.runningSoftware",     &ImGuiManager::statusBarItemVisibilityRunningSoftware},
236
	};
237
};
238
239
// Parse machine or extension config files:
240
//  store config-name, display-name and meta-data
241
template<typename InfoType>
242
std::vector<InfoType> parseAllConfigFiles(ImGuiManager& manager, std::string_view type, std::initializer_list<std::string_view> topics)
243
{
244
	static constexpr auto replacer = StringReplacer::create(
245
		"name",         "Name",
246
		"manufacturer", "Manufacturer",
247
		"code",         "Product code",
248
		"region",       "Region",
249
		"release_year", "Release year",
250
		"description",  "Description",
251
		"type",         "Type");
252
253
	std::vector<InfoType> result;
254
255
	const auto& configs = Reactor::getHwConfigs(type);
256
	result.reserve(configs.size());
257
	for (const auto& config : configs) {
258
		auto& info = result.emplace_back();
259
		info.configName = config;
260
261
		// get machine meta-data
262
		auto& configInfo = info.configInfo;
263
		if (auto r = manager.execute(makeTclList("openmsx_info", type, config))) {
264
			auto first = r->begin();
265
			auto last = r->end();
266
			while (first != last) {
267
				auto desc = *first++;
268
				if (first == last) break; // shouldn't happen
269
				auto value = *first++;
270
				if (!value.empty()) {
271
					configInfo.emplace_back(std::string(replacer(desc)),
272
								std::string(value));
273
				}
274
			}
275
		}
276
277
		// Based on the above meta-data, try to construct a more
278
		// readable name Unfortunately this new name is no
279
		// longer guaranteed to be unique, we'll address this
280
		// below.
281
		auto& display = info.displayName;
282
		for (const auto topic : topics) {
283
			if (const auto* value = getOptionalDictValue(configInfo, topic)) {
284
				if (!value->empty()) {
285
					if (!display.empty()) strAppend(display, ' ');
286
					strAppend(display, *value);
287
				}
288
			}
289
		}
290
		if (display.empty()) display = config;
291
	}
292
293
	std::ranges::sort(result, StringOp::caseless{}, &InfoType::displayName);
294
295
	// make 'displayName' unique again
296
	auto sameDisplayName = [](InfoType& x, InfoType& y) {
297
		StringOp::casecmp cmp;
298
		return cmp(x.displayName, y.displayName);
299
	};
300
	chunk_by(result, sameDisplayName, [](auto first, auto last) {
301
		if (std::distance(first, last) == 1) return; // no duplicate name
302
		for (auto it = first; it != last; ++it) {
303
			strAppend(it->displayName, " (", it->configName, ')');
304
		}
305
		std::ranges::sort(first, last, StringOp::caseless{}, &InfoType::displayName);
306
	});
307
308
	return result;
309
}
310
311
} // namespace openmsx
312
313
#endif