text: /**
   ******************************************************************************
   * Xenia : Xbox 360 Emulator Research Project                                 *
   ******************************************************************************
   * Copyright 2022 Ben Vanik. All rights reserved.                             *
   * Released under the BSD license - see LICENSE in the root for more details. *
   ******************************************************************************
   */
  
  #ifndef XENIA_APP_EMULATOR_WINDOW_H_
  #define XENIA_APP_EMULATOR_WINDOW_H_
  
  #include <memory>
  #include <string>
  
  #include "xenia/kernel/kernel_flags.h"
  #include "xenia/emulator.h"
  #include "xenia/gpu/command_processor.h"
  #include "xenia/ui/imgui_dialog.h"
  #include "xenia/ui/imgui_drawer.h"
  #include "xenia/ui/immediate_drawer.h"
  #include "xenia/ui/menu_item.h"
  #include "xenia/ui/presenter.h"
  #include "xenia/ui/window.h"
  #include "xenia/ui/window_listener.h"
  #include "xenia/ui/windowed_app_context.h"
  #include "xenia/xbox.h"
  
  namespace xe {
  namespace app {
  
  class EmulatorWindow {
   public:
    enum : size_t {
      // The UI is on top of the game and is open in special cases, so
      // lowest-priority.
      kZOrderHidInput,
      kZOrderImGui,
      kZOrderProfiler,
      // Emulator window controls are expected to be always accessible by the
      // user, so highest-priority.
      kZOrderEmulatorWindowInput,
    };
  
    virtual ~EmulatorWindow();
  
    static std::unique_ptr<EmulatorWindow> Create(
        Emulator* emulator, ui::WindowedAppContext& app_context);
  
    Emulator* emulator() const { return emulator_; }
    ui::WindowedAppContext& app_context() const { return app_context_; }
    ui::Window* window() const { return window_.get(); }
    ui::ImGuiDrawer* imgui_drawer() const { return imgui_drawer_.get(); }
  
    ui::Presenter* GetGraphicsSystemPresenter() const;
    void SetupGraphicsSystemPresenterPainting();
    void ShutdownGraphicsSystemPresenterPainting();
  
    void OnEmulatorInitialized();
  
    void UpdateTitle();
    void SetFullscreen(bool fullscreen);
    void ToggleFullscreen();
    void SetInitializingShaderStorage(bool initializing);
  
   private:
    class EmulatorWindowListener final : public ui::WindowListener,
                                         public ui::WindowInputListener {
     public:
      explicit EmulatorWindowListener(EmulatorWindow& emulator_window)
          : emulator_window_(emulator_window) {}
  
      void OnClosing(ui::UIEvent& e) override;
      void OnFileDrop(ui::FileDropEvent& e) override;
  
      void OnKeyDown(ui::KeyEvent& e) override;
  
     private:
      EmulatorWindow& emulator_window_;
    };
  
    class DisplayConfigGameConfigLoadCallback
        : public Emulator::GameConfigLoadCallback {
     public:
      DisplayConfigGameConfigLoadCallback(Emulator& emulator,
                                          EmulatorWindow& emulator_window)
          : Emulator::GameConfigLoadCallback(emulator),
            emulator_window_(emulator_window) {}
  
      void PostGameConfigLoad() override;
  
     private:
      EmulatorWindow& emulator_window_;
    };
  
    class DisplayConfigDialog final : public ui::ImGuiDialog {
     public:
      DisplayConfigDialog(ui::ImGuiDrawer* imgui_drawer,
                          EmulatorWindow& emulator_window)
          : ui::ImGuiDialog(imgui_drawer), emulator_window_(emulator_window) {}
  
     protected:
      void OnDraw(ImGuiIO& io) override;
  
     private:
      EmulatorWindow& emulator_window_;
    };
  
    explicit EmulatorWindow(Emulator* emulator,
                            ui::WindowedAppContext& app_context);
  
    bool Initialize();
  
    // For comparisons, use GetSwapPostEffectForCvarValue instead as the default
    // fallback may be used for multiple values.
    static const char* GetCvarValueForSwapPostEffect(
        gpu::CommandProcessor::SwapPostEffect effect);
    static gpu::CommandProcessor::SwapPostEffect GetSwapPostEffectForCvarValue(
        const std::string& cvar_value);
    // For comparisons, use GetGuestOutputPaintEffectForCvarValue instead as the
    // default fallback may be used for multiple values.
    static const char* GetCvarValueForGuestOutputPaintEffect(
        ui::Presenter::GuestOutputPaintConfig::Effect effect);
    static ui::Presenter::GuestOutputPaintConfig::Effect
    GetGuestOutputPaintEffectForCvarValue(const std::string& cvar_value);
    static ui::Presenter::GuestOutputPaintConfig
    GetGuestOutputPaintConfigForCvars();
    void ApplyDisplayConfigForCvars();
  
    void OnKeyDown(ui::KeyEvent& e);
    void FileDrop(const std::filesystem::path& filename);
    void FileOpen();
    void FileClose();
    void ShowContentDirectory();
    void CpuTimeScalarReset();
    void CpuTimeScalarSetHalf();
    void CpuTimeScalarSetDouble();
    void CpuBreakIntoDebugger();
    void CpuBreakIntoHostDebugger();
    void GpuTraceFrame();
    void GpuClearCaches();
    void ShowCustomBuildWarning();
    void ShowHelpWebsite();
    void ShowAboutWebsite();
    void ShowCommitID();
    void ToggleDisplayConfigDialog();
    void ShowCompatibility();
    void ShowFAQ();
    void ShowBuildCommit();
  
    Emulator* emulator_;
    ui::WindowedAppContext& app_context_;
    EmulatorWindowListener window_listener_;
    std::unique_ptr<ui::Window> window_;
    std::unique_ptr<ui::ImGuiDrawer> imgui_drawer_;
    std::unique_ptr<DisplayConfigGameConfigLoadCallback>
        display_config_game_config_load_callback_;
    // Creation may fail, in this case immediate drawer UI must not be drawn.
    std::unique_ptr<ui::ImmediateDrawer> immediate_drawer_;
  
    bool emulator_initialized_ = false;
  
    std::string base_title_;
    bool initializing_shader_storage_ = false;
  
    std::unique_ptr<DisplayConfigDialog> display_config_dialog_;
  };
  
  }  // namespace app
  }  // namespace xe
  
  #endif  // XENIA_APP_EMULATOR_WINDOW_H_
  