openMSX
ImGuiManager.cc
Go to the documentation of this file.
1#include "ImGuiManager.hh"
2
4#include "ImGuiBreakPoints.hh"
5#include "ImGuiCharacter.hh"
6#include "ImGuiCheatFinder.hh"
7#include "ImGuiCpp.hh"
8#include "ImGuiConnector.hh"
9#include "ImGuiConsole.hh"
10#include "ImGuiDebugger.hh"
12#include "ImGuiHelp.hh"
13#include "ImGuiKeyboard.hh"
14#include "ImGuiMachine.hh"
15#include "ImGuiMedia.hh"
16#include "ImGuiMessages.hh"
17#include "ImGuiOpenFile.hh"
18#include "ImGuiPalette.hh"
19#include "ImGuiOsdIcons.hh"
20#include "ImGuiReverseBar.hh"
21#include "ImGuiSettings.hh"
22#include "ImGuiSoundChip.hh"
23#include "ImGuiSpriteViewer.hh"
24#include "ImGuiSymbols.hh"
25#include "ImGuiTools.hh"
26#include "ImGuiTrainer.hh"
27#include "ImGuiUtils.hh"
28#include "ImGuiVdpRegs.hh"
29#include "ImGuiWatchExpr.hh"
30
31
33#include "CommandException.hh"
34#include "Display.hh"
35#include "Event.hh"
36#include "EventDistributor.hh"
37#include "FileContext.hh"
38#include "FileOperations.hh"
39#include "FilePool.hh"
40#include "Reactor.hh"
41#include "RealDrive.hh"
42#include "RomDatabase.hh"
43#include "RomInfo.hh"
44#include "SettingsConfig.hh"
45
46#include "stl.hh"
47#include "strCat.hh"
48
49#include <imgui.h>
50#include <imgui_impl_opengl3.h>
51#include <imgui_impl_sdl2.h>
52#include <imgui_internal.h>
53#include <CustomFont.ii> // icons for ImGuiFileDialog
54
55#include <SDL.h>
56
57namespace openmsx {
58
59using namespace std::literals;
60
61ImFont* ImGuiManager::addFont(zstring_view filename, int fontSize)
62{
63 auto& io = ImGui::GetIO();
64 if (!filename.empty()) {
65 try {
66 const auto& context = systemFileContext();
67
68 File file(context.resolve(FileOperations::join("skins", filename)));
69 auto fileSize = file.getSize();
70 auto ttfData = std::span(
71 static_cast<uint8_t*>(ImGui::MemAlloc(fileSize)), fileSize);
72 file.read(ttfData);
73
74 static const std::array<ImWchar, 2*6 + 1> ranges = {
75 0x0020, 0x00FF, // Basic Latin + Latin Supplement
76 0x0370, 0x03FF, // Greek and Coptic
77 0x0400, 0x052F, // Cyrillic + Cyrillic Supplement
78 //0x0E00, 0x0E7F, // Thai
79 //0x2000, 0x206F, // General Punctuation
80 //0x2DE0, 0x2DFF, // Cyrillic Extended-A
81 0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
82 0x3131, 0x3163, // Korean alphabets
83 0x31F0, 0x31FF, // Katakana Phonetic Extensions
84 //0x4e00, 0x9FAF, // CJK Ideograms
85 //0xA640, 0xA69F, // Cyrillic Extended-B
86 //0xAC00, 0xD7A3, // Korean characters
87 //0xFF00, 0xFFEF, // Half-width characters
88 0
89 };
90 return io.Fonts->AddFontFromMemoryTTF(
91 ttfData.data(), // transfer ownership of 'ttfData' buffer
92 narrow<int>(ttfData.size()), narrow<float>(fontSize),
93 nullptr, ranges.data());
94 } catch (MSXException& e) {
95 getCliComm().printWarning("Couldn't load font: ", filename, ": ", e.getMessage(),
96 ". Reverted to builtin font");
97 }
98 }
99 return io.Fonts->AddFontDefault(); // embedded "ProggyClean.ttf", size 13
100}
101
102void ImGuiManager::loadFont()
103{
104 ImGuiIO& io = ImGui::GetIO();
105
106 assert(fontProp == nullptr);
108
110 static constexpr std::array<ImWchar, 3> icons_ranges = {ICON_MIN_IGFD, ICON_MAX_IGFD, 0};
111 ImFontConfig icons_config; icons_config.MergeMode = true; icons_config.PixelSnapH = true;
112 io.Fonts->AddFontFromMemoryCompressedBase85TTF(FONT_ICON_BUFFER_NAME_IGFD, 15.0f, &icons_config, icons_ranges.data());
113 // load debugger icons, also only in default font
115
116 assert(fontMono == nullptr);
118}
119
120void ImGuiManager::reloadFont()
121{
122 fontProp = fontMono = nullptr;
123
125
126 ImGuiIO& io = ImGui::GetIO();
127 io.Fonts->Clear();
128 loadFont();
129 io.Fonts->Build();
130
132}
133
134void ImGuiManager::initializeImGui()
135{
136 // Setup Dear ImGui context
137 IMGUI_CHECKVERSION();
138 ImGui::CreateContext();
139 ImGuiIO& io = ImGui::GetIO();
140 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard |
141 //ImGuiConfigFlags_NavEnableGamepad | // TODO revisit this later
142 ImGuiConfigFlags_DockingEnable |
143 ImGuiConfigFlags_ViewportsEnable;
144 static auto iniFilename = systemFileContext().resolveCreate("imgui.ini");
145 io.IniFilename = iniFilename.c_str();
146
147 loadFont();
148}
149
150static void cleanupImGui()
151{
152 ImGui::DestroyContext();
153}
154
155
157 : reactor(reactor_)
158 , fontPropFilename(reactor.getCommandController(), "gui_font_default_filename", "TTF font filename for the default GUI font", "DejaVuSans.ttf.gz")
159 , fontMonoFilename(reactor.getCommandController(), "gui_font_mono_filename", "TTF font filename for the monospaced GUI font", "DejaVuSansMono.ttf.gz")
160 , fontPropSize(reactor.getCommandController(), "gui_font_default_size", "size for the default GUI font", 13, 9, 72)
161 , fontMonoSize(reactor.getCommandController(), "gui_font_mono_size", "size for the monospaced GUI font", 13, 9, 72)
162 , windowPos{SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED}
163{
164 settingsConfig.setShortcuts(shortcuts);
165 parts.push_back(this);
166
167 // In order that they appear in the menubar
168 machine = std::make_unique<ImGuiMachine>(*this);
169 media = std::make_unique<ImGuiMedia>(*this);
170 connector = std::make_unique<ImGuiConnector>(*this);
171 reverseBar = std::make_unique<ImGuiReverseBar>(*this);
172 tools = std::make_unique<ImGuiTools>(*this);
173 settings = std::make_unique<ImGuiSettings>(*this);
174 debugger = std::make_unique<ImGuiDebugger>(*this);
175 help = std::make_unique<ImGuiHelp>(*this);
176
177 breakPoints = std::make_unique<ImGuiBreakPoints>(*this);
178 symbols = std::make_unique<ImGuiSymbols>(*this);
179 watchExpr = std::make_unique<ImGuiWatchExpr>(*this);
180 bitmap = std::make_unique<ImGuiBitmapViewer>(*this);
181 character = std::make_unique<ImGuiCharacter>(*this);
182 sprite = std::make_unique<ImGuiSpriteViewer>(*this);
183 vdpRegs = std::make_unique<ImGuiVdpRegs>(*this);
184 palette = std::make_unique<ImGuiPalette>(*this);
185 osdIcons = std::make_unique<ImGuiOsdIcons>(*this);
186 openFile = std::make_unique<ImGuiOpenFile>(*this);
187 trainer = std::make_unique<ImGuiTrainer>(*this);
188 cheatFinder = std::make_unique<ImGuiCheatFinder>(*this);
189 diskManipulator = std::make_unique<ImGuiDiskManipulator>(*this);
190 soundChip = std::make_unique<ImGuiSoundChip>(*this);
191 keyboard = std::make_unique<ImGuiKeyboard>(*this);
192 console = std::make_unique<ImGuiConsole>(*this);
193 messages = std::make_unique<ImGuiMessages>(*this);
194 initializeImGui();
195
196 ImGuiSettingsHandler ini_handler;
197 ini_handler.TypeName = "openmsx";
198 ini_handler.TypeHash = ImHashStr("openmsx");
199 ini_handler.UserData = this;
200 //ini_handler.ClearAllFn = [](ImGuiContext*, ImGuiSettingsHandler* handler) { // optional
201 // // Clear all settings data
202 // static_cast<ImGuiManager*>(handler->UserData)->iniClearAll();
203 //};
204 ini_handler.ReadInitFn = [](ImGuiContext*, ImGuiSettingsHandler* handler) { // optional
205 // Read: Called before reading (in registration order)
206 static_cast<ImGuiManager*>(handler->UserData)->iniReadInit();
207 };
208 ini_handler.ReadOpenFn = [](ImGuiContext*, ImGuiSettingsHandler* handler, const char* name) -> void* { // required
209 // Read: Called when entering into a new ini entry e.g. "[Window][Name]"
210 return static_cast<ImGuiManager*>(handler->UserData)->iniReadOpen(name);
211 };
212 ini_handler.ReadLineFn = [](ImGuiContext*, ImGuiSettingsHandler* handler, void* entry, const char* line) { // required
213 // Read: Called for every line of text within an ini entry
214 static_cast<ImGuiManager*>(handler->UserData)->loadLine(entry, line);
215 };
216 ini_handler.ApplyAllFn = [](ImGuiContext*, ImGuiSettingsHandler* handler) { // optional
217 // Read: Called after reading (in registration order)
218 static_cast<ImGuiManager*>(handler->UserData)->iniApplyAll();
219 };
220 ini_handler.WriteAllFn = [](ImGuiContext*, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf) { // required
221 // Write: Output every entries into 'out_buf'
222 static_cast<ImGuiManager*>(handler->UserData)->iniWriteAll(*out_buf);
223 };
224 ImGui::AddSettingsHandler(&ini_handler);
225
226 auto& eventDistributor = reactor.getEventDistributor();
227 using enum EventType;
231 eventDistributor.registerEventListener(type, *this, EventDistributor::IMGUI);
232 }
233
236 fontPropSize.attach(*this);
237 fontMonoSize.attach(*this);
238}
239
241{
242 fontMonoSize.detach(*this);
243 fontPropSize.detach(*this);
246
247 auto& eventDistributor = reactor.getEventDistributor();
248 using enum EventType;
249 for (auto type : {BREAK, IMGUI_DELAYED_ACTION, FILE_DROP, WINDOW, TEXT,
252 eventDistributor.unregisterEventListener(type, *this);
253 }
254
255 cleanupImGui();
256}
257
259{
260 assert(!contains(parts, part));
261 assert(!contains(toBeAddedParts, part));
262 toBeAddedParts.push_back(part);
263}
264
266{
267 if (auto it1 = ranges::find(parts, part); it1 != parts.end()) {
268 *it1 = nullptr;
269 removeParts = true; // filter nullptr later
270 } else if (auto it2 = ranges::find(toBeAddedParts, part); it2 != toBeAddedParts.end()) {
271 toBeAddedParts.erase(it2); // fine to remove now
272 }
273}
274
275void ImGuiManager::updateParts()
276{
277 if (removeParts) {
278 removeParts = false;
279 parts.erase(ranges::remove(parts, nullptr), parts.end());
280 }
281
282 append(parts, toBeAddedParts);
283 toBeAddedParts.clear();
284}
285
286void ImGuiManager::save(ImGuiTextBuffer& buf)
287{
288 // We cannot query "reactor.getDisplay().getWindowPosition()" here
289 // because display may already be destroyed. Instead Display pushes
290 // window position to here
291 savePersistent(buf, *this, persistentElements);
292}
293
294void ImGuiManager::loadLine(std::string_view name, zstring_view value)
295{
296 loadOnePersistent(name, value, *this, persistentElements);
297}
298
299void ImGuiManager::loadEnd()
300{
301 reactor.getDisplay().setWindowPosition(windowPos);
302}
303
305{
306 return reactor.getInterpreter();
307}
308
310{
311 return reactor.getCliComm();
312}
313
314std::optional<TclObject> ImGuiManager::execute(TclObject command)
315{
316 try {
317 return command.executeCommand(getInterpreter());
318 } catch (CommandException&) {
319 // ignore
320 return {};
321 }
322}
323
324void ImGuiManager::executeDelayed(std::function<void()> action)
325{
326 delayedActionQueue.push_back(std::move(action));
328}
329
331 const std::function<void(const TclObject&)>& ok,
332 const std::function<void(const std::string&)>& error)
333{
334 executeDelayed([this, command, ok, error]() mutable {
335 try {
336 auto result = command.executeCommand(getInterpreter());
337 if (ok) ok(result);
338 } catch (CommandException& e) {
339 if (error) error(e.getMessage());
340 }
341 });
342}
343
345 const std::function<void(const TclObject&)>& ok)
346{
347 executeDelayed(std::move(command), ok,
348 [this](const std::string& message) { this->printError(message); });
349}
350
351void ImGuiManager::printError(std::string_view message)
352{
353 getCliComm().printError(message);
354}
355
356int ImGuiManager::signalEvent(const Event& event)
357{
358 if (auto* evt = get_event_if<SdlEvent>(event)) {
359 const SDL_Event& sdlEvent = evt->getSdlEvent();
361 const ImGuiIO& io = ImGui::GetIO();
362 if ((io.WantCaptureMouse &&
363 sdlEvent.type == one_of(SDL_MOUSEMOTION, SDL_MOUSEWHEEL,
364 SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP)) ||
365 (io.WantCaptureKeyboard &&
366 sdlEvent.type == one_of(SDL_KEYDOWN, SDL_KEYUP, SDL_TEXTINPUT))) {
367 static constexpr auto block = EventDistributor::Priority(EventDistributor::IMGUI + 1);
368 return block; // block event for lower priority listeners
369 }
370 } else {
371 switch (getType(event)) {
373 for (auto& action : delayedActionQueue) {
374 std::invoke(action);
375 }
376 delayedActionQueue.clear();
377 break;
378 }
380 const auto& fde = get_event<FileDropEvent>(event);
381 droppedFile = fde.getFileName();
382 handleDropped = true;
383 break;
384 }
385 case EventType::BREAK:
386 debugger->signalBreak();
387 break;
388 default:
390 }
391 }
392 return 0;
393}
394
395void ImGuiManager::update(const Setting& /*setting*/) noexcept
396{
397 needReloadFont = true;
398}
399
400// TODO share code with ImGuiMedia
401static std::vector<std::string> getDrives(MSXMotherBoard* motherBoard)
402{
403 std::vector<std::string> result;
404 if (!motherBoard) return result;
405
406 std::string driveName = "diskX";
407 auto drivesInUse = RealDrive::getDrivesInUse(*motherBoard);
408 for (auto i : xrange(RealDrive::MAX_DRIVES)) {
409 if (!(*drivesInUse)[i]) continue;
410 driveName[4] = char('a' + i);
411 result.push_back(driveName);
412 }
413 return result;
414}
415
416static std::vector<std::string> getSlots(MSXMotherBoard* motherBoard)
417{
418 std::vector<std::string> result;
419 if (!motherBoard) return result;
420
421 const auto& slotManager = motherBoard->getSlotManager();
422 std::string cartName = "cartX";
423 for (auto slot : xrange(CartridgeSlotManager::MAX_SLOTS)) {
424 if (!slotManager.slotExists(slot)) continue;
425 cartName[4] = char('a' + slot);
426 result.push_back(cartName);
427 }
428 return result;
429}
430
432{
433 if (!loadIniFile.empty()) {
434 ImGui::LoadIniSettingsFromDisk(loadIniFile.c_str());
435 loadIniFile.clear();
436 }
437 if (needReloadFont) {
438 needReloadFont = false;
439 reloadFont();
440 }
441}
442
444{
445 // Apply added/removed parts. Avoids iterating over a changing vector.
446 updateParts();
447
448 auto* motherBoard = reactor.getMotherBoard();
449 for (auto* part : parts) {
450 part->paint(motherBoard);
451 }
453 openFile->doPaint();
454 }
455
456 auto drawMenu = [&]{
457 for (auto* part : parts) {
458 part->showMenu(motherBoard);
459 }
460 };
461 if (mainMenuBarUndocked) {
462 im::Window("openMSX main menu", &mainMenuBarUndocked, ImGuiWindowFlags_MenuBar, [&]{
463 im::MenuBar([&]{
464 if (ImGui::ArrowButton("re-dock-button", ImGuiDir_Down)) {
465 mainMenuBarUndocked = false;
466 }
467 simpleToolTip("Dock the menu bar in the main openMSX window.");
468 drawMenu();
469 });
470 });
471 } else {
472 bool active = ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow) ||
473 ImGui::IsWindowFocused(ImGuiHoveredFlags_AnyWindow);
474 if (active != guiActive) {
475 guiActive = active;
476 auto& eventDistributor = reactor.getEventDistributor();
477 eventDistributor.distributeEvent(ImGuiActiveEvent(active));
478 }
479 menuAlpha = [&] {
480 if (!menuFade) return 1.0f;
481 auto target = active ? 1.0f : 0.0001f;
482 auto period = active ? 0.5f : 5.0f;
483 return calculateFade(menuAlpha, target, period);
484 }();
485 im::StyleVar(ImGuiStyleVar_Alpha, menuAlpha, [&]{
486 im::MainMenuBar([&]{
487 if (ImGui::ArrowButton("undock-button", ImGuiDir_Up)) {
488 mainMenuBarUndocked = true;
489 }
490 simpleToolTip("Undock the menu bar from the main openMSX window.");
491 drawMenu();
492 });
493 });
494 }
495
496 // drag and drop (move this to ImGuiMedia ?)
497 auto insert2 = [&](std::string_view displayName, TclObject cmd) {
498 auto message = strCat("Inserted ", droppedFile, " in ", displayName);
499 executeDelayed(cmd, [this, message](const TclObject&){
500 insertedInfo = message;
501 openInsertedInfo = true;
502 });
503 };
504 auto insert = [&](std::string_view displayName, std::string_view cmd) {
505 insert2(displayName, makeTclList(cmd, "insert", droppedFile));
506 };
507 if (handleDropped) {
508 handleDropped = false;
509 insertedInfo.clear();
510
511 auto category = execute(makeTclList("openmsx_info", "file_type_category", droppedFile))->getString();
512 if (category == "unknown" && FileOperations::isDirectory(droppedFile)) {
513 category = "disk";
514 }
515
516 auto error = [&](auto&& ...message) {
517 executeDelayed(makeTclList("error", strCat(message...)));
518 };
519 auto cantHandle = [&](auto&& ...message) {
520 error("Can't handle dropped file ", droppedFile, ": ", message...);
521 };
522 auto notPresent = [&](const auto& mediaType) {
523 cantHandle("no ", mediaType, " present.");
524 };
525
526 auto testMedia = [&](std::string_view displayName, std::string_view cmd) {
527 if (auto cmdResult = execute(TclObject(cmd))) {
528 insert(displayName, cmd);
529 } else {
530 notPresent(displayName);
531 }
532 };
533
534 if (category == "disk") {
535 auto list = getDrives(motherBoard);
536 if (list.empty()) {
537 notPresent("disk drive");
538 } else if (list.size() == 1) {
539 const auto& drive = list.front();
540 insert(strCat("disk drive ", char(drive.back() - 'a' + 'A')), drive);
541 } else {
542 selectList = std::move(list);
543 ImGui::OpenPopup("select-drive");
544 }
545 } else if (category == "rom") {
546 auto list = getSlots(motherBoard);
547 if (list.empty()) {
548 notPresent("cartridge slot");
549 return;
550 }
551 selectedMedia = list.front();
552 selectList = std::move(list);
553 if (auto sha1 = reactor.getFilePool().getSha1Sum(droppedFile)) {
554 romInfo = reactor.getSoftwareDatabase().fetchRomInfo(*sha1);
555 } else {
556 romInfo = nullptr;
557 }
558 selectedRomType = romInfo ? romInfo->getRomType()
559 : ROM_UNKNOWN; // auto-detect
560 ImGui::OpenPopup("select-cart");
561 } else if (category == "cassette") {
562 testMedia("casette port", "cassetteplayer");
563 } else if (category == "laserdisc") {
564 testMedia("laser disc player", "laserdiscplayer");
565 } else if (category == "savestate") {
566 executeDelayed(makeTclList("loadstate", droppedFile));
567 } else if (category == "replay") {
568 executeDelayed(makeTclList("reverse", "loadreplay", droppedFile));
569 } else if (category == "script") {
570 executeDelayed(makeTclList("source", droppedFile));
571 } else if (FileOperations::getExtension(droppedFile) == ".txt") {
572 executeDelayed(makeTclList("type_from_file", droppedFile));
573 } else {
574 cantHandle("unknown file type");
575 }
576 }
577 im::Popup("select-drive", [&]{
578 ImGui::TextUnformatted(tmpStrCat("Select disk drive for ", droppedFile));
579 auto n = std::min(3.5f, narrow<float>(selectList.size()));
580 auto height = n * ImGui::GetTextLineHeightWithSpacing() + ImGui::GetStyle().FramePadding.y;
581 im::ListBox("##select-media", {-FLT_MIN, height}, [&]{
582 for (const auto& item : selectList) {
583 auto drive = item.back() - 'a';
584 auto display = strCat(char('A' + drive), ": ", media->displayNameForDriveContent(drive, true));
585 if (ImGui::Selectable(display.c_str())) {
586 insert(strCat("disk drive ", char(drive + 'A')), item);
587 ImGui::CloseCurrentPopup();
588 }
589 }
590 });
591 });
592 im::Popup("select-cart", [&]{
593 ImGui::TextUnformatted(strCat("Filename: ", droppedFile));
594 ImGui::Separator();
595
596 if (!romInfo) {
597 ImGui::TextUnformatted("ROM not present in software database"sv);
598 }
599 im::Table("##extension-info", 2, [&]{
600 const char* buf = reactor.getSoftwareDatabase().getBufferStart();
601 ImGui::TableSetupColumn("description", ImGuiTableColumnFlags_WidthFixed);
602 ImGui::TableSetupColumn("value", ImGuiTableColumnFlags_WidthStretch);
603
604 if (romInfo) {
605 ImGuiMedia::printDatabase(*romInfo, buf);
606 }
607 if (ImGui::TableNextColumn()) {
608 ImGui::AlignTextToFramePadding();
609 ImGui::TextUnformatted("Mapper"sv);
610 }
611 if (ImGui::TableNextColumn()) {
612 ImGuiMedia::selectMapperType("##mapper-type", selectedRomType);
613 }
614 });
615 ImGui::Separator();
616
617 if (selectList.size() > 1) {
618 const auto& slotManager = motherBoard->getSlotManager();
619 ImGui::TextUnformatted("Select cartridge slot"sv);
620 auto n = std::min(3.5f, narrow<float>(selectList.size()));
621 auto height = n * ImGui::GetTextLineHeightWithSpacing() + ImGui::GetStyle().FramePadding.y;
622 im::ListBox("##select-media", {-FLT_MIN, height}, [&]{
623 for (const auto& item : selectList) {
624 auto slot = item.back() - 'a';
625 auto display = strCat(
626 char('A' + slot),
627 " (", slotManager.getPsSsString(slot), "): ",
628 media->displayNameForSlotContent(slotManager, slot, true));
629
630 if (ImGui::Selectable(display.c_str(), item == selectedMedia)) {
631 selectedMedia = item;
632 }
633 }
634 });
635 }
636
637 ImGui::Checkbox("Reset MSX on inserting ROM", &media->resetOnInsertRom);
638
639 if (ImGui::Button("Insert ROM")) {
640 auto cmd = makeTclList(selectedMedia, "insert", droppedFile);
641 if (selectedRomType != ROM_UNKNOWN) {
642 cmd.addListElement("-romtype", RomInfo::romTypeToName(selectedRomType));
643 }
644 insert2(strCat("cartridge slot ", char(selectedMedia.back() - 'a' + 'A')), cmd);
645 if (media->resetOnInsertRom) {
646 executeDelayed(TclObject("reset"));
647 }
648 ImGui::CloseCurrentPopup();
649 }
650 ImGui::SameLine();
651 if (ImGui::Button("Cancel")) {
652 ImGui::CloseCurrentPopup();
653 }
654 });
655 if (openInsertedInfo) {
656 openInsertedInfo = false;
657 insertedInfoTimeout = 3.0f;
658 ImGui::OpenPopup("inserted-info");
659 }
660 im::Popup("inserted-info", [&]{
661 insertedInfoTimeout -= ImGui::GetIO().DeltaTime;
662 if (insertedInfoTimeout <= 0.0f || insertedInfo.empty()) {
663 ImGui::CloseCurrentPopup();
664 }
665 im::TextWrapPos(ImGui::GetFontSize() * 35.0f, [&]{
666 ImGui::TextUnformatted(insertedInfo);
667 });
668 });
669}
670
671void ImGuiManager::iniReadInit()
672{
673 updateParts();
674 for (auto* part : parts) {
675 if (part) { // loadStart() could call unregisterPart()
676 part->loadStart();
677 }
678 }
679}
680
681void* ImGuiManager::iniReadOpen(std::string_view name)
682{
683 updateParts();
684 for (auto* part : parts) {
685 if (part->iniName() == name) return part;
686 }
687 return nullptr;
688}
689
690void ImGuiManager::loadLine(void* entry, const char* line_) const
691{
692 zstring_view line = line_;
693 auto pos = line.find('=');
694 if (pos == zstring_view::npos) return;
695 std::string_view name = line.substr(0, pos);
696 zstring_view value = line.substr(pos + 1);
697
698 assert(entry);
699 static_cast<ImGuiPartInterface*>(entry)->loadLine(name, value);
700}
701
702void ImGuiManager::iniApplyAll()
703{
704 updateParts();
705 for (auto* part : parts) {
706 part->loadEnd();
707 }
708}
709
710void ImGuiManager::iniWriteAll(ImGuiTextBuffer& buf)
711{
712 updateParts();
713 for (auto* part : parts) {
714 if (auto name = part->iniName(); !name.empty()) {
715 buf.appendf("[openmsx][%s]\n", name.c_str());
716 part->save(buf);
717 buf.append("\n");
718 }
719 }
720}
721
722} // namespace openmsx
void printError(std::string_view message)
Definition CliComm.cc:15
void printWarning(std::string_view message)
Definition CliComm.cc:10
void setWindowPosition(gl::ivec2 pos)
Definition Display.cc:230
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
void distributeEvent(Event &&event)
Schedule the given event for delivery.
void registerEventListener(EventType type, EventListener &listener, Priority priority=OTHER)
Registers a given object to receive certain events.
Priority
Priorities from high to low, higher priority listeners can block events for lower priority listeners.
std::string resolveCreate(std::string_view filename) const
Sha1Sum getSha1Sum(File &file)
Calculate sha1sum for the given File object.
Definition FilePool.cc:58
zstring_view getString() const noexcept
std::unique_ptr< ImGuiMachine > machine
void registerPart(ImGuiPartInterface *part)
std::unique_ptr< ImGuiBreakPoints > breakPoints
void printError(std::string_view message)
std::unique_ptr< ImGuiVdpRegs > vdpRegs
std::unique_ptr< ImGuiCheatFinder > cheatFinder
std::unique_ptr< ImGuiTrainer > trainer
std::unique_ptr< ImGuiDiskManipulator > diskManipulator
IntegerSetting fontMonoSize
std::unique_ptr< ImGuiWatchExpr > watchExpr
std::unique_ptr< ImGuiPalette > palette
std::unique_ptr< ImGuiConnector > connector
std::optional< TclObject > execute(TclObject command)
std::unique_ptr< ImGuiKeyboard > keyboard
std::unique_ptr< ImGuiHelp > help
IntegerSetting fontPropSize
std::unique_ptr< ImGuiSpriteViewer > sprite
Interpreter & getInterpreter()
std::unique_ptr< ImGuiConsole > console
std::unique_ptr< ImGuiSoundChip > soundChip
std::unique_ptr< ImGuiReverseBar > reverseBar
std::unique_ptr< ImGuiMedia > media
std::unique_ptr< ImGuiMessages > messages
std::unique_ptr< ImGuiOpenFile > openFile
std::unique_ptr< ImGuiOsdIcons > osdIcons
FilenameSetting fontPropFilename
std::unique_ptr< ImGuiBitmapViewer > bitmap
std::unique_ptr< ImGuiSettings > settings
std::unique_ptr< ImGuiDebugger > debugger
std::unique_ptr< ImGuiCharacter > character
void unregisterPart(ImGuiPartInterface *part)
std::unique_ptr< ImGuiTools > tools
void executeDelayed(std::function< void()> action)
ImGuiManager(Reactor &reactor_, SettingsConfig &config_)
FilenameSetting fontMonoFilename
std::unique_ptr< ImGuiSymbols > symbols
static void printDatabase(const RomInfo &romInfo, const char *buf)
static bool selectMapperType(const char *label, RomType &item)
int getInt() const noexcept
Contains the main loop of openMSX.
Definition Reactor.hh:74
MSXMotherBoard * getMotherBoard() const
Definition Reactor.cc:409
Display & getDisplay()
Definition Reactor.hh:92
CliComm & getCliComm()
Definition Reactor.cc:323
Interpreter & getInterpreter()
Definition Reactor.cc:328
EventDistributor & getEventDistributor()
Definition Reactor.hh:88
RomDatabase & getSoftwareDatabase()
Definition Reactor.cc:315
FilePool & getFilePool()
Definition Reactor.hh:97
static std::shared_ptr< DrivesInUse > getDrivesInUse(MSXMotherBoard &motherBoard)
Definition RealDrive.cc:21
const RomInfo * fetchRomInfo(const Sha1Sum &sha1sum) const
Lookup an entry in the database by sha1sum.
static std::string_view romTypeToName(RomType type)
Definition RomInfo.cc:188
RomType getRomType() const
Definition RomInfo.hh:61
void setShortcuts(Shortcuts &shortcuts_)
void detach(Observer< T > &observer)
Definition Subject.hh:60
void attach(Observer< T > &observer)
Definition Subject.hh:54
TclObject executeCommand(Interpreter &interp, bool compile=false)
Interpret this TclObject as a command and execute it.
Definition TclObject.cc:248
Like std::string_view, but with the extra guarantee that it refers to a zero-terminated string.
static constexpr auto npos
constexpr auto find(char c, size_type pos=0) const
constexpr zstring_view substr(size_type pos) const
constexpr auto empty() const
ImGuiID ImHashStr(const char *data_p, size_t data_size, ImGuiID seed)
Definition imgui.cc:2086
bool ImGui_ImplOpenGL3_CreateFontsTexture()
void ImGui_ImplOpenGL3_DestroyFontsTexture()
bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event *event)
void TextUnformatted(const std::string &str)
Definition ImGuiUtils.hh:24
constexpr double e
Definition Math.hh:21
std::optional< Context > context
Definition GLContext.cc:10
void Table(const char *str_id, int column, ImGuiTableFlags flags, const ImVec2 &outer_size, float inner_width, std::invocable<> auto next)
Definition ImGuiCpp.hh:459
void MainMenuBar(std::invocable<> auto next)
Definition ImGuiCpp.hh:354
void MenuBar(std::invocable<> auto next)
Definition ImGuiCpp.hh:345
void Window(const char *name, bool *p_open, ImGuiWindowFlags flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:63
void StyleVar(ImGuiStyleVar idx, float val, std::invocable<> auto next)
Definition ImGuiCpp.hh:190
void ListBox(const char *label, const ImVec2 &size, std::invocable<> auto next)
Definition ImGuiCpp.hh:332
void TextWrapPos(float wrap_local_pos_x, std::invocable<> auto next)
Definition ImGuiCpp.hh:212
void Popup(const char *str_id, ImGuiWindowFlags flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:395
string_view getExtension(string_view path)
Returns the extension portion of a path.
bool isDirectory(const Stat &st)
string join(string_view part1, string_view part2)
Join two paths.
This file implemented 3 utility functions:
Definition Autofire.cc:11
const FileContext & systemFileContext()
EventType
Definition Event.hh:455
bool loadOnePersistent(std::string_view name, zstring_view value, C &c, const std::tuple< Elements... > &tup)
void simpleToolTip(std::string_view desc)
Definition ImGuiUtils.hh:66
void savePersistent(ImGuiTextBuffer &buf, C &c, const std::tuple< Elements... > &tup)
EventType getType(const Event &event)
Definition Event.hh:518
@ ROM_UNKNOWN
Definition RomTypes.hh:94
std::variant< KeyUpEvent, KeyDownEvent, MouseMotionEvent, MouseButtonUpEvent, MouseButtonDownEvent, MouseWheelEvent, JoystickAxisMotionEvent, JoystickHatEvent, JoystickButtonUpEvent, JoystickButtonDownEvent, OsdControlReleaseEvent, OsdControlPressEvent, WindowEvent, TextEvent, FileDropEvent, QuitEvent, FinishFrameEvent, CliCommandEvent, GroupEvent, BootEvent, FrameDrawnEvent, BreakEvent, SwitchRendererEvent, TakeReverseSnapshotEvent, AfterTimedEvent, MachineLoadedEvent, MachineActivatedEvent, MachineDeactivatedEvent, MidiInReaderEvent, MidiInWindowsEvent, MidiInCoreMidiEvent, MidiInCoreMidiVirtualEvent, MidiInALSAEvent, Rs232TesterEvent, Rs232NetEvent, ImGuiDelayedActionEvent, ImGuiActiveEvent > Event
Definition Event.hh:446
float calculateFade(float current, float target, float period)
TclObject makeTclList(Args &&... args)
Definition TclObject.hh:293
auto remove(ForwardRange &&range, const T &value)
Definition ranges.hh:283
auto find(InputRange &&range, const T &value)
Definition ranges.hh:162
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition stl.hh:32
std::string strCat()
Definition strCat.hh:703
TemporaryString tmpStrCat(Ts &&... ts)
Definition strCat.hh:742
#define UNREACHABLE
constexpr auto xrange(T e)
Definition xrange.hh:132