/*
 * Gearcoleco - ColecoVision Emulator
 * Copyright (C) 2021  Ignacio Sanchez

 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses/
 *
 */

#define GUI_MENUS_IMPORT
#include "gui_menus.h"
#include "gui.h"
#include "gui_filedialogs.h"
#include "gui_popups.h"
#include "gui_actions.h"
#include "gui_debug_disassembler.h"
#include "gui_debug_memory.h"
#include "config.h"
#include "application.h"
#include "display.h"
#include "gamepad.h"
#include "emu.h"
#include "rewind.h"
#include "ogl_renderer.h"
#include "ogl_shader_chain.h"
#include "shader_preset.h"
#include "utils.h"
#include "gearcoleco.h"

static bool open_rom = false;
static bool open_ram = false;
static bool save_ram = false;
static bool open_state = false;
static bool save_state = false;
static bool open_about = false;
static bool open_load_defaults = false;
static bool save_screenshot = false;
static bool save_vgm = false;
static bool choose_savestates_path = false;
static bool choose_screenshots_path = false;
static bool choose_backup_ram_path = false;
static bool open_bios = false;
static bool open_bios_warning = false;
static bool save_debug_settings = false;
static bool load_debug_settings = false;
static ShaderPresetInfo shader_presets[SHADER_PRESET_MAX_DISCOVERED];
static int shader_preset_count = 0;

static void menu_gearcoleco(void);
static void menu_emulator(void);
static void menu_video(void);
static void menu_shader(void);
static void draw_shader_parameters(void);
static bool shader_parameter_is_toggle(const ShaderPresetParameter* parameter);
static bool shader_parameter_is_integer(const ShaderPresetParameter* parameter);
static int shader_parameter_round_to_int(float value);
static void menu_input(void);
static void menu_audio(void);
static void menu_debug(void);
static void menu_about(void);
static void draw_background_color_menu(const char* label, int theme);
static void draw_mcp_status(void);
static void file_dialogs(void);
static void keyboard_configuration_item(const char* text, SDL_Scancode* key, int player);
static void gamepad_configuration_item(const char* text, int* button, int player);
static void hotkey_configuration_item(const char* text, config_Hotkey* hotkey);
static void gamepad_device_selector(int player);
static void draw_savestate_slot_info(int slot);

void gui_init_menus(void)
{
    gui_shortcut_open_rom = false;
    shader_preset_count = shader_preset_scan_bundled(shader_presets, SHADER_PRESET_MAX_DISCOVERED);
}

void gui_main_menu(void)
{
    open_rom = false;
    open_ram = false;
    save_ram = false;
    open_state = false;
    save_state = false;
    open_about = false;
    open_load_defaults = false;
    save_screenshot = false;
    save_vgm = false;
    choose_savestates_path = false;
    choose_screenshots_path = false;
    gui_main_menu_hovered = false;
    choose_backup_ram_path = false;
    open_bios = false;
    open_bios_warning = false;
    save_debug_settings = false;
    load_debug_settings = false;

    if (application_show_menu && ImGui::BeginMainMenuBar())
    {
        gui_main_menu_hovered = ImGui::IsWindowHovered();

        menu_gearcoleco();
        menu_emulator();
        menu_video();
        menu_input();
        menu_audio();
        menu_debug();
        menu_about();
        draw_mcp_status();

        gui_main_menu_height = (int)ImGui::GetWindowSize().y;

        ImGui::EndMainMenuBar();
    }

    file_dialogs();
}

static void menu_gearcoleco(void)
{
    if (ImGui::BeginMenu(GEARCOLECO_TITLE))
    {
        gui_in_use = true;
        bool media_actions_enabled = !emu_is_empty();

        if (ImGui::MenuItem("Open ROM...", config_hotkeys[config_HotkeyIndex_OpenROM].str))
        {
            if (emu_is_bios_loaded())
                open_rom = true;
            else
                open_bios_warning = true;
        }

        if (ImGui::BeginMenu("Open Recent"))
        {
            for (int i = 0; i < config_max_recent_roms; i++)
            {
                if (config_emulator.recent_roms[i].length() > 0)
                {
                    const char* shortcut = (i == 0) ? config_hotkeys[config_HotkeyIndex_ReloadROM].str : NULL;
                    if (ImGui::MenuItem(config_emulator.recent_roms[i].c_str(), shortcut))
                    {
                        if (emu_is_bios_loaded())
                        {
                            char rom_path[4096];
                            strncpy_fit(rom_path, config_emulator.recent_roms[i].c_str(), sizeof(rom_path));
                            gui_load_rom(rom_path);
                        }
                        else
                            open_bios_warning = true;
                    }
                }
            }

            ImGui::EndMenu();
        }

        ImGui::Separator();
        
        if (ImGui::MenuItem("Reset", config_hotkeys[config_HotkeyIndex_Reset].str, false, media_actions_enabled))
        {
            gui_action_reset();
        }

        if (ImGui::MenuItem("Pause", config_hotkeys[config_HotkeyIndex_Pause].str, &config_emulator.paused, media_actions_enabled))
        {
            gui_action_pause();
        }

        ImGui::Separator();

        if (ImGui::MenuItem("Fast Forward", config_hotkeys[config_HotkeyIndex_FFWD].str, &config_emulator.ffwd, media_actions_enabled))
        {
            gui_action_ffwd();
        }

        if (ImGui::BeginMenu("Fast Forward Speed"))
        {
            ImGui::PushItemWidth(100.0f);
            ImGui::Combo("##fwd", &config_emulator.ffwd_speed, "X 1.5\0X 2\0X 2.5\0X 3\0Unlimited\0\0");
            ImGui::PopItemWidth();
            ImGui::EndMenu();
        }

        if (ImGui::BeginMenu("Rewind"))
        {
            if (ImGui::MenuItem("Enabled", config_hotkeys[config_HotkeyIndex_Rewind].str, &config_rewind.enabled))
                rewind_reset();

            ImGui::PushItemWidth(140.0f);
            ImGui::SliderFloat("Speed", &config_rewind.speed, 1.0f, 8.0f, "%.0fx");
            ImGui::PopItemWidth();

            ImGui::EndMenu();
        }

        if (ImGui::BeginMenu("Run-Ahead"))
        {
            ImGui::PushItemWidth(140.0f);
            ImGui::Combo("##runahead", &config_emulator.runahead, "Disabled\0" "1 Frame\0" "2 Frames\0" "3 Frames\0\0");
            ImGui::PopItemWidth();

            if (ImGui::IsItemHovered())
            {
                ImGui::BeginTooltip();
                ImGui::Text("Reduces input lag by speculatively running extra frames each update.");
                ImGui::Text("Every frame multiplies CPU cost, so use the lowest value that feels right.");
                ImGui::Text("Ignored while fast-forwarding.");
                ImGui::EndTooltip();
            }

            ImGui::EndMenu();
        }

        ImGui::Separator();

        bool has_save_data = media_actions_enabled && emu_get_core()->GetMemory()->GetMapper() && emu_get_core()->GetMemory()->GetMapper()->GetSaveDataSize() > 0;

        if (ImGui::MenuItem("Save RAM As...", NULL, false, has_save_data))
        {
            save_ram = true;
        }

        if (ImGui::MenuItem("Load RAM From...", NULL, false, has_save_data))
        {
            open_ram = true;
        }

        ImGui::Separator();

        if (ImGui::MenuItem("Save State As...", "", false, media_actions_enabled))
        {
            save_state = true;
        }

        if (ImGui::MenuItem("Load State From...", "", false, media_actions_enabled))
        {
            open_state = true;
        }

        ImGui::Separator();

        if (ImGui::BeginMenu("Save State Slot"))
        {
            ImGui::PushItemWidth(100.0f);
            ImGui::Combo("##slot", &config_emulator.save_slot, "Slot 1\0Slot 2\0Slot 3\0Slot 4\0Slot 5\0\0");
            ImGui::PopItemWidth();

            ImGui::Separator();
            draw_savestate_slot_info(config_emulator.save_slot);

            ImGui::EndMenu();
        }

        if (ImGui::MenuItem("Save State", config_hotkeys[config_HotkeyIndex_SaveState].str, false, media_actions_enabled))
        {
            std::string message("Saving state to slot ");
            message += std::to_string(config_emulator.save_slot + 1);
            gui_set_status_message(message.c_str(), 3000);
            emu_save_state_slot(config_emulator.save_slot + 1);
        }

        if (ImGui::MenuItem("Load State", config_hotkeys[config_HotkeyIndex_LoadState].str, false, media_actions_enabled))
        {
            std::string message("Loading state from slot ");
            message += std::to_string(config_emulator.save_slot + 1);
            gui_set_status_message(message.c_str(), 3000);
            emu_load_state_slot(config_emulator.save_slot + 1);
        }
        if (ImGui::IsItemHovered())
        {
            ImGui::BeginTooltip();
            ImGui::Text("Slot: %d", config_emulator.save_slot + 1);
            ImGui::Separator();
            draw_savestate_slot_info(config_emulator.save_slot);
            ImGui::EndTooltip();
        }

        ImGui::Separator();

        if (ImGui::MenuItem("Save Screenshot As...", "", false, media_actions_enabled))
        {
            save_screenshot = true;
        }

        if (ImGui::MenuItem("Save Screenshot", config_hotkeys[config_HotkeyIndex_Screenshot].str, false, media_actions_enabled))
        {
            gui_action_save_screenshot(NULL);
        }

        ImGui::Separator();

        if (ImGui::MenuItem("Load Default Settings"))
        {
            open_load_defaults = true;
        }

        ImGui::Separator();

        if (ImGui::MenuItem("Quit", config_hotkeys[config_HotkeyIndex_Quit].str))
        {
            application_trigger_quit();
        }

        ImGui::EndMenu();
    }
}

static void menu_emulator(void)
{
    if (ImGui::BeginMenu("Emulator"))
    {
        gui_in_use = true;

        if (ImGui::BeginMenu("Save States Dir"))
        {
            ImGui::PushItemWidth(220.0f);
            if (ImGui::Combo("##savestate_option", &config_emulator.savestates_dir_option, "Default Location\0Same as ROM\0Custom Location\0\0"))
            {
                update_savestates_data();
            }

            switch ((Directory_Location)config_emulator.savestates_dir_option)
            {
                case Directory_Location_Default:
                {
                    ImGui::Text("%s", config_root_path);
                    break;
                }
                case Directory_Location_ROM:
                {
                    if (!emu_is_empty())
                        ImGui::Text("%s", emu_get_core()->GetCartridge()->GetFileDirectory());
                    break;
                }
                case Directory_Location_Custom:
                {
                    if (ImGui::MenuItem("Choose..."))
                    {
                        choose_savestates_path = true;
                    }

                    ImGui::PushItemWidth(450);
                    if (ImGui::InputText("##savestate_path", gui_savestates_path, IM_ARRAYSIZE(gui_savestates_path), ImGuiInputTextFlags_AutoSelectAll))
                    {
                        config_emulator.savestates_path.assign(gui_savestates_path);
                        update_savestates_data();
                    }
                    ImGui::PopItemWidth();
                    break;
                }
            }

            ImGui::EndMenu();
        }

        if (ImGui::BeginMenu("Save Files Dir"))
        {
            ImGui::PushItemWidth(220.0f);
            ImGui::Combo("##savefiles_option", &config_emulator.savefiles_dir_option, "Default Location\0Same as ROM\0Custom Location\0\0");

            switch ((Directory_Location)config_emulator.savefiles_dir_option)
            {
                case Directory_Location_Default:
                {
                    ImGui::Text("%s", config_root_path);
                    break;
                }
                case Directory_Location_ROM:
                {
                    if (!emu_is_empty())
                        ImGui::Text("%s", emu_get_core()->GetCartridge()->GetFileDirectory());
                    break;
                }
                case Directory_Location_Custom:
                {
                    if (ImGui::MenuItem("Choose..."))
                    {
                        choose_backup_ram_path = true;
                    }

                    ImGui::PushItemWidth(450);
                    if (ImGui::InputText("##savefiles_path", gui_savefiles_path, IM_ARRAYSIZE(gui_savefiles_path), ImGuiInputTextFlags_AutoSelectAll))
                    {
                        config_emulator.savefiles_path.assign(gui_savefiles_path);
                    }
                    ImGui::PopItemWidth();
                    break;
                }
            }

            ImGui::EndMenu();
        }

        if (ImGui::BeginMenu("Screenshots Dir"))
        {
            ImGui::PushItemWidth(220.0f);
            ImGui::Combo("##screenshots_option", &config_emulator.screenshots_dir_option, "Default Location\0Same as ROM\0Custom Location\0\0");

            switch ((Directory_Location)config_emulator.screenshots_dir_option)
            {
                case Directory_Location_Default:
                {
                    ImGui::Text("%s", config_root_path);
                    break;
                }
                case Directory_Location_ROM:
                {
                    if (!emu_is_empty())
                        ImGui::Text("%s", emu_get_core()->GetCartridge()->GetFileDirectory());
                    break;
                }
                case Directory_Location_Custom:
                {
                    if (ImGui::MenuItem("Choose..."))
                    {
                        choose_screenshots_path = true;
                    }

                    ImGui::PushItemWidth(450);
                    if (ImGui::InputText("##screenshots_path", gui_screenshots_path, IM_ARRAYSIZE(gui_screenshots_path), ImGuiInputTextFlags_AutoSelectAll))
                    {
                        config_emulator.screenshots_path.assign(gui_screenshots_path);
                    }
                    ImGui::PopItemWidth();
                    break;
                }
            }

            ImGui::EndMenu();
        }

        ImGui::Separator();

        if (ImGui::BeginMenu("BIOS"))
        {
            if (ImGui::MenuItem("Load BIOS..."))
            {
                open_bios = true;
            }
            ImGui::PushItemWidth(350);
            if (ImGui::InputText("##bios_path", gui_bios_path, IM_ARRAYSIZE(gui_bios_path), ImGuiInputTextFlags_AutoSelectAll))
            {
                config_emulator.bios_path.assign(gui_bios_path);
                emu_load_bios(gui_bios_path);
            }
            ImGui::PopItemWidth();

            ImGui::Separator();
            if (strlen(gui_bios_path) > 0)
            {
                ImGui::TextColored(ImVec4(0.10f, 0.90f, 0.10f, 1.0f), "BIOS loaded");
            }
            else
            {
                ImGui::TextColored(ImVec4(0.50f, 0.50f, 0.50f, 1.0f), "No BIOS loaded");
            }

            ImGui::EndMenu();
        }

        ImGui::Separator();

        if (ImGui::BeginMenu("Refresh Rate"))
        {
            ImGui::PushItemWidth(130.0f);
            if (ImGui::Combo("##emu_rate", &config_emulator.region, "Auto\0NTSC (60 Hz)\0PAL (50 Hz)\0\0"))
            {
                if (config_emulator.region > 0)
                {
                    config_emulator.ffwd = false;
                    config_audio.sync = true;
                }
            }
            ImGui::PopItemWidth();
            ImGui::EndMenu();
        }

        ImGui::Separator();

        ImGui::MenuItem("Show ROM info", "", &config_emulator.show_info);
        ImGui::MenuItem("Status Messages", "", &config_emulator.status_messages);

        ImGui::Separator();

        ImGui::MenuItem("Start Paused", "", &config_emulator.start_paused);
        ImGui::MenuItem("Pause When Inactive", "", &config_emulator.pause_when_inactive);

        ImGui::Separator();

        if (ImGui::BeginMenu("Hotkeys"))
        {
            hotkey_configuration_item("Open ROM:", &config_hotkeys[config_HotkeyIndex_OpenROM]);
            hotkey_configuration_item("Quit:", &config_hotkeys[config_HotkeyIndex_Quit]);
            hotkey_configuration_item("Reset:", &config_hotkeys[config_HotkeyIndex_Reset]);
            hotkey_configuration_item("Reload ROM:", &config_hotkeys[config_HotkeyIndex_ReloadROM]);
            hotkey_configuration_item("Pause:", &config_hotkeys[config_HotkeyIndex_Pause]);
            hotkey_configuration_item("Fast Forward:", &config_hotkeys[config_HotkeyIndex_FFWD]);
            hotkey_configuration_item("Rewind:", &config_hotkeys[config_HotkeyIndex_Rewind]);
            hotkey_configuration_item("Save State:", &config_hotkeys[config_HotkeyIndex_SaveState]);
            hotkey_configuration_item("Load State:", &config_hotkeys[config_HotkeyIndex_LoadState]);
            hotkey_configuration_item("Save State Slot 1:", &config_hotkeys[config_HotkeyIndex_SelectSlot1]);
            hotkey_configuration_item("Save State Slot 2:", &config_hotkeys[config_HotkeyIndex_SelectSlot2]);
            hotkey_configuration_item("Save State Slot 3:", &config_hotkeys[config_HotkeyIndex_SelectSlot3]);
            hotkey_configuration_item("Save State Slot 4:", &config_hotkeys[config_HotkeyIndex_SelectSlot4]);
            hotkey_configuration_item("Save State Slot 5:", &config_hotkeys[config_HotkeyIndex_SelectSlot5]);
            hotkey_configuration_item("Screenshot:", &config_hotkeys[config_HotkeyIndex_Screenshot]);
            hotkey_configuration_item("Mute Audio:", &config_hotkeys[config_HotkeyIndex_Mute]);
            hotkey_configuration_item("Fullscreen:", &config_hotkeys[config_HotkeyIndex_Fullscreen]);
            hotkey_configuration_item("Capture Mouse:", &config_hotkeys[config_HotkeyIndex_CaptureMouse]);
            hotkey_configuration_item("Show Main Menu:", &config_hotkeys[config_HotkeyIndex_ShowMainMenu]);

            gui_popup_modal_hotkey();

            ImGui::EndMenu();
        }

        if (ImGui::BeginMenu("Debug Hotkeys"))
        {
            hotkey_configuration_item("Step Into:", &config_hotkeys[config_HotkeyIndex_DebugStepInto]);
            hotkey_configuration_item("Step Over:", &config_hotkeys[config_HotkeyIndex_DebugStepOver]);
            hotkey_configuration_item("Step Out:", &config_hotkeys[config_HotkeyIndex_DebugStepOut]);
            hotkey_configuration_item("Step Frame:", &config_hotkeys[config_HotkeyIndex_DebugStepFrame]);
            hotkey_configuration_item("Continue:", &config_hotkeys[config_HotkeyIndex_DebugContinue]);
            hotkey_configuration_item("Break:", &config_hotkeys[config_HotkeyIndex_DebugBreak]);
            hotkey_configuration_item("Run to Cursor:", &config_hotkeys[config_HotkeyIndex_DebugRunToCursor]);
            hotkey_configuration_item("Toggle Breakpoint:", &config_hotkeys[config_HotkeyIndex_DebugBreakpoint]);
            hotkey_configuration_item("Go Back:", &config_hotkeys[config_HotkeyIndex_DebugGoBack]);

            gui_popup_modal_hotkey();

            ImGui::EndMenu();
        }

        ImGui::Separator();

        ImGui::MenuItem("Single Instance", "", &config_debug.single_instance);
        if (ImGui::IsItemHovered())
        {
            ImGui::BeginTooltip();
            ImGui::Text("RESTART REQUIRED");
            ImGui::NewLine();
            ImGui::Text("When enabled, opening a ROM while another instance is running");
            ImGui::Text("will send the ROM to the running instance instead of");
            ImGui::Text("starting a new one.");
            ImGui::EndTooltip();
        }

        ImGui::EndMenu();
    }
}

static void menu_video(void)
{
    if (ImGui::BeginMenu("Video"))
    {
        gui_in_use = true;

        if (ImGui::MenuItem("Full Screen", config_hotkeys[config_HotkeyIndex_Fullscreen].str, &config_emulator.fullscreen))
        {
            application_trigger_fullscreen(config_emulator.fullscreen);
        }

#if !defined(__APPLE__)
        if (ImGui::BeginMenu("Fullscreen Mode"))
        {
            ImGui::PushItemWidth(130.0f);
            ImGui::Combo("##fullscreen_mode", &config_emulator.fullscreen_mode, "Borderless\0Exclusive\0\0");
            ImGui::PopItemWidth();
            ImGui::EndMenu();
        }
#endif

        ImGui::Separator();

        ImGui::MenuItem("Always Show Menu", config_hotkeys[config_HotkeyIndex_ShowMainMenu].str, &config_emulator.always_show_menu);
        if (ImGui::IsItemHovered())
        {
            ImGui::BeginTooltip();
            ImGui::Text("This option will enable menu even in fullscreen.");
            ImGui::Text("Menu always shows in debug mode.");
            ImGui::EndTooltip();
        }

        if (ImGui::MenuItem("Resize Window to Content"))
        {
            if (!config_debug.debug)
            {
                application_trigger_fit_to_content(gui_main_window_width, gui_main_window_height + gui_main_menu_height);
            }
        }

        ImGui::Separator();

        if (ImGui::BeginMenu("Scale"))
        {
            ImGui::PushItemWidth(250.0f);
            ImGui::Combo("##scale", &config_video.scale, "Integer Scale (Auto)\0Integer Scale (Manual)\0Scale to Window Height\0Scale to Window Width & Height\0\0");
            if (config_video.scale == 1)
                ImGui::SliderInt("##scale_manual", &config_video.scale_manual, 1, 10);
            ImGui::PopItemWidth();
            ImGui::EndMenu();
        }

        if (ImGui::BeginMenu("Aspect Ratio"))
        {
            ImGui::PushItemWidth(200.0f);
            ImGui::Combo("##ratio", &config_video.ratio, "Square Pixels (1:1 PAR)\0Standard (4:3 DAR)\0Wide (16:9 DAR)\0Wide (16:10 DAR)\0\0");
            ImGui::PopItemWidth();
            ImGui::EndMenu();
        }

        if (ImGui::BeginMenu("Overscan"))
        {
            ImGui::PushItemWidth(150.0f);
            if (ImGui::Combo("##overscan", &config_video.overscan, "Disabled\0Top+Bottom\0Full (284 width)\0Full (320 width)\0\0"))
            {
                emu_set_overscan(config_debug.debug ? 0 : config_video.overscan);
            }
            ImGui::PopItemWidth();
            ImGui::EndMenu();
        }

        ImGui::Separator();

        if (ImGui::BeginMenu("Vertical Sync"))
        {
            ImGui::PushItemWidth(240.0f);
#if defined(_WIN32)
            if (ImGui::Combo("##sync_mode", &config_video.sync_mode, "Disabled\0Fixed (60 Hz, 120 Hz, 240 Hz)\0Variable Refresh Rate (VRR)\0\0"))
#else
            if (ImGui::Combo("##sync_mode", &config_video.sync_mode, "Disabled\0Fixed (60 Hz, 120 Hz, 240 Hz)\0\0"))
#endif
            {
                if (config_video.sync_mode != config_VideoSync_Disabled)
                {
                    config_audio.sync = true;
                    config_emulator.ffwd = false;
                    emu_audio_reset();
                }

                display_use_vsync_if_enabled();
            }
            ImGui::PopItemWidth();

            if (ImGui::IsItemHovered())
            {
                ImGui::BeginTooltip();
                ImGui::Text("Disabled: do not synchronize presentation to the monitor.");
                ImGui::Text("Fixed: use normal VSync for 60 Hz, 120 Hz, and 240 Hz displays.");
#if defined(_WIN32)
                ImGui::Text("VRR: present at the emulator frame rate.");
                ImGui::Text("VRR requires fullscreen, a VRR display, and G-SYNC,");
                ImGui::Text("FreeSync, or Adaptive Sync enabled in your monitor and GPU driver settings.");
#endif
                ImGui::EndTooltip();
            }

            ImGui::EndMenu();
        }

        ImGui::MenuItem("Show FPS", "", &config_video.fps);

        ImGui::Separator();

        menu_shader();

        ImGui::Separator();

        if (ImGui::MenuItem("Disable Sprite Limit", "", &config_video.sprite_limit))
        {
            emu_video_no_sprite_limit(config_video.sprite_limit);
        }

        if (ImGui::BeginMenu("Palette"))
        {
            ImGui::PushItemWidth(130.0f);
            if (ImGui::Combo("##palette", &config_video.palette, "Coleco\0TMS9918\0Custom\0\0", 11))
            {
                gui_update_palette();
            }
            ImGui::PopItemWidth();
            ImGui::EndMenu();
        }

        if (ImGui::BeginMenu("Custom Palette"))
        {
            for (int i = 0; i < 16; i++)
            {
                char text[10] = {0};
                snprintf(text, sizeof(text), "Color #%d", i);
                if (ImGui::ColorEdit3(text, (float*)&gui_custom_palette[i], ImGuiColorEditFlags_NoInputs))
                {
                    gui_update_palette();
                }
            }

            ImGui::EndMenu();
        }

        ImGui::Separator();

        if (ImGui::BeginMenu("Theme"))
        {
            ImGui::PushItemWidth(100.0f);
            if (ImGui::Combo("##theme", &config_emulator.theme, "Light\0Dark\0\0"))
            {
                gui_set_style();
            }
            ImGui::PopItemWidth();
            ImGui::EndMenu();
        }

        if (ImGui::BeginMenu("Background Color"))
        {
            draw_background_color_menu("Dark Theme", config_Theme_Dark);
            draw_background_color_menu("Light Theme", config_Theme_Light);

            ImGui::EndMenu();
        }

        ImGui::EndMenu();
    }
}

static void draw_background_color_menu(const char* label, int theme)
{
    if (ImGui::BeginMenu(label))
    {
        ImGui::PushID(theme);

        ImGui::ColorEdit3("##normal_bg", config_video.background_color[theme], ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_Float);
        ImGui::SameLine();
        ImGui::Text("Normal Background");

        ImGui::Separator();

        if (ImGui::ColorEdit3("##debugger_bg", config_video.background_color_debugger[theme], ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_Float))
        {
            if (config_emulator.theme == theme)
                gui_set_style();
        }
        ImGui::SameLine();
        ImGui::Text("Debugger Background");

        ImGui::PopID();
        ImGui::EndMenu();
    }
}

static void menu_shader(void)
{
    if (!ImGui::BeginMenu("Shader"))
        return;

    bool has_preset = ogl_shader_chain_has_preset();
    int selected_index = 0;

    if (has_preset && config_video.shader_mode == config_ShaderMode_External)
    {
        for (int i = 0; i < shader_preset_count; i++)
        {
            if (shader_preset_config_path_matches(config_video.shader_preset_path.c_str(), shader_presets[i].path))
            {
                selected_index = i + 1;
                break;
            }
        }
    }

    const char* preview = selected_index == 0 ? "Pixel Perfect" : shader_presets[selected_index - 1].name;
    ImGui::PushItemWidth(240.0f);
    if (ImGui::BeginCombo("##ShaderPreset", preview))
    {
        bool selected = selected_index == 0;
        if (ImGui::Selectable("Pixel Perfect", selected))
        {
            if (selected_index != 0)
            {
                ogl_renderer_unload_shader_preset();
                gui_set_status_message("Shader preset: Pixel Perfect", 3000);
            }
        }
        if (selected)
            ImGui::SetItemDefaultFocus();

        for (int i = 0; i < shader_preset_count; i++)
        {
            selected = selected_index == i + 1;
            if (ImGui::Selectable(shader_presets[i].name, selected))
            {
                if (selected_index != i + 1)
                {
                    if (ogl_renderer_load_shader_preset(shader_presets[i].path))
                    {
                        std::string message("Shader preset loaded: ");
                        message += ogl_shader_chain_get_preset_name();
                        gui_set_status_message(message.c_str(), 3000);
                    }
                    else
                    {
                        std::string message("Shader preset failed: ");
                        message += ogl_shader_chain_get_last_error();
                        gui_set_status_message(message.c_str(), 5000);
                    }
                }
            }
            if (selected)
                ImGui::SetItemDefaultFocus();
        }
        ImGui::EndCombo();
    }
    ImGui::PopItemWidth();

    has_preset = ogl_shader_chain_has_preset();

    if (has_preset && ogl_shader_chain_get_parameter_count() > 0)
    {
        if (ImGui::BeginMenu("Parameters"))
        {
            draw_shader_parameters();
            ImGui::EndMenu();
        }
    }
    else if (ogl_shader_chain_get_last_error()[0] != '\0')
    {
        ImGui::Separator();
        ImGui::TextColored(ImVec4(0.98f, 0.15f, 0.45f, 1.0f), "%s", ogl_shader_chain_get_last_error());
    }

    ImGui::EndMenu();
}

static void draw_shader_parameters(void)
{
    int count = ogl_shader_chain_get_parameter_count();
    if (count <= 0)
        return;

    const float parameter_width = 220.0f;

    if (ImGui::Button("Restore Defaults", ImVec2(parameter_width, 0.0f)))
    {
        if (ogl_shader_chain_restore_default_parameters())
        {
            ogl_renderer_save_shader_parameter_config();
            gui_set_status_message("Shader parameters restored", 3000);
        }
    }

    ImGui::PushItemWidth(parameter_width);

    for (int i = 0; i < count; i++)
    {
        const ShaderPresetParameter* parameter = ogl_shader_chain_get_parameter(i);
        if (!parameter)
            continue;

        float value = parameter->value;
        char label[160];
        snprintf(label, sizeof(label), "%s##shader_parameter_%d", parameter->label[0] != '\0' ? parameter->label : parameter->name, i);

        if (shader_parameter_is_toggle(parameter))
        {
            bool enabled = value >= 0.5f;
            if (ImGui::Checkbox(label, &enabled))
            {
                ogl_shader_chain_set_parameter(i, enabled ? 1.0f : 0.0f);
                ogl_renderer_save_shader_parameter_config();
            }
            continue;
        }

        if (shader_parameter_is_integer(parameter))
        {
            int int_value = shader_parameter_round_to_int(value);
            int min_value = shader_parameter_round_to_int(parameter->minimum);
            int max_value = shader_parameter_round_to_int(parameter->maximum);
            if (ImGui::SliderInt(label, &int_value, min_value, max_value))
            {
                ogl_shader_chain_set_parameter(i, (float)int_value);
                ogl_renderer_save_shader_parameter_config();
            }
            continue;
        }

        if (ImGui::SliderFloat(label, &value, parameter->minimum, parameter->maximum, "%.3f"))
        {
            ogl_shader_chain_set_parameter(i, value);
            ogl_renderer_save_shader_parameter_config();
        }
    }

    ImGui::PopItemWidth();
}

static bool shader_parameter_is_toggle(const ShaderPresetParameter* parameter)
{
    return parameter && parameter->minimum == 0.0f && parameter->maximum == 1.0f && parameter->step >= 1.0f;
}

static bool shader_parameter_is_integer(const ShaderPresetParameter* parameter)
{
    return parameter && parameter->step >= 1.0f;
}

static int shader_parameter_round_to_int(float value)
{
    return value >= 0.0f ? (int)(value + 0.5f) : (int)(value - 0.5f);
}

static void menu_input(void)
{
    if (ImGui::BeginMenu("Input"))
    {
        gui_in_use = true;

        if (ImGui::BeginMenu("Keyboard Configuration"))
        {
            if (ImGui::BeginMenu("Player 1"))
            {
                ImGui::TextDisabled("Keyboard Player 1");
                ImGui::Separator();
                keyboard_configuration_item("Left:", &config_input[0].key_left, 0);
                keyboard_configuration_item("Right:", &config_input[0].key_right, 0);
                keyboard_configuration_item("Up:", &config_input[0].key_up, 0);
                keyboard_configuration_item("Down:", &config_input[0].key_down, 0);
                keyboard_configuration_item("Yellow (Left):", &config_input[0].key_left_button, 0);
                keyboard_configuration_item("Red (Right):", &config_input[0].key_right_button, 0);
                keyboard_configuration_item("Purple:", &config_input[0].key_purple, 0);
                keyboard_configuration_item("Blue:", &config_input[0].key_blue, 0);
                keyboard_configuration_item("Keypad 0:", &config_input[0].key_0, 0);
                keyboard_configuration_item("Keypad 1:", &config_input[0].key_1, 0);
                keyboard_configuration_item("Keypad 2:", &config_input[0].key_2, 0);
                keyboard_configuration_item("Keypad 3:", &config_input[0].key_3, 0);
                keyboard_configuration_item("Keypad 4:", &config_input[0].key_4, 0);
                keyboard_configuration_item("Keypad 5:", &config_input[0].key_5, 0);
                keyboard_configuration_item("Keypad 6:", &config_input[0].key_6, 0);
                keyboard_configuration_item("Keypad 7:", &config_input[0].key_7, 0);
                keyboard_configuration_item("Keypad 8:", &config_input[0].key_8, 0);
                keyboard_configuration_item("Keypad 9:", &config_input[0].key_9, 0);
                keyboard_configuration_item("Keypad *:", &config_input[0].key_asterisk, 0);
                keyboard_configuration_item("Keypad #:", &config_input[0].key_hash, 0);

                gui_popup_modal_keyboard();

                ImGui::EndMenu();
            }

            if (ImGui::BeginMenu("Player 2"))
            {
                ImGui::TextDisabled("Keyboard Player 2");
                ImGui::Separator();
                keyboard_configuration_item("Left:", &config_input[1].key_left, 1);
                keyboard_configuration_item("Right:", &config_input[1].key_right, 1);
                keyboard_configuration_item("Up:", &config_input[1].key_up, 1);
                keyboard_configuration_item("Down:", &config_input[1].key_down, 1);
                keyboard_configuration_item("Yellow (Left):", &config_input[1].key_left_button, 1);
                keyboard_configuration_item("Red (Right):", &config_input[1].key_right_button, 1);
                keyboard_configuration_item("Purple:", &config_input[1].key_purple, 1);
                keyboard_configuration_item("Blue:", &config_input[1].key_blue, 1);
                keyboard_configuration_item("Keypad 0:", &config_input[1].key_0, 1);
                keyboard_configuration_item("Keypad 1:", &config_input[1].key_1, 1);
                keyboard_configuration_item("Keypad 2:", &config_input[1].key_2, 1);
                keyboard_configuration_item("Keypad 3:", &config_input[1].key_3, 1);
                keyboard_configuration_item("Keypad 4:", &config_input[1].key_4, 1);
                keyboard_configuration_item("Keypad 5:", &config_input[1].key_5, 1);
                keyboard_configuration_item("Keypad 6:", &config_input[1].key_6, 1);
                keyboard_configuration_item("Keypad 7:", &config_input[1].key_7, 1);
                keyboard_configuration_item("Keypad 8:", &config_input[1].key_8, 1);
                keyboard_configuration_item("Keypad 9:", &config_input[1].key_9, 1);
                keyboard_configuration_item("Keypad *:", &config_input[1].key_asterisk, 1);
                keyboard_configuration_item("Keypad #:", &config_input[1].key_hash, 1);

                gui_popup_modal_keyboard();

                ImGui::EndMenu();
            }

            ImGui::EndMenu();
        }

                    ImGui::Separator();

        if (ImGui::BeginMenu("Gamepads"))
        {
            if (ImGui::BeginMenu("Player 1"))
            {
                ImGui::MenuItem("Enable Gamepad P1", "", &config_input[0].gamepad);

                if (ImGui::BeginMenu("Device"))
                {
                    gamepad_device_selector(0);
                    ImGui::EndMenu();
                }

                if (ImGui::BeginMenu("Directional Controls"))
                {
                    ImGui::PushItemWidth(150.0f);
                    ImGui::Combo("##directional", &config_input[0].gamepad_directional, "D-pad\0Left Analog Stick\0\0");
                    ImGui::PopItemWidth();
                    ImGui::EndMenu();
                }

                if (ImGui::BeginMenu("Button Configuration"))
                {
                    ImGui::TextDisabled("Gamepad Player 1");
                    ImGui::Separator();
                    gamepad_configuration_item("Yellow (Left):", &config_input[0].gamepad_left_button, 0);
                    gamepad_configuration_item("Red (Right):", &config_input[0].gamepad_right_button, 0);
                    gamepad_configuration_item("Purple:", &config_input[0].gamepad_purple, 0);
                    gamepad_configuration_item("Blue:", &config_input[0].gamepad_blue, 0);
                    gamepad_configuration_item("Keypad 0:", &config_input[0].gamepad_0, 0);
                    gamepad_configuration_item("Keypad 1:", &config_input[0].gamepad_1, 0);
                    gamepad_configuration_item("Keypad 2:", &config_input[0].gamepad_2, 0);
                    gamepad_configuration_item("Keypad 3:", &config_input[0].gamepad_3, 0);
                    gamepad_configuration_item("Keypad 4:", &config_input[0].gamepad_4, 0);
                    gamepad_configuration_item("Keypad 5:", &config_input[0].gamepad_5, 0);
                    gamepad_configuration_item("Keypad 6:", &config_input[0].gamepad_6, 0);
                    gamepad_configuration_item("Keypad 7:", &config_input[0].gamepad_7, 0);
                    gamepad_configuration_item("Keypad 8:", &config_input[0].gamepad_8, 0);
                    gamepad_configuration_item("Keypad 9:", &config_input[0].gamepad_9, 0);
                    gamepad_configuration_item("Asterisk:", &config_input[0].gamepad_asterisk, 0);
                    gamepad_configuration_item("Hash:", &config_input[0].gamepad_hash, 0);

                    gui_popup_modal_gamepad(0);

                    ImGui::EndMenu();
                }

                if (ImGui::BeginMenu("Shortcut Configuration"))
                {
                    ImGui::TextDisabled("Gamepad Player 1 - Shortcuts");
                    ImGui::Separator();

                    gamepad_configuration_item("Save State:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_SaveState], 0);
                    gamepad_configuration_item("Load State:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_LoadState], 0);
                    gamepad_configuration_item("Save State Slot 1:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_SelectSlot1], 0);
                    gamepad_configuration_item("Save State Slot 2:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_SelectSlot2], 0);
                    gamepad_configuration_item("Save State Slot 3:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_SelectSlot3], 0);
                    gamepad_configuration_item("Save State Slot 4:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_SelectSlot4], 0);
                    gamepad_configuration_item("Save State Slot 5:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_SelectSlot5], 0);

                    ImGui::Separator();

                    gamepad_configuration_item("Reset:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_Reset], 0);
                    gamepad_configuration_item("Pause:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_Pause], 0);
                    gamepad_configuration_item("Fast Forward:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_FFWD], 0);
                    gamepad_configuration_item("Rewind:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_Rewind], 0);
                    gamepad_configuration_item("Screenshot:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_Screenshot], 0);
                    gamepad_configuration_item("Mute Audio:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_Mute], 0);
                    gamepad_configuration_item("Fullscreen:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_Fullscreen], 0);
                    gamepad_configuration_item("Capture Mouse:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_CaptureMouse], 0);
                    gamepad_configuration_item("Show Main Menu:", &config_input_gamepad_shortcuts[0].gamepad_shortcuts[config_HotkeyIndex_ShowMainMenu], 0);

                    gui_popup_modal_gamepad(0);

                    ImGui::EndMenu();
                }

                ImGui::EndMenu();
            }

            if (ImGui::BeginMenu("Player 2"))
            {
                ImGui::MenuItem("Enable Gamepad P2", "", &config_input[1].gamepad);

                if (ImGui::BeginMenu("Device"))
                {
                    gamepad_device_selector(1);
                    ImGui::EndMenu();
                }

                if (ImGui::BeginMenu("Directional Controls"))
                {
                    ImGui::PushItemWidth(150.0f);
                    ImGui::Combo("##directional", &config_input[1].gamepad_directional, "D-pad\0Left Analog Stick\0\0");
                    ImGui::PopItemWidth();
                    ImGui::EndMenu();
                }

                if (ImGui::BeginMenu("Button Configuration"))
                {
                    ImGui::TextDisabled("Gamepad Player 2");
                    ImGui::Separator();
                    gamepad_configuration_item("Yellow (Left):", &config_input[1].gamepad_left_button, 1);
                    gamepad_configuration_item("Red (Right):", &config_input[1].gamepad_right_button, 1);
                    gamepad_configuration_item("Purple:", &config_input[1].gamepad_purple, 1);
                    gamepad_configuration_item("Blue:", &config_input[1].gamepad_blue, 1);
                    gamepad_configuration_item("Keypad 0:", &config_input[1].gamepad_0, 1);
                    gamepad_configuration_item("Keypad 1:", &config_input[1].gamepad_1, 1);
                    gamepad_configuration_item("Keypad 2:", &config_input[1].gamepad_2, 1);
                    gamepad_configuration_item("Keypad 3:", &config_input[1].gamepad_3, 1);
                    gamepad_configuration_item("Keypad 4:", &config_input[1].gamepad_4, 1);
                    gamepad_configuration_item("Keypad 5:", &config_input[1].gamepad_5, 1);
                    gamepad_configuration_item("Keypad 6:", &config_input[1].gamepad_6, 1);
                    gamepad_configuration_item("Keypad 7:", &config_input[1].gamepad_7, 1);
                    gamepad_configuration_item("Keypad 8:", &config_input[1].gamepad_8, 1);
                    gamepad_configuration_item("Keypad 9:", &config_input[1].gamepad_9, 1);
                    gamepad_configuration_item("Asterisk:", &config_input[1].gamepad_asterisk, 1);
                    gamepad_configuration_item("Hash:", &config_input[1].gamepad_hash, 1);

                    gui_popup_modal_gamepad(1);

                    ImGui::EndMenu();
                }

                if (ImGui::BeginMenu("Shortcut Configuration"))
                {
                    ImGui::TextDisabled("Gamepad Player 2 - Shortcuts");
                    ImGui::Separator();

                    gamepad_configuration_item("Save State:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_SaveState], 1);
                    gamepad_configuration_item("Load State:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_LoadState], 1);
                    gamepad_configuration_item("Save State Slot 1:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_SelectSlot1], 1);
                    gamepad_configuration_item("Save State Slot 2:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_SelectSlot2], 1);
                    gamepad_configuration_item("Save State Slot 3:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_SelectSlot3], 1);
                    gamepad_configuration_item("Save State Slot 4:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_SelectSlot4], 1);
                    gamepad_configuration_item("Save State Slot 5:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_SelectSlot5], 1);

                    ImGui::Separator();

                    gamepad_configuration_item("Reset:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_Reset], 1);
                    gamepad_configuration_item("Pause:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_Pause], 1);
                    gamepad_configuration_item("Fast Forward:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_FFWD], 1);
                    gamepad_configuration_item("Rewind:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_Rewind], 1);
                    gamepad_configuration_item("Screenshot:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_Screenshot], 1);
                    gamepad_configuration_item("Mute Audio:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_Mute], 1);
                    gamepad_configuration_item("Fullscreen:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_Fullscreen], 1);
                    gamepad_configuration_item("Capture Mouse:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_CaptureMouse], 1);
                    gamepad_configuration_item("Show Main Menu:", &config_input_gamepad_shortcuts[1].gamepad_shortcuts[config_HotkeyIndex_ShowMainMenu], 1);

                    gui_popup_modal_gamepad(1);

                    ImGui::EndMenu();
                }

                ImGui::EndMenu();
            }

            ImGui::EndMenu();
        }

        ImGui::Separator();

        if (ImGui::BeginMenu("Spinners"))
        {
            ImGui::MenuItem("Capture Mouse", config_hotkeys[config_HotkeyIndex_CaptureMouse].str, &config_emulator.capture_mouse);
            if (ImGui::IsItemHovered())
            {
                ImGui::SetTooltip("When enabled, the mouse will be captured inside\nthe emulator window to use spinners freely.\nPress %s to release the mouse.", config_hotkeys[config_HotkeyIndex_CaptureMouse].str);
            }

            ImGui::Combo("##spinner", &config_emulator.spinner, "Disabled\0Super Action Controller\0Steering Wheel\0Roller Controller\0\0", 4);
            if (ImGui::IsItemHovered())
            {
                ImGui::SetTooltip("SAC Spinner for P1 is controlled with mouse movement.\nSAC Spinner for P2 is controlled with mouse wheel.\nSteering Wheel is controlled with mouse movement.\nRoller Controller is controlled with mouse movement and mouse buttons.");
            }
            ImGui::SliderInt("##spinner_sensitivity", &config_emulator.spinner_sensitivity, 1, 10, "Sensitivity = %d");

            ImGui::EndMenu();
        }

        ImGui::Separator();

        bool allow_up_down = config_input[0].allow_up_down && config_input[1].allow_up_down;

        if (ImGui::MenuItem("Allow Up+Down / Left+Right", "", &allow_up_down))
        {
            for (int i = 0; i < GC_MAX_GAMEPADS; i++)
                config_input[i].allow_up_down = allow_up_down;
        }
        if (ImGui::IsItemHovered())
        {
            ImGui::BeginTooltip();
            ImGui::Text("Allow pressing, quickly alternating, or holding");
            ImGui::Text("both left and right or up and down directions.");
            ImGui::Text("This may cause movement glitches in certain games.");
            ImGui::EndTooltip();
        }

        ImGui::EndMenu();
    }
}

static void menu_audio(void)
{
    if (ImGui::BeginMenu("Audio"))
    {
        gui_in_use = true;

        if (ImGui::MenuItem("Enable Audio", config_hotkeys[config_HotkeyIndex_Mute].str, &config_audio.enable))
        {
            emu_audio_mute(!config_audio.enable);
        }

        // if (ImGui::MenuItem("Sync With Emulator", "", &config_audio.sync))
        // {
        //     config_emulator.ffwd = false;

        //     if (!config_audio.sync)
        //     {
        //         config_video.sync_mode = config_VideoSync_Disabled;
        //         display_disable_vsync();
        //     }
        // }

        ImGui::Separator();

        if (ImGui::BeginMenu("Master Volume", config_audio.enable))
        {
            ImGui::PushItemWidth(200.0f);
            if (ImGui::SliderFloat("##master_volume", &config_audio.master_volume, 0.0f, 2.0f, "Volume = %.2f", ImGuiSliderFlags_AlwaysClamp))
            {
                emu_audio_set_master_volume(config_audio.master_volume);
            }
            ImGui::PopItemWidth();
            if (ImGui::IsItemHovered())
            {
                ImGui::BeginTooltip();
                ImGui::Text("Anything above 1.00 may cause clipping.");
                ImGui::EndTooltip();
            }
            ImGui::EndMenu();
        }

        ImGui::Separator();

        if (ImGui::BeginMenu("Buffer Size", config_audio.enable))
        {
            ImGui::PushItemWidth(150.0f);
            if (ImGui::SliderInt("##buffer_count", &config_audio.buffer_count, 2, 5, "Buffers = %d"))
            {
                emu_audio_reset();
            }
            ImGui::PopItemWidth();
            if (ImGui::IsItemHovered())
            {
                float latency_ms = (config_audio.buffer_count * GC_AUDIO_QUEUE_SIZE) / (float)(GC_AUDIO_SAMPLE_RATE * 2) * 1000.0f;
                ImGui::BeginTooltip();
                ImGui::Text("Lower values reduce audio latency.");
                ImGui::Text("Higher values prevent audio underruns.");
                ImGui::Text("Enabling VSync may force higher buffer counts.");
                ImGui::Text("Current audio latency: %.0f ms", latency_ms);
                ImGui::EndTooltip();
            }
            ImGui::EndMenu();
        }

#ifndef GEARCOLECO_DISABLE_VGMRECORDER
        ImGui::Separator();

        bool is_recording = emu_is_vgm_recording();

        if (ImGui::MenuItem("Start VGM Recording...", "", false, !is_recording && !emu_is_empty()))
        {
            save_vgm = true;
        }

        if (ImGui::MenuItem("Stop VGM Recording", "", false, is_recording))
        {
            emu_stop_vgm_recording();
            gui_set_status_message("VGM recording stopped", 3000);
        }
#endif

        ImGui::EndMenu();
    }
}

static void menu_debug(void)
{
#if !defined(GEARCOLECO_DISABLE_DISASSEMBLER)
    if (ImGui::BeginMenu("Debug"))
    {
        gui_in_use = true;

        if (ImGui::MenuItem("Enable", "", &config_debug.debug))
        {
            emu_set_overscan(config_debug.debug ? 0 : config_video.overscan);

            if (config_debug.debug)
                emu_debug_step_over();
            else
                emu_debug_continue();
        }

        ImGui::Separator();

        if (ImGui::MenuItem("Save Debug Settings...", "", false, config_debug.debug))
        {
            save_debug_settings = true;
        }

        if (ImGui::MenuItem("Load Debug Settings...", "", false, config_debug.debug))
        {
            load_debug_settings = true;
        }

        ImGui::MenuItem("Auto Save/Load Debug Settings", "", &config_debug.auto_debug_settings, config_debug.debug);

        ImGui::Separator();

        if (ImGui::MenuItem("Reload ROM", config_hotkeys[config_HotkeyIndex_ReloadROM].str, false, config_debug.debug && !emu_is_empty()))
        {
            gui_action_reload_rom();
        }

        ImGui::Separator();

        if (ImGui::BeginMenu("MCP Server", config_debug.debug))
        {
            bool mcp_running = emu_mcp_is_running();
            int transport_mode = emu_mcp_get_transport_mode();
            bool http_running = mcp_running && (transport_mode == 1);
            bool stdio_running = mcp_running && (transport_mode == 0);

            if (ImGui::MenuItem("Start HTTP Server", "", false, !mcp_running))
            {
                if (strlen(gui_mcp_http_address) == 0)
                    strncpy_fit(gui_mcp_http_address, "127.0.0.1", sizeof(gui_mcp_http_address));
                config_emulator.mcp_http_address = gui_mcp_http_address;
                emu_mcp_set_transport(1, config_emulator.mcp_tcp_port, config_emulator.mcp_http_address.c_str());
                emu_mcp_start();
            }

            if (ImGui::MenuItem("Stop HTTP Server", "", false, http_running))
            {
                emu_mcp_stop();
            }

            ImGui::Separator();

            if (stdio_running)
                ImGui::TextColored(ImVec4(0.90f, 0.70f, 0.10f, 1.0f), "STDIO mode active");
            else if (http_running)
                ImGui::TextColored(ImVec4(0.10f, 0.90f, 0.10f, 1.0f), "Listening on %s:%d", config_emulator.mcp_http_address.c_str(), config_emulator.mcp_tcp_port);
            else
                ImGui::TextColored(ImVec4(0.98f, 0.15f, 0.45f, 1.0f), "Stopped");

            ImGui::Separator();

            ImGui::Text("HTTP Address:");
            ImGui::SameLine();
            ImGui::SetNextItemWidth(120);
            if (ImGui::InputText("##mcp_address", gui_mcp_http_address, IM_ARRAYSIZE(gui_mcp_http_address), ImGuiInputTextFlags_AutoSelectAll))
                config_emulator.mcp_http_address = gui_mcp_http_address;

            ImGui::Text("HTTP Port:");
            ImGui::SameLine();
            ImGui::SetNextItemWidth(50);
            if (ImGui::InputInt("##mcp_port", &config_emulator.mcp_tcp_port, 0, 0))
            {
                if (config_emulator.mcp_tcp_port < 1)
                    config_emulator.mcp_tcp_port = 1;
                if (config_emulator.mcp_tcp_port > 65535)
                    config_emulator.mcp_tcp_port = 65535;
            }

            ImGui::EndMenu();
        }

        ImGui::Separator();

        ImGui::MenuItem("Show Output Screen", "", &config_debug.show_screen, config_debug.debug);

        if (ImGui::BeginMenu("Output Scale", config_debug.debug))
        {
            ImGui::PushItemWidth(200.0f);
            ImGui::SliderInt("##debug_scale", &config_debug.scale, 1, 10);
            ImGui::PopItemWidth();
            ImGui::EndMenu();
        }

        ImGui::Separator();

        ImGui::MenuItem("Show Disassembler", "", &config_debug.show_disassembler, config_debug.debug);

        ImGui::MenuItem("Show Z80", "", &config_debug.show_processor, config_debug.debug);

        ImGui::MenuItem("Show Call Stack", "", &config_debug.show_call_stack, config_debug.debug);

        ImGui::MenuItem("Show Breakpoints", "", &config_debug.show_breakpoints, config_debug.debug);

        ImGui::MenuItem("Show Symbols", "", &config_debug.show_symbols, config_debug.debug);

        ImGui::MenuItem("Show Memory Editor", "", &config_debug.show_memory, config_debug.debug);

        if (ImGui::BeginMenu("Video", config_debug.debug))
        {
            ImGui::MenuItem("Show Name Table", "", &config_debug.show_video_nametable);
            ImGui::MenuItem("Show Pattern Table", "", &config_debug.show_video_tiles);
            ImGui::MenuItem("Show Sprites", "", &config_debug.show_video_sprites);
            //if (!emu_get_core()->GetVideo()->IsSG1000Mode())
                ImGui::MenuItem("Show Palettes", "", &config_debug.show_video_palettes);
            ImGui::MenuItem("Show VDP Registers", "", &config_debug.show_video_regs);
            ImGui::EndMenu();
        }

        if (ImGui::BeginMenu("Audio", config_debug.debug))
        {
            ImGui::MenuItem("Show PSG", "", &config_debug.show_psg, config_debug.debug);
            ImGui::MenuItem("Show AY-3-8910 (SGM)", "", &config_debug.show_ay8910, config_debug.debug);
            ImGui::EndMenu();
        }

        ImGui::MenuItem("Show Trace Logger", "", &config_debug.show_trace_logger, config_debug.debug);
        ImGui::MenuItem("Show Rewind", "", &config_debug.show_rewind, config_debug.debug);


#if defined(__APPLE__) || defined(_WIN32)
        ImGui::Separator();
        ImGui::MenuItem("Multi-Viewport", "", &config_debug.multi_viewport, config_debug.debug);
        if (ImGui::IsItemHovered())
        {
            ImGui::BeginTooltip();
            ImGui::Text("RESTART REQUIRED");
            ImGui::NewLine();
            ImGui::Text("Enables docking of debug windows outside of main window.");
            ImGui::EndTooltip();
        }
#endif

        ImGui::Separator();

        if (ImGui::BeginMenu("Font Size", config_debug.debug))
        {
            ImGui::PushItemWidth(110.0f);
            if (ImGui::Combo("##font", &config_debug.font_size, "Very Small\0Small\0Medium\0Large\0\0"))
            {
                gui_default_font = gui_default_fonts[config_debug.font_size];
            }
            ImGui::PopItemWidth();
            ImGui::EndMenu();
        }

        ImGui::EndMenu();
    }
#endif
}

static void menu_about(void)
{
    if (ImGui::BeginMenu("About"))
    {
        gui_in_use = true;

        if (ImGui::MenuItem("About " GEARCOLECO_TITLE " " GEARCOLECO_VERSION " ..."))
        {
            open_about = true;
        }
        ImGui::EndMenu();
    }
}

static void draw_mcp_status(void)
{
    if (!emu_mcp_is_running())
        return;

    char status[128];
    ImVec4 color(0.10f, 0.90f, 0.10f, 1.0f);

    int transport_mode = emu_mcp_get_transport_mode();
    if (transport_mode == 0)
    {
        snprintf(status, sizeof(status), "MCP: STDIO");
        color = ImVec4(0.90f, 0.70f, 0.10f, 1.0f);
    }
    else if (transport_mode == 1)
    {
        snprintf(status, sizeof(status), "MCP: HTTP (%s:%d)", config_emulator.mcp_http_address.c_str(), config_emulator.mcp_tcp_port);
    }
    else
    {
        return;
    }

    ImGuiStyle& style = ImGui::GetStyle();
    float text_width = ImGui::CalcTextSize(status).x;
    float status_x = ImGui::GetWindowWidth() - text_width - style.ItemSpacing.x - 10.0f;
    float cursor_x = ImGui::GetCursorPosX();

    if (status_x <= cursor_x + style.ItemSpacing.x)
        return;

    ImGui::SameLine(status_x);
    ImGui::AlignTextToFramePadding();
    ImGui::TextColored(color, "%s", status);
}

static void file_dialogs(void)
{
    gui_file_dialog_process_results();

    if (open_rom || gui_shortcut_open_rom)
    {
        gui_shortcut_open_rom = false;
        if (emu_is_bios_loaded())
            gui_file_dialog_open_rom();
        else
            open_bios_warning = true;
    }
    if (open_ram)
        gui_file_dialog_load_ram();
    if (save_ram)
        gui_file_dialog_save_ram();
    if (open_state)
        gui_file_dialog_load_state();
    if (save_state)
        gui_file_dialog_save_state();
    if (save_screenshot)
        gui_file_dialog_save_screenshot();
    if (save_vgm)
        gui_file_dialog_save_vgm();
    if (choose_savestates_path)
        gui_file_dialog_choose_savestate_path();
    if (choose_screenshots_path)
        gui_file_dialog_choose_screenshot_path();
    if (choose_backup_ram_path)
        gui_file_dialog_choose_saves_path();
    if (open_bios)
        gui_file_dialog_load_bios();
    if (save_debug_settings)
        gui_file_dialog_save_debug_settings();
    if (load_debug_settings)
        gui_file_dialog_load_debug_settings();
    if (open_about)
    {
        gui_dialog_in_use = true;
        ImGui::OpenPopup("About " GEARCOLECO_TITLE);
    }

    if (open_load_defaults)
    {
        gui_dialog_in_use = true;
        ImGui::OpenPopup("Load Default Settings");
    }

    if (open_bios_warning)
    {
        gui_dialog_in_use = true;
        ImGui::OpenPopup("BIOS not found");
    }

    gui_popup_modal_about();
    gui_popup_modal_load_defaults();
    gui_popup_modal_bios();
}

static void keyboard_configuration_item(const char* text, SDL_Scancode* key, int player)
{
    ImGui::Text("%s", text);
    ImGui::SameLine(120);

    char button_label[256];
    snprintf(button_label, 256, "%s##%s%d", SDL_GetKeyName(SDL_GetKeyFromScancode(*key, SDL_KMOD_NONE, false)), text, player);

    if (ImGui::Button(button_label, ImVec2(90,0)))
    {
        gui_configured_key = key;
        ImGui::OpenPopup("Keyboard Configuration");
    }

    ImGui::SameLine();

    char remove_label[256];
    snprintf(remove_label, sizeof(remove_label), "X##rk%s%d", text, player);

    if (ImGui::Button(remove_label))
    {
        *key = SDL_SCANCODE_UNKNOWN;
    }
}

static void gamepad_configuration_item(const char* text, int* button, int player)
{
    ImGui::Text("%s", text);
    ImGui::SameLine(130);

    const char* button_name = "";

    if (*button == SDL_GAMEPAD_BUTTON_INVALID)
    {
        button_name = "";
    }
    else if (*button >= 0 && *button < SDL_GAMEPAD_BUTTON_COUNT)
    {
        static const char* gamepad_names[21] = {"A", "B", "X" ,"Y", "BACK", "GUIDE", "START", "L3", "R3", "L1", "R1", "UP", "DOWN", "LEFT", "RIGHT", "MISC", "PAD1", "PAD2", "PAD3", "PAD4", "TOUCH"};
        button_name = gamepad_names[*button];
    }
    else if (*button >= GAMEPAD_VBTN_AXIS_BASE)
    {
        int axis = *button - GAMEPAD_VBTN_AXIS_BASE;
        if (axis == SDL_GAMEPAD_AXIS_LEFT_TRIGGER)
            button_name = "L2";
        else if (axis == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER)
            button_name = "R2";
        else
            button_name = "??";
    }

    char button_label[256];
    snprintf(button_label, sizeof(button_label), "%s##%s%d", button_name, text, player);

    if (ImGui::Button(button_label, ImVec2(70,0)))
    {
        gui_configured_button = button;
        ImGui::OpenPopup("Gamepad Configuration");
    }

    ImGui::SameLine();

    char remove_label[256];
    snprintf(remove_label, sizeof(remove_label), "X##rg%s%d", text, player);

    if (ImGui::Button(remove_label))
    {
        *button = SDL_GAMEPAD_BUTTON_INVALID;
    }
}

static void hotkey_configuration_item(const char* text, config_Hotkey* hotkey)
{
    ImGui::Text("%s", text);
    ImGui::SameLine(150);

    char button_label[256];
    snprintf(button_label, sizeof(button_label), "%s##%s", hotkey->str[0] != '\0' ? hotkey->str : "<None>", text);

    if (ImGui::Button(button_label, ImVec2(150,0)))
    {
        gui_configured_hotkey = hotkey;
        ImGui::OpenPopup("Hotkey Configuration");
    }

    ImGui::SameLine();

    char remove_label[256];
    snprintf(remove_label, sizeof(remove_label), "X##rh%s", text);

    if (ImGui::Button(remove_label))
    {
        hotkey->key = SDL_SCANCODE_UNKNOWN;
        hotkey->mod = SDL_KMOD_NONE;
        config_update_hotkey_string(hotkey);
    }
}

static void gamepad_device_selector(int player)
{
    if (player < 0 || player >= GC_MAX_GAMEPADS)
        return;

    const int max_detected_gamepads = 32;
    SDL_JoystickID id_map[max_detected_gamepads];
    id_map[0] = 0;
    int count = 1;

    std::string items;
    items.reserve(4096);
    items.append("<None>");
    items.push_back('\0');

    Gamepad_Detected_Info detected[max_detected_gamepads];
    int num_detected = gamepad_get_detected(detected, max_detected_gamepads);

    SDL_JoystickID current_id = 0;
    if (IsValidPointer(gamepad_controller[player]))
        current_id = SDL_GetJoystickID(SDL_GetGamepadJoystick(gamepad_controller[player]));

    int selected = 0;

    for (int i = 0; i < num_detected && count < max_detected_gamepads; i++)
    {
        const char* name = detected[i].name;
        if (!IsValidPointer(name))
            name = "Unknown Gamepad";

        id_map[count] = detected[i].id;

        if (current_id == detected[i].id)
            selected = count;

        size_t len = strlen(detected[i].guid_str);
        const char* id_8 = detected[i].guid_str + (len > 8 ? len - 8 : 0);

        char label[192];
        snprintf(label, sizeof(label), "%s (ID: %s)", name, id_8);

        items.append(label);
        items.push_back('\0');
        count++;
    }

    items.push_back('\0');

    char label[32];
    snprintf(label, sizeof(label), "##device_player%d", player + 1);

    if (ImGui::Combo(label, &selected, items.c_str()))
    {
        SDL_JoystickID instance_id = id_map[selected];
        gamepad_assign(player, instance_id);
    }
}

static void draw_savestate_slot_info(int slot)
{
    if (emu_savestates[slot].rom_name[0] != 0)
    {
        if (emu_savestates[slot].version < GC_SAVESTATE_MIN_VERSION || emu_savestates[slot].version > GC_SAVESTATE_VERSION)
        {
            if (emu_savestates[slot].version == GC_SAVESTATE_VERSION_V1)
            {
                ImGui::TextColored(ImVec4(1.0f, 0.80f, 0.0f, 1.0f), "This save state is from an older version");
            }
            else
            {
                ImGui::TextColored(ImVec4(0.98f, 0.15f, 0.45f, 1.0f), "This save state is from an older version and will not work");
                if (emu_savestates[slot].emu_build[0] != 0)
                    ImGui::TextColored(ImVec4(0.98f, 0.15f, 0.45f, 1.0f), "Use %s - %s", GEARCOLECO_TITLE, emu_savestates[slot].emu_build);
            }
            ImGui::Separator();
        }

        ImGui::Text("%s", emu_savestates[slot].rom_name);
        char date[64];
        get_date_time_string(emu_savestates[slot].timestamp, date, sizeof(date));
        ImGui::Text("%s", date);

        if (IsValidPointer(emu_savestates_screenshots[slot].data))
        {
            float width = (float)emu_savestates_screenshots[slot].width;
            float height = (float)emu_savestates_screenshots[slot].height;
            ImGui::Image((ImTextureID)(intptr_t)ogl_renderer_emu_savestates, ImVec2((height / 3.0f) * 4.0f, height), ImVec2(0, 0), ImVec2(width / (float)SYSTEM_TEXTURE_WIDTH, height / (float)SYSTEM_TEXTURE_HEIGHT));
        }
    }
    else
    {
        ImGui::TextColored(ImVec4(0.50f, 0.50f, 0.50f, 1.0f), "Slot %d is empty", slot + 1);
    }
}
