mirror of
https://github.com/JaCzekanski/Avocado.git
synced 2024-05-20 04:50:32 -04:00
9409b91ced
Use builtin backends
564 lines
19 KiB
C++
564 lines
19 KiB
C++
#include "gui.h"
|
|
#include <fmt/core.h>
|
|
#include <imgui.h>
|
|
#include <platform/windows/utils/platform_tools.h>
|
|
#include "config.h"
|
|
#include <backends/imgui_impl_opengl3.h>
|
|
#include <backends/imgui_impl_sdl.h>
|
|
#include "platform/windows/input/key.h"
|
|
#include "platform/windows/gui/icons.h"
|
|
#include "system.h"
|
|
#include "state/state.h"
|
|
#include "utils/file.h"
|
|
#include "utils/string.h"
|
|
#include "images.h"
|
|
#include "disc/load.h"
|
|
#include "memory_card/card_formats.h"
|
|
|
|
float GUI::scale = 1.f;
|
|
|
|
GUI::GUI(SDL_Window* window, void* glContext) : window(window) {
|
|
ImGui::CreateContext();
|
|
ImGui::StyleColorsDark();
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
iniPath = avocado::PATH_USER + "imgui.ini";
|
|
io.IniFilename = iniPath.c_str();
|
|
// io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
|
#ifdef ANDROID
|
|
io.ConfigFlags |= ImGuiConfigFlags_IsTouchScreen;
|
|
#endif
|
|
|
|
scale = 1.f;
|
|
#ifdef ANDROID
|
|
float dpi = 1.f;
|
|
if (SDL_GetDisplayDPI(0, &dpi, nullptr, nullptr) == 0) {
|
|
scale = dpi / 160.f;
|
|
}
|
|
#endif
|
|
float fontSize = 16.f * scale;
|
|
|
|
ImGuiStyle& style = ImGui::GetStyle();
|
|
style.GrabRounding = 6.f;
|
|
style.FrameRounding = 6.f;
|
|
style.ScaleAllSizes(scale);
|
|
#ifdef ANDROID
|
|
style.TouchExtraPadding = ImVec2(10.f, 10.f);
|
|
#endif
|
|
|
|
ImFontConfig config;
|
|
config.OversampleH = 2;
|
|
config.OversampleV = 2;
|
|
config.FontDataOwnedByAtlas = false;
|
|
config.SizePixels = fontSize;
|
|
|
|
{
|
|
auto font = getFileContents(avocado::assetsPath("roboto-mono.ttf"));
|
|
io.Fonts->AddFontFromMemoryTTF(font.data(), font.size(), fontSize, &config);
|
|
}
|
|
|
|
{
|
|
ImFontConfig config;
|
|
config.SizePixels = 13.f * scale;
|
|
io.Fonts->AddFontDefault(&config);
|
|
}
|
|
|
|
{
|
|
auto font = getFileContents(avocado::assetsPath("fa-solid-900.ttf"));
|
|
const char* glyphs[] = {
|
|
ICON_FA_PLAY, ICON_FA_PAUSE, ICON_FA_SAVE, ICON_FA_COMPACT_DISC, ICON_FA_GAMEPAD, ICON_FA_COMPRESS, ICON_FA_COG, ICON_FA_SYNC,
|
|
};
|
|
|
|
ImVector<ImWchar> ranges;
|
|
ImFontGlyphRangesBuilder builder;
|
|
for (auto glyph : glyphs) {
|
|
builder.AddText(glyph);
|
|
}
|
|
builder.BuildRanges(&ranges);
|
|
io.Fonts->AddFontFromMemoryTTF(font.data(), font.size(), fontSize, &config, ranges.Data);
|
|
io.Fonts->Build();
|
|
}
|
|
|
|
ImGui_ImplSDL2_InitForOpenGL(window, glContext);
|
|
ImGui_ImplOpenGL3_Init();
|
|
|
|
busToken = bus.listen<Event::Gui::Debug::OpenDrawListWindows>([&](auto) {
|
|
gpuDebug.logWindowOpen = true;
|
|
gpuDebug.vramWindowOpen = true;
|
|
});
|
|
}
|
|
|
|
GUI::~GUI() {
|
|
bus.unlistenAll(busToken);
|
|
ImGui::DestroyContext();
|
|
}
|
|
|
|
void GUI::processEvent(SDL_Event* e) { ImGui_ImplSDL2_ProcessEvent(e); }
|
|
|
|
void GUI::mainMenu(std::unique_ptr<System>& sys) {
|
|
if (!ImGui::BeginMainMenuBar()) {
|
|
return;
|
|
}
|
|
if (ImGui::BeginMenu("File")) {
|
|
ImGui::MenuItem("Open", nullptr, &openFile.openWindowOpen);
|
|
#if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
|
|
ImGui::Separator();
|
|
if (ImGui::MenuItem("Open Avocado directory")) {
|
|
openFileBrowser(avocado::PATH_USER);
|
|
}
|
|
#endif
|
|
ImGui::Separator();
|
|
if (ImGui::MenuItem("Exit", "Esc")) bus.notify(Event::File::Exit{});
|
|
ImGui::EndMenu();
|
|
}
|
|
if (ImGui::BeginMenu("Emulation")) {
|
|
if (ImGui::MenuItem("Pause/Resume", Key(config.hotkeys["toggle_pause"]).getButton().c_str())) {
|
|
if (sys->state == System::State::pause) {
|
|
sys->state = System::State::run;
|
|
} else if (sys->state == System::State::run) {
|
|
sys->state = System::State::pause;
|
|
}
|
|
}
|
|
if (ImGui::MenuItem("Soft reset", Key(config.hotkeys["reset"]).getButton().c_str())) {
|
|
bus.notify(Event::System::SoftReset{});
|
|
}
|
|
|
|
std::string key = "Shift+";
|
|
key += Key(config.hotkeys["reset"]).getButton();
|
|
if (ImGui::MenuItem("Hard reset", key.c_str())) {
|
|
bus.notify(Event::System::HardReset{});
|
|
}
|
|
|
|
const char* shellStatus = sys->cdrom->getShell() ? "Close disk tray" : "Open disk tray";
|
|
if (ImGui::MenuItem(shellStatus, Key(config.hotkeys["close_tray"]).getButton().c_str())) {
|
|
sys->cdrom->setShell(!sys->cdrom->getShell());
|
|
}
|
|
|
|
if (ImGui::MenuItem("Single frame", Key(config.hotkeys["single_frame"]).getButton().c_str())) {
|
|
singleFrame = true;
|
|
sys->state = System::State::run;
|
|
}
|
|
|
|
ImGui::Separator();
|
|
|
|
if (ImGui::MenuItem("Quick save", Key(config.hotkeys["quick_save"]).getButton().c_str())) {
|
|
bus.notify(Event::System::SaveState{});
|
|
}
|
|
|
|
bool quickLoadStateExists = fs::exists(state::getStatePath(sys.get()));
|
|
if (ImGui::MenuItem("Quick load", Key(config.hotkeys["quick_load"]).getButton().c_str(), nullptr, quickLoadStateExists))
|
|
bus.notify(Event::System::LoadState{});
|
|
|
|
if (ImGui::BeginMenu("Save")) {
|
|
for (int i = 1; i <= 5; i++) {
|
|
if (ImGui::MenuItem(fmt::format("Slot {}##save", i).c_str())) bus.notify(Event::System::SaveState{i});
|
|
}
|
|
ImGui::EndMenu();
|
|
}
|
|
|
|
if (ImGui::BeginMenu("Load")) {
|
|
bool anySaveExists = false;
|
|
for (int i = 1; i <= 5; i++) {
|
|
auto path = state::getStatePath(sys.get(), i);
|
|
if (fs::exists(path)) {
|
|
anySaveExists = true;
|
|
if (ImGui::MenuItem(fmt::format("Slot {}##load", i).c_str())) bus.notify(Event::System::LoadState{i});
|
|
}
|
|
}
|
|
|
|
if (!anySaveExists) {
|
|
ImGui::TextUnformatted("No save states");
|
|
}
|
|
ImGui::EndMenu();
|
|
}
|
|
|
|
ImGui::EndMenu();
|
|
}
|
|
if (ImGui::BeginMenu("Debug")) {
|
|
if (ImGui::MenuItem("System log", nullptr, &sys->debugOutput)) {
|
|
config.debug.log.system = (int)sys->debugOutput;
|
|
}
|
|
if (ImGui::MenuItem("Syscall log", nullptr, (bool*)&sys->biosLog)) {
|
|
config.debug.log.bios = sys->biosLog;
|
|
}
|
|
#ifdef ENABLE_IO_LOG
|
|
ImGui::MenuItem("IO log", nullptr, &ioDebug.logWindowOpen);
|
|
#endif
|
|
ImGui::MenuItem("GTE log", nullptr, >eDebug.logWindowOpen);
|
|
ImGui::MenuItem("GPU log", nullptr, &gpuDebug.logWindowOpen);
|
|
|
|
ImGui::Separator();
|
|
|
|
ImGui::MenuItem("Debugger", nullptr, &cpuDebug.debuggerWindowOpen);
|
|
ImGui::MenuItem("Breakpoints", nullptr, &cpuDebug.breakpointsWindowOpen);
|
|
ImGui::MenuItem("Watch", nullptr, &cpuDebug.watchWindowOpen);
|
|
ImGui::MenuItem("RAM", nullptr, &cpuDebug.ramWindowOpen);
|
|
|
|
ImGui::Separator();
|
|
|
|
ImGui::MenuItem("CDROM", nullptr, &cdromDebug.cdromWindowOpen);
|
|
ImGui::MenuItem("Timers", nullptr, &timersDebug.timersWindowOpen);
|
|
ImGui::MenuItem("GPU", nullptr, &gpuDebug.registersWindowOpen);
|
|
ImGui::MenuItem("GTE", nullptr, >eDebug.registersWindowOpen);
|
|
ImGui::MenuItem("SPU", nullptr, &spuDebug.spuWindowOpen);
|
|
ImGui::MenuItem("VRAM", nullptr, &gpuDebug.vramWindowOpen);
|
|
ImGui::MenuItem("Kernel", nullptr, &showKernelWindow);
|
|
|
|
ImGui::Separator();
|
|
if (ImGui::MenuItem("Dump state")) {
|
|
sys->dumpRam();
|
|
sys->spu->dumpRam();
|
|
sys->gpu->dumpVram();
|
|
toast("State dumped");
|
|
}
|
|
ImGui::EndMenu();
|
|
}
|
|
if (ImGui::BeginMenu("Options")) {
|
|
if (ImGui::MenuItem("Graphics", nullptr)) showGraphicsOptionsWindow = true;
|
|
ImGui::MenuItem("BIOS", nullptr, &biosOptions.biosWindowOpen);
|
|
if (ImGui::MenuItem("Controller", nullptr)) showControllerSetupWindow = true;
|
|
if (ImGui::MenuItem("Hotkeys", nullptr)) showHotkeysSetupWindow = true;
|
|
ImGui::MenuItem("Memory Card", nullptr, &memoryCardOptions.memoryCardWindowOpen);
|
|
|
|
ImGui::MenuItem("System", nullptr, &systemOptions.systemWindowOpen);
|
|
|
|
bool soundEnabled = config.options.sound.enabled;
|
|
if (ImGui::MenuItem("Sound", nullptr, &soundEnabled)) {
|
|
config.options.sound.enabled = soundEnabled;
|
|
bus.notify(Event::Config::Spu{});
|
|
}
|
|
|
|
ImGui::Separator();
|
|
|
|
bool preserveState = config.options.emulator.preserveState;
|
|
if (ImGui::MenuItem("Save state on close", nullptr, &preserveState)) {
|
|
config.options.emulator.preserveState = preserveState;
|
|
}
|
|
|
|
bool timeTravel = config.options.emulator.timeTravel;
|
|
if (ImGui::MenuItem("Time travel", Key(config.hotkeys["rewind_state"]).getButton().c_str(), &timeTravel)) {
|
|
config.options.emulator.timeTravel = timeTravel;
|
|
}
|
|
|
|
ImGui::EndMenu();
|
|
}
|
|
if (ImGui::BeginMenu("Help")) {
|
|
ImGui::MenuItem("About", nullptr, &aboutHelp.aboutWindowOpen);
|
|
ImGui::EndMenu();
|
|
}
|
|
|
|
std::string info;
|
|
if (statusMouseLocked) {
|
|
info += " | Press Alt to unlock mouse";
|
|
}
|
|
if (sys->state == System::State::pause) {
|
|
info += " | Paused";
|
|
} else {
|
|
info += fmt::format(" | {:.0f} FPS", statusFps);
|
|
if (!statusFramelimitter) {
|
|
info += " (Unlimited)";
|
|
}
|
|
}
|
|
auto size = ImGui::CalcTextSize(info.c_str());
|
|
ImGui::SameLine(ImGui::GetWindowWidth() - size.x - ImGui::GetStyle().FramePadding.x * 4);
|
|
ImGui::TextUnformatted(info.c_str());
|
|
|
|
if (ImGui::IsItemHovered()) {
|
|
ImGui::BeginTooltip();
|
|
ImGui::TextUnformatted(fmt::format("Frame time: {:.2f} ms\nTab to disable frame limiting", (1000.0 / statusFps)).c_str());
|
|
ImGui::EndTooltip();
|
|
}
|
|
ImGui::EndMainMenuBar();
|
|
}
|
|
|
|
void GUI::render(std::unique_ptr<System>& sys) {
|
|
ImGui_ImplOpenGL3_NewFrame();
|
|
ImGui_ImplSDL2_NewFrame(window);
|
|
ImGui::NewFrame();
|
|
|
|
if (showGui) {
|
|
if (showMenu) mainMenu(sys);
|
|
|
|
// File
|
|
openFile.displayWindows();
|
|
|
|
// Debug
|
|
if (showKernelWindow) kernelWindow(sys.get());
|
|
|
|
cdromDebug.displayWindows(sys.get());
|
|
cpuDebug.displayWindows(sys.get());
|
|
gpuDebug.displayWindows(sys.get());
|
|
timersDebug.displayWindows(sys.get());
|
|
gteDebug.displayWindows(sys.get());
|
|
spuDebug.displayWindows(sys.get());
|
|
ioDebug.displayWindows(sys.get());
|
|
|
|
// Options
|
|
if (showGraphicsOptionsWindow) graphicsOptionsWindow();
|
|
if (showControllerSetupWindow) controllerSetupWindow();
|
|
if (showHotkeysSetupWindow) hotkeysSetupWindow();
|
|
|
|
biosOptions.displayWindows();
|
|
memoryCardOptions.displayWindows(sys.get());
|
|
systemOptions.displayWindows();
|
|
|
|
// Help
|
|
aboutHelp.displayWindows();
|
|
}
|
|
|
|
toasts.display();
|
|
|
|
if (!config.isEmulatorConfigured() && !notInitializedWindowShown) {
|
|
notInitializedWindowShown = true;
|
|
ImGui::OpenPopup("Avocado");
|
|
} else if (droppedItem) {
|
|
if (droppedItemDialog == DroppedItemDialog::None) {
|
|
if (memory_card::isMemoryCardImage(*droppedItem)) {
|
|
droppedItemDialog = DroppedItemDialog::MemoryCard;
|
|
ImGui::OpenPopup("Memory card##select_file");
|
|
} else if (disc::isDiscImage(*droppedItem)) {
|
|
droppedItemDialog = DroppedItemDialog::Disc;
|
|
ImGui::OpenPopup("Disc##select_file");
|
|
}
|
|
}
|
|
} else {
|
|
drawControls(sys);
|
|
}
|
|
|
|
if (ImGui::BeginPopupModal("Avocado", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
|
ImGui::Text("Avocado needs to be set up before running.");
|
|
ImGui::Text("You need one of BIOS files placed in data/bios directory.");
|
|
|
|
if (ImGui::Button("Select BIOS file")) {
|
|
notInitializedWindowShown = true;
|
|
biosOptions.biosWindowOpen = true;
|
|
ImGui::CloseCurrentPopup();
|
|
}
|
|
|
|
ImGui::EndPopup();
|
|
}
|
|
|
|
memoryCardDialog();
|
|
discDialog();
|
|
|
|
// Work in progress
|
|
// renderController();
|
|
|
|
ImGui::Render();
|
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
|
}
|
|
|
|
void GUI::memoryCardDialog() {
|
|
if (!ImGui::BeginPopupModal("Memory card##select_file", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize)) {
|
|
return;
|
|
}
|
|
|
|
ImGui::Text("Select card slot for %s", getFilenameExt(*droppedItem).c_str());
|
|
for (int slot = 0; slot < 2; slot++) {
|
|
if (ImGui::Button(fmt::format("Slot {}", slot + 1).c_str())) {
|
|
config.memoryCard[slot].path = *droppedItem;
|
|
bus.notify(Event::Controller::MemoryCardSwapped{slot});
|
|
ImGui::CloseCurrentPopup();
|
|
}
|
|
ImGui::SameLine();
|
|
}
|
|
|
|
if (ImGui::Button("Cancel")) {
|
|
ImGui::CloseCurrentPopup();
|
|
}
|
|
ImGui::EndPopup();
|
|
|
|
if (!ImGui::IsPopupOpen("Memory card##select_file")) {
|
|
droppedItem = {};
|
|
droppedItemDialog = DroppedItemDialog::None;
|
|
}
|
|
}
|
|
void GUI::discDialog() {
|
|
if (!ImGui::BeginPopupModal("Disc##select_file", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize)) {
|
|
return;
|
|
}
|
|
|
|
ImGui::Text("%s", getFilenameExt(*droppedItem).c_str());
|
|
if (ImGui::Button("Boot")) {
|
|
bus.notify(Event::File::Load{*droppedItem, Event::File::Load::Action::slowboot});
|
|
ImGui::CloseCurrentPopup();
|
|
}
|
|
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Restart console and boot the CD");
|
|
|
|
ImGui::SameLine();
|
|
if (ImGui::Button("Fast boot")) {
|
|
bus.notify(Event::File::Load{*droppedItem, Event::File::Load::Action::fastboot});
|
|
ImGui::CloseCurrentPopup();
|
|
}
|
|
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Restart console and boot the CD (skipping BIOS intro)");
|
|
|
|
ImGui::SameLine();
|
|
if (ImGui::Button("Swap disc")) {
|
|
bus.notify(Event::File::Load{*droppedItem, Event::File::Load::Action::swap});
|
|
ImGui::CloseCurrentPopup();
|
|
}
|
|
if (ImGui::IsItemHovered()) ImGui::SetTooltip("Swap currently inserted disc");
|
|
ImGui::SameLine();
|
|
|
|
if (ImGui::Button("Cancel")) {
|
|
ImGui::CloseCurrentPopup();
|
|
}
|
|
ImGui::EndPopup();
|
|
|
|
if (!ImGui::IsPopupOpen("Disc##select_file")) {
|
|
droppedItem = {};
|
|
droppedItemDialog = DroppedItemDialog::None;
|
|
}
|
|
}
|
|
|
|
void GUI::drawControls(std::unique_ptr<System>& sys) {
|
|
auto symbolButton = [](const char* hint, const char* symbol, ImVec4 bg = ImVec4(1, 1, 1, 0.08f)) -> bool {
|
|
auto padding = ImGui::GetStyle().FramePadding;
|
|
padding.x *= 3.f;
|
|
padding.y *= 2.5f;
|
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, padding);
|
|
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[2]);
|
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(bg.x, bg.y, bg.z, bg.w));
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(bg.x, bg.y, bg.z, 0.5));
|
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(bg.x, bg.y, bg.z, 0.75));
|
|
|
|
bool clicked = ImGui::Button(symbol);
|
|
|
|
ImGui::PopStyleColor(3);
|
|
ImGui::PopFont();
|
|
ImGui::PopStyleVar();
|
|
|
|
if (ImGui::IsItemHovered()) {
|
|
ImGui::SetTooltip("%s", hint);
|
|
}
|
|
|
|
return clicked;
|
|
};
|
|
auto io = ImGui::GetIO();
|
|
|
|
static auto lastTime = std::chrono::steady_clock::now();
|
|
// Reset timer if mouse was moved
|
|
if (io.MouseDelta.x != 0 || io.MouseDelta.y != 0) {
|
|
lastTime = std::chrono::steady_clock::now();
|
|
}
|
|
|
|
auto now = std::chrono::steady_clock::now();
|
|
float timeDiff = std::chrono::duration_cast<std::chrono::milliseconds>(now - lastTime).count() / 1000.f;
|
|
|
|
const float visibleFor = 1.5f; // Seconds
|
|
const float fadeoutDuration = 0.5f; // Seconds
|
|
|
|
// Display for 1.5 seconds, then fade out 0.5 second, then hide
|
|
float alpha;
|
|
if (timeDiff < visibleFor) {
|
|
alpha = 1.f;
|
|
} else if (timeDiff < visibleFor + fadeoutDuration) {
|
|
alpha = lerp(1.f, 0.f, (timeDiff - visibleFor) / fadeoutDuration);
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
// TODO: Handle gamepad "home" button
|
|
|
|
auto displaySize = io.DisplaySize;
|
|
auto pos = ImVec2(displaySize.x / 2.f, displaySize.y * 0.9f);
|
|
ImGui::SetNextWindowPos(pos, 0, ImVec2(.5f, .5f));
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha);
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.f);
|
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 8.f);
|
|
ImGui::Begin("##controls", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize);
|
|
|
|
ImVec4 pauseColor = ImVec4(1, 0, 0, 0.25f);
|
|
if (sys->state == System::State::run) {
|
|
if (symbolButton("Pause emulation", ICON_FA_PAUSE, pauseColor)) {
|
|
sys->state = System::State::pause;
|
|
}
|
|
} else {
|
|
if (symbolButton("Resume emulation", ICON_FA_PLAY, pauseColor)) {
|
|
sys->state = System::State::run;
|
|
}
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
|
|
symbolButton("Save/Load", ICON_FA_SAVE);
|
|
if (ImGui::BeginPopupContextItem(nullptr, 0)) {
|
|
if (fs::exists(state::getStatePath(sys.get()))) {
|
|
if (ImGui::Selectable("Quick load")) bus.notify(Event::System::LoadState{});
|
|
ImGui::Separator();
|
|
}
|
|
if (ImGui::Selectable("Quick save")) bus.notify(Event::System::SaveState{});
|
|
ImGui::EndPopup();
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
|
|
std::string game{};
|
|
|
|
auto cdPath = sys->cdrom->disc->getFile();
|
|
if (!cdPath.empty()) {
|
|
game = getFilename(cdPath);
|
|
}
|
|
if (!game.empty()) {
|
|
ImGui::TextUnformatted(game.c_str());
|
|
} else {
|
|
if (symbolButton("Open", ICON_FA_COMPACT_DISC, ImVec4(0.25f, 0.5f, 1, 0.4f))) {
|
|
openFile.openWindowOpen = true;
|
|
}
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
|
|
symbolButton("Settings", ICON_FA_COG);
|
|
if (ImGui::BeginPopupContextItem(nullptr, 0)) {
|
|
if (ImGui::Selectable("Controller")) showControllerSetupWindow = !showControllerSetupWindow;
|
|
ImGui::Separator();
|
|
ImGui::MenuItem("Show menu", Key(config.hotkeys["toggle_menu"]).getButton().c_str(), &showMenu);
|
|
ImGui::EndPopup();
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
|
|
std::string hint = "Toggle fullscreen (" + (std::string)Key(config.hotkeys["toggle_fullscreen"]).getButton().c_str() + ")";
|
|
if (symbolButton(hint.c_str(), ICON_FA_COMPRESS)) {
|
|
bus.notify(Event::Gui::ToggleFullscreen{});
|
|
}
|
|
|
|
ImGui::End();
|
|
ImGui::PopStyleVar(3);
|
|
}
|
|
|
|
void GUI::renderController() {
|
|
ImDrawList* drawList = ImGui::GetBackgroundDrawList();
|
|
float size = 64.f;
|
|
auto button = [drawList, size](const char* button, float _x, float _y) {
|
|
auto btn = getImage(button, avocado::assetsPath("buttons/"));
|
|
if (!btn) return;
|
|
// AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min = ImVec2(0, 0), const
|
|
// ImVec2& uv_max = ImVec2(1, 1), ImU32 col = IM_COL32_WHITE);
|
|
float x = ImGui::GetIO().DisplaySize.x * _x;
|
|
float y = ImGui::GetIO().DisplaySize.y * lerp(0.3f, 0.6f, _y);
|
|
float r = size / 2 * 1.2;
|
|
|
|
drawList->AddCircleFilled(ImVec2(x, y), r, ImColor(0, 0, 0, 128));
|
|
drawList->AddImage((ImTextureID)btn->id, ImVec2(x - size / 2, y - size / 2), ImVec2(x + size / 2, y + size / 2), ImVec2(0, 0),
|
|
ImVec2(1, 1), ImColor(0xff, 0xff, 0xff, 192));
|
|
};
|
|
|
|
float COL = 1.f / 12.f;
|
|
float ROW = 1.f / 3.f;
|
|
|
|
button("dpad_up", 2 * COL, 1 * ROW);
|
|
button("dpad_left", 1 * COL, 2 * ROW);
|
|
button("dpad_right", 3 * COL, 2 * ROW);
|
|
button("dpad_down", 2 * COL, 3 * ROW);
|
|
|
|
button("select", 5 * COL, 3 * ROW);
|
|
button("start", 7 * COL, 3 * ROW);
|
|
|
|
button("triangle", 1 - 2 * COL, 1 * ROW);
|
|
button("square", 1 - 1 * COL, 2 * ROW);
|
|
button("circle", 1 - 3 * COL, 2 * ROW);
|
|
button("cross", 1 - 2 * COL, 3 * ROW);
|
|
}
|