code:
#pragma once
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/FadeoutScreen.hpp"

struct Dialog_FadeoutScreen : IEventDialogController {
  Dialog_FadeoutScreen() = delete;
  explicit Dialog_FadeoutScreen(const std::string& name, const std::shared_ptr<FadeoutScreenCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new FadeoutScreenCommand());
    }
    m_open = false;
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return command; };

private:
  bool m_confirmed{true};
  std::shared_ptr<FadeoutScreenCommand> command;
  std::tuple<bool, bool> result;
};


code:
#include "Core/EventCommands/Dialog_FlashScreen.hpp"

#include "imgui.h"
#include <tuple>

std::tuple<bool, bool> Dialog_FlashScreen::draw() {
  if (isOpen()) {
    ImGui::OpenPopup(m_name.c_str());
  }
  ImVec2 center = ImGui::GetMainViewport()->GetCenter();
  ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  ImGui::SetNextWindowSize(ImVec2{410, 250}, ImGuiCond_Appearing);
  if (ImGui::BeginPopupModal(m_name.c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {

    ImGui::SeparatorText("Flash Color");

    color_picker.draw();

    ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 4.f);
    ImGui::PushItemWidth(390);
    if (ImGui::BeginCombo("##flashscreen_presets", "Future presets go in this list")) {
      // TODO: Template system for tint screen
      ImGui::EndCombo();
    }
    ImGui::SeparatorText("Duration");
    ImGui::SetNextItemWidth(100);
    if (ImGui::InputInt("##flashscreen_duration", &m_duration)) {
      if (m_duration < 1)
        m_duration = 1;
      if (m_duration > 999)
        m_duration = 999;
    }
    ImGui::SameLine();
    ImGui::Text("frames 1/60 sec");
    ImGui::SameLine();
    ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 80.f);
    ImGui::Checkbox("Wait for Completion", &m_waitForCompletion);

    if (ImGui::Button("OK")) {
      m_confirmed = true;
      command->color.r = color_picker.r();
      command->color.g = color_picker.g();
      command->color.b = color_picker.b();
      command->color.intensity = color_picker.intensity();
      command->duration = m_duration;
      command->waitForCompletion = m_waitForCompletion;
      ImGui::CloseCurrentPopup();
      setOpen(false);
    }
    ImGui::SameLine();
    if (ImGui::Button("Cancel")) {
      ImGui::CloseCurrentPopup();
      setOpen(false);
    }
    ImGui::EndPopup();
  }

  return std::make_tuple(!m_open, m_confirmed);
}

repo_name: Antidote/openrpgeditor

license: mit


code:
#pragma once
#include "Core/CommonUI/ColorFlashPicker.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/FlashScreen.hpp"

struct Dialog_FlashScreen : IEventDialogController {
  Dialog_FlashScreen() = delete;
  explicit Dialog_FlashScreen(const std::string& name, const std::shared_ptr<FlashScreenCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new FlashScreenCommand());
    }
    r = command->color.r;
    g = command->color.g;
    b = command->color.b;
    m_intensity = command->color.intensity;
    m_duration = command->duration;
    m_waitForCompletion = command->waitForCompletion;

    color_picker.setValues(r, g, b, m_intensity);
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return command; };

private:
  int r;
  int g;
  int b;
  int m_intensity;
  int m_duration;
  bool m_waitForCompletion;

  bool m_confirmed{false};
  std::shared_ptr<FlashScreenCommand> command;
  std::tuple<bool, bool> result;

  ColorFlashPicker color_picker;
};


code:
#include "Core/EventCommands/Dialog_GameData.hpp"

#include "Core/CommonUI/GroupBox.hpp"
#include "Core/ImGuiExt/ImGuiUtils.hpp"
#include "Core/Log.hpp"
#include "Database/Database.hpp"
#include <imgui.h>
#include <imgui_internal.h>

std::tuple<bool, bool> Dialog_GameData::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###GameData");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 48) + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetFrameHeightWithSpacing() * 11) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});

  if (ImGui::BeginPopupModal(std::format("{}###GameData", m_name).c_str(), &m_open, ImGuiWindowFlags_NoResize)) {
    drawPickers();
    ImGui::BeginVertical("##game_data_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      GroupBox gameDataGroup("", "##game_data_group_box", {-1, 0});
      if (gameDataGroup.begin()) {
        ImGui::BeginHorizontal("##game_data_inner_layout");
        {
          ImGui::BeginVertical("##game_data_inner_radios", {-1, -1}, 0);
          {
            ImGui::RadioButton(trNOOP("Item"), &m_type, 0);
            ImGui::RadioButton(trNOOP("Weapon"), &m_type, 1);
            ImGui::RadioButton(trNOOP("Armor"), &m_type, 2);
            ImGui::RadioButton(trNOOP("Actor"), &m_type, 3);
            ImGui::RadioButton(trNOOP("Enemy"), &m_type, 4);
            ImGui::RadioButton(trNOOP("Character"), &m_type, 5);
            ImGui::RadioButton(trNOOP("Party"), &m_type, 6);
            ImGui::RadioButton(trNOOP("Other"), &m_type, 7);
          }
          ImGui::EndVertical();
          ImGui::BeginVertical("##game_data_inner_values", {-1, -1}, 0);
          {
            ImGui::BeginHorizontal("##game_data_inner_values_item");
            {
              ImGui::BeginDisabled(m_type != 0);
              {
                ImGui::PushID("##game_data_item_id");
                if (ImGui::EllipsesButton(m_type != 0 ? "" : Database::instance()->itemNameAndId(m_itemValue).c_str(), ImVec2{ImGui::GetContentRegionAvail().x * .55f, 0})) {
                  m_itemPicker = ObjectPicker(trNOOP("Items"), Database::instance()->items.items(), m_itemValue);
                  m_itemPicker->setOpen(true);
                }
                ImGui::PopID();
                ImGui::TextUnformatted(trNOOP("(Possession Count)"));
              }
              ImGui::EndDisabled();
            }
            ImGui::EndHorizontal();
            ImGui::BeginHorizontal("##game_data_inner_values_weapon");
            {
              ImGui::BeginDisabled(m_type != 1);
              {
                ImGui::PushID("##game_data_weapon_id");
                if (ImGui::EllipsesButton(m_type != 1 ? "" : Database::instance()->weaponNameAndId(m_weaponValue).c_str(), ImVec2{ImGui::GetContentRegionAvail().x * .55f, 0})) {
                  m_weaponPicker = ObjectPicker(trNOOP("Weapons"), Database::instance()->weapons.weapons(), m_weaponValue);
                  m_weaponPicker->setOpen(true);
                }
                ImGui::PopID();
                ImGui::TextUnformatted(trNOOP("(Possession Count)"));
              }
              ImGui::EndDisabled();
            }
            ImGui::EndHorizontal();
            ImGui::BeginHorizontal("##game_data_inner_values_armor");
            {
              ImGui::BeginDisabled(m_type != 2);
              {
                ImGui::PushID("##game_data_weapon_id");
                if (ImGui::EllipsesButton(m_type != 2 ? "" : Database::instance()->armorNameAndId(m_armorValue).c_str(), ImVec2{ImGui::GetContentRegionAvail().x * .55f, 0})) {
                  m_armorPicker = ObjectPicker(trNOOP("Armors"), Database::instance()->armors.armors(), m_armorValue);
                  m_armorPicker->setOpen(true);
                }
                ImGui::PopID();
                ImGui::TextUnformatted(trNOOP("(Possession Count)"));
              }
              ImGui::EndDisabled();
            }
            ImGui::EndHorizontal();
            ImGui::BeginHorizontal("##game_data_inner_values_actor");
            {
              ImGui::BeginDisabled(m_type != 3);
              {
                ImGui::PushID("##game_data_actor_id");
                if (ImGui::EllipsesButton(m_type != 3 ? "" : Database::instance()->actorNameAndId(m_actorValue).c_str(), ImVec2{ImGui::GetContentRegionAvail().x * .55f, 0})) {
                  m_actorPicker = ObjectPicker(trNOOP("Actors"), Database::instance()->actors.actorList(), m_actorValue);
                  m_actorPicker->setOpen(true);
                }
                ImGui::PopID();
                ImGui::SetNextItemWidth(-1);
                if (ImGui::BeginCombo("##game_data_actor_combo", m_type != 3 ? "" : magic_enum::enum_name(static_cast<ActorDataSource>(m_actorSource)).data())) {
                  for (auto dataSource : ActorData) {
                    const bool isSelected = m_actorSource == static_cast<int>(dataSource);
                    if (ImGui::Selectable(DecodeEnumName(dataSource).c_str(), isSelected)) {
                      m_actorSource = static_cast<int>(dataSource);
                    }
                    if (isSelected) {
                      ImGui::SetItemDefaultFocus();
                    }
                  }
                  ImGui::EndCombo();
                }
              }
              ImGui::EndDisabled();
            }
            ImGui::EndHorizontal();
            ImGui::BeginHorizontal("##game_data_inner_values_enemy");
            {
              ImGui::BeginDisabled(m_type != 4);
              {
                ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * .55f);
                const auto preview = m_type != 4 ? "" : std::format("#{} {}", m_enemyValue + 1, Database::instance()->troopMemberName(m_troopId, m_enemyValue));
                if (ImGui::BeginCombo("##game_data_enemy_list", preview.c_str())) {
                  for (int i = 0; i < 8; ++i) {
                    const auto name = std::format("#{} {}", i + 1, Database::instance()->troopMemberName(m_troopId, i));
                    if (ImGui::Selectable(name.c_str(), i == m_enemyValue)) {
                      m_enemyValue = i;
                    }
                  }
                  ImGui::EndCombo();
                }
                ImGui::SetNextItemWidth(-1);
                if (ImGui::BeginCombo("##game_data_enemy_source_combo", m_type != 4 ? "" : DecodeEnumName(static_cast<EnemyDataSource>(m_enemySource)).c_str())) {
                  for (auto dataSource : EnemyData) {
                    const bool isSelected = m_enemySource == static_cast<int>(dataSource);
                    if (ImGui::Selectable(DecodeEnumName(dataSource).c_str(), isSelected)) {
                      m_enemySource = static_cast<int>(dataSource);
                    }
                    if (isSelected) {
                      ImGui::SetItemDefaultFocus();
                    }
                  }
                  ImGui::EndCombo();
                }
              }
              ImGui::EndDisabled();
            }
            ImGui::EndHorizontal();

            ImGui::BeginHorizontal("##game_data_inner_values_character");
            {
              ImGui::BeginDisabled(m_type != 5);
              {
                ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * .55f);
                const auto preview = m_type != 5 ? "" : Database::instance()->eventNameOrId(m_characterValue);
                if (ImGui::BeginCombo("##game_data_character_list", preview.c_str())) {
                  for (int i = -1; i < static_cast<int>(Database::instance()->mapInfos.currentMap()->map()->events().size()); ++i) {
                    if (i > 0 && !Database::instance()->mapInfos.currentMap()->map()->event(i)) {
                      continue;
                    }

                    if (ImGui::Selectable(Database::instance()->eventNameOrId(i).c_str(), i == m_characterValue)) {
                      m_characterValue = i;
                    }
                  }
                  ImGui::EndCombo();
                }
                ImGui::SetNextItemWidth(-1);
                if (ImGui::BeginCombo("##game_data_enemy_source_combo", m_type != 5 ? "" : DecodeEnumName(static_cast<CharacterDataSource>(m_characterSource)).c_str())) {
                  for (auto dataSource : CharacterData) {
                    const bool isSelected = m_characterSource == static_cast<int>(dataSource);
                    if (ImGui::Selectable(DecodeEnumName(dataSource).c_str(), isSelected)) {
                      m_characterSource = static_cast<int>(dataSource);
                    }
                    if (isSelected) {
                      ImGui::SetItemDefaultFocus();
                    }
                  }
                  ImGui::EndCombo();
                }
              }
              ImGui::EndDisabled();
            }
            ImGui::EndHorizontal();
            ImGui::BeginHorizontal("##game_data_inner_values_party");
            {
              ImGui::BeginDisabled(m_type != 6);
              {
                ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * .55f);
                if (ImGui::BeginCombo("##game_data_party", m_type != 6 ? "" : std::format("Member #{}", m_partyValue + 1).c_str())) {
                  for (int n = 0; n < 8; n++) {
                    const bool isSelected = m_partyValue == n;
                    if (ImGui::Selectable(std::format("Member #{}", n + 1).c_str(), isSelected)) {
                      m_partyValue = n;
                    }
                    if (isSelected)
                      ImGui::SetItemDefaultFocus();
                  }
                  ImGui::EndCombo();
                }
                ImGui::TextUnformatted(trNOOP("(Actor ID)"));
              }
              ImGui::EndDisabled();
            }
            ImGui::EndHorizontal();
            ImGui::BeginHorizontal("##game_data_inner_values_other");
            {
              ImGui::BeginDisabled(m_type != 7);
              {
                ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * .55f);
                if (ImGui::BeginCombo("##game_data_other", m_type != 7 ? "" : DecodeEnumName(static_cast<OtherDataSource>(m_otherValue)).c_str())) {
                  for (auto dataSource : OtherSource) {
                    const bool isSelected = m_otherValue == static_cast<int>(dataSource);
                    if (ImGui::Selectable(DecodeEnumName(dataSource).c_str(), isSelected)) {
                      m_otherValue = static_cast<int>(dataSource);
                    }
                    if (isSelected) {
                      ImGui::SetItemDefaultFocus();
                    }
                  }
                  ImGui::EndCombo();
                }
              }
              ImGui::EndDisabled();
            }
            ImGui::EndHorizontal();
          }
          ImGui::EndVertical();
        }
        ImGui::EndHorizontal();
      }
      gameDataGroup.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##game_data_button_layout", {-1, -1}, 0);
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##game_data_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command.gameData.type = static_cast<GameDataType>(m_type);
          switch (static_cast<GameDataType>(m_type)) {
          case GameDataType::Item:
            m_command.gameData.value = m_itemValue;
            break;
          case GameDataType::Weapon:
            m_command.gameData.value = m_weaponValue;
            break;
          case GameDataType::Armor:
            m_command.gameData.value = m_armorValue;
            break;
          case GameDataType::Actor:
            m_command.gameData.rawSource = m_actorSource;
            m_command.gameData.value = m_actorValue;
            break;
          case GameDataType::Enemy:
            m_command.gameData.rawSource = m_enemySource;
            m_command.gameData.value = m_enemyValue;
            break;
          case GameDataType::Character:
            m_command.gameData.rawSource = m_characterSource;
            m_command.gameData.value = m_characterValue;
            break;
          case GameDataType::Party:
            m_command.gameData.value = m_partyValue;
            break;
          case GameDataType::Other:
            m_command.gameData.otherSource = static_cast<OtherDataSource>(m_otherValue);
            break;
          default:
            m_command.gameData.rawSource = 0;
            m_command.gameData.value = 0;
            break;
          }
          ImGui::CloseCurrentPopup();
          setOpen(false);
        } else if (ret == 1) {
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }
  return std::make_tuple(!m_open, m_confirmed);
}

void Dialog_GameData::drawPickers() {
  if (m_actorPicker) {
    if (const auto [closed, confirmed] = m_actorPicker->draw(); closed) {
      if (confirmed) {
        m_actorSource = m_actorPicker->selection();
      }
      m_actorPicker.reset();
    }
  }
  if (m_armorPicker) {
    if (const auto [closed, confirmed] = m_armorPicker->draw(); closed) {
      if (confirmed) {
        m_armorValue = m_armorPicker->selection();
      }
      m_armorPicker.reset();
    }
  }
  if (m_weaponPicker) {
    if (const auto [closed, confirmed] = m_weaponPicker->draw(); closed) {
      if (confirmed) {
        m_weaponValue = m_weaponPicker->selection();
      }
      m_weaponPicker.reset();
    }
  }
  if (m_itemPicker) {
    if (const auto [closed, confirmed] = m_itemPicker->draw(); closed) {
      if (confirmed) {
        m_itemValue = m_itemPicker->selection();
      }
      m_itemPicker.reset();
    }
  }
}


code:
#pragma once
#include "Core/CommonUI/ObjectPicker.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/Class.hpp"
#include "Database/Database.hpp"
#include "Database/EventCommands/ControlVariables.hpp"
#include "Database/Items.hpp"

struct Dialog_GameData : IEventDialogController {
  Dialog_GameData() = delete;
  explicit Dialog_GameData(const std::string& name, const int type, const int rawSource, const int value = 0, const int troopId = 0)
  : IEventDialogController(name)
  , m_troopId(troopId)
  , m_type(type) {
    switch (static_cast<GameDataType>(m_type)) {
    case GameDataType::Item:
      m_itemValue = value;
      break;
    case GameDataType::Weapon:
      m_weaponValue = value;
      break;
    case GameDataType::Armor:
      m_armorValue = value;
      break;
    case GameDataType::Actor:
      m_actorSource = rawSource;
      m_actorValue = value;
      break;
    case GameDataType::Enemy:
      m_enemySource = rawSource;
      m_enemyValue = value;
      break;
    case GameDataType::Character:
      m_characterSource = rawSource;
      m_characterValue = value;
      break;
    case GameDataType::Party:
      m_partyValue = value;
      break;
    case GameDataType::Other:
      m_otherValue = value;
      break;
    }
    m_command.gameData.value = 0;
  }
  std::tuple<bool, bool> draw() override;

  ControlVariables& getData() { return m_command; }
  const ControlVariables& getData() const { return m_command; }

private:
  void drawPickers();
  int m_troopId{0};
  bool m_confirmed{false};

  int m_type;

  int m_itemValue{1};
  int m_weaponValue{1};
  int m_armorValue{1};
  int m_actorValue{1};
  int m_actorSource{0};
  int m_enemyValue{0};
  int m_enemySource{0};
  int m_characterValue{-1};
  int m_characterSource{0};
  int m_partyValue{0};
  int m_otherValue{0};

  static constexpr auto ActorData = magic_enum::enum_values<ActorDataSource>();
  static constexpr auto EnemyData = magic_enum::enum_values<EnemyDataSource>();
  static constexpr auto CharacterData = magic_enum::enum_values<CharacterDataSource>();
  static constexpr auto OtherSource = magic_enum::enum_values<OtherDataSource>();

  ControlVariables m_command;
  std::optional<ObjectPicker<Item>> m_itemPicker;
  std::optional<ObjectPicker<Actor>> m_actorPicker;
  std::optional<ObjectPicker<Armor>> m_armorPicker;
  std::optional<ObjectPicker<Weapon>> m_weaponPicker;
};


code:
#include "Core/EventCommands/Dialog_GameOver.hpp"

#include "Core/Log.hpp"

#include <tuple>

std::tuple<bool, bool> Dialog_GameOver::draw() {
  if (isOpen()) {
    setOpen(false);
    m_confirmed = true;
  }
  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/GameOver.hpp"

struct Dialog_GameOver : IEventDialogController {
  Dialog_GameOver() = delete;
  explicit Dialog_GameOver(const std::string& name, const std::shared_ptr<GameOverCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new GameOverCommand());
    }
    m_open = false;
  }
  std::tuple<bool, bool> draw() override;
  std::shared_ptr<IEventCommand> getCommand() override { return m_command; };

private:
  bool m_confirmed{true};
  std::shared_ptr<GameOverCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_GatherFollowers.hpp"
#include <tuple>

std::tuple<bool, bool> Dialog_GatherFollowers::draw() {
  if (isOpen()) {
    setOpen(false);
    m_confirmed = true;
  }
  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/GatherFollowers.hpp"

struct Dialog_GatherFollowers : IEventDialogController {
  Dialog_GatherFollowers() = delete;
  explicit Dialog_GatherFollowers(const std::string& name, const std::shared_ptr<GatherFollowersCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new GatherFollowersCommand());
    }
    m_open = false;
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return command; };

private:
  bool m_confirmed{true};
  std::shared_ptr<GatherFollowersCommand> command;
  std::tuple<bool, bool> result;
};


code:
#include "Core/EventCommands/Dialog_GetOnOffVehicle.hpp"
#include <tuple>

std::tuple<bool, bool> Dialog_GetOnOffVehicle::draw() {
  if (isOpen()) {
    setOpen(false);
    m_confirmed = true;
  }
  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/GetOnOffVehicle.hpp"

struct Dialog_GetOnOffVehicle : IEventDialogController {
  Dialog_GetOnOffVehicle() = delete;
  explicit Dialog_GetOnOffVehicle(const std::string& name, const std::shared_ptr<GetOnOffVehicleCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new GetOnOffVehicleCommand());
    }
    m_open = false;
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return command; };

private:
  bool m_confirmed{true};
  std::shared_ptr<GetOnOffVehicleCommand> command;
  std::tuple<bool, bool> result;
};


code:
#include "Core/EventCommands/Dialog_InputNumber.hpp"

#include "Core/CommonUI/GroupBox.hpp"
#include "Core/ImGuiExt/ImGuiUtils.hpp"
#include "Database/Database.hpp"

#include <imgui.h>
#include <imgui_internal.h>
#include <tuple>

std::tuple<bool, bool> Dialog_InputNumber::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###InputNumber");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 30) + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetFrameHeightWithSpacing() * 7) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});

  if (ImGui::BeginPopupModal(std::format("{}###InputNumber", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    drawPickers();

    ImGui::BeginVertical("##input_number_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      GroupBox variableGroupBox(trNOOP("Variable"), "##input_number_variable_group_box", {-1, 0});
      if (variableGroupBox.begin()) {
        if (ImGui::EllipsesButton(Database::instance()->variableNameAndId(m_variable).c_str(), {-1, 0})) {
          m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_variable);
          m_variablePicker->setOpen(true);
        }
      }
      variableGroupBox.end();
      GroupBox digitsGroupBox(trNOOP("Digits"), "##input_number_digits_group_box", {-1, 0});
      if (digitsGroupBox.begin()) {
        ImGui::SetNextItemWidth(-1);
        if (ImGui::SpinInt("##input_number_digits", &m_digits)) {
          m_digits = std::clamp(m_digits, 1, 9);
        }
      }
      digitsGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##input_number_button_layout");
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##input_number_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->variable = m_variable;
          m_command->digits = m_digits;
          ImGui::CloseCurrentPopup();
          setOpen(false);
        } else if (ret == 1) {
          ImGui::CloseCurrentPopup();
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }

  return std::make_tuple(!m_open, m_confirmed);
}

void Dialog_InputNumber::drawPickers() {
  if (m_variablePicker) {
    if (const auto [closed, confirmed] = m_variablePicker->draw(); closed) {
      if (confirmed) {
        m_variable = m_variablePicker->selection();
      }
      m_variablePicker.reset();
    }
  }
}


code:
#pragma once
#include "Core/CommonUI/VariableSwitchPicker.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/InputNumber.hpp"

struct Dialog_InputNumber : IEventDialogController {
  Dialog_InputNumber() = delete;
  explicit Dialog_InputNumber(const std::string& name, const std::shared_ptr<InputNumberCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new InputNumberCommand());
    }
    m_variable = m_command->variable;
    m_digits = m_command->digits;
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return m_command; };

private:
  void drawPickers();
  int m_variable;
  int m_digits;

  bool m_confirmed{false};
  std::optional<VariableSwitchPicker> m_variablePicker;
  std::shared_ptr<InputNumberCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_JumpToLabel.hpp"

#include "Core/CommonUI/GroupBox.hpp"
#include "Core/ImGuiExt/ImGuiUtils.hpp"
#include "Database/Database.hpp"

#include <imgui.h>
#include <imgui_internal.h>

#include <tuple>

std::tuple<bool, bool> Dialog_JumpToLabel::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###JumpToLabel");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize =
      ImVec2{ImGui::CalcTextSize("#############################").x + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetFrameHeightWithSpacing() * 5) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});
  if (ImGui::BeginPopupModal(std::format("{}###JumpToLabel", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    ImGui::BeginVertical("##jump_to_label_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      GroupBox labelGroupBox(trNOOP("Label Name"), "##jump_to_label_label_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiWindowFlags_AlwaysAutoResize);
      if (labelGroupBox.begin()) {
        ImGui::SetNextItemWidth(-1);
        ImGui::InputText("##label_input", &m_label);
      }
      labelGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##jump_to_label_buttons_layout", {-1, -1}, 0);
      {
        ImGui::Spring();
        ImGui::SetNextItemWidth(-1);
        if (const auto ret = ImGui::ButtonGroup("##jump_to_label_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->label = m_label;
          ImGui::CloseCurrentPopup();
          setOpen(false);
        } else if (ret == 1) {
          ImGui::CloseCurrentPopup();
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }

  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/CommonUI/ObjectPicker.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/JumpToLabel.hpp"

struct Dialog_JumpToLabel : IEventDialogController {
  Dialog_JumpToLabel() = delete;
  explicit Dialog_JumpToLabel(const std::string& name, const std::shared_ptr<JumpToLabelCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new JumpToLabelCommand());
    }
    m_label = m_command->label;
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return m_command; };

private:
  std::string m_label;

  bool m_confirmed{false};
  std::shared_ptr<JumpToLabelCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_Label.hpp"

#include "Core/CommonUI/GroupBox.hpp"
#include "Core/ImGuiExt/ImGuiUtils.hpp"
#include "Database/Database.hpp"

#include <imgui.h>
#include <imgui_internal.h>

#include <tuple>

std::tuple<bool, bool> Dialog_Label::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###Label");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize =
      ImVec2{ImGui::CalcTextSize("#############################").x + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetFrameHeightWithSpacing() * 5) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});
  if (ImGui::BeginPopupModal(std::format("{}###Label", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    ImGui::BeginVertical("##label_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      GroupBox labelGroupBox(trNOOP("Label Name"), "##label_label_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiWindowFlags_AlwaysAutoResize);
      if (labelGroupBox.begin()) {
        ImGui::SetNextItemWidth(-1);
        ImGui::InputText("##label_input", &m_label);
      }
      labelGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##label_buttons_layout", {-1, -1}, 0);
      {
        ImGui::Spring();
        ImGui::SetNextItemWidth(-1);
        if (const auto ret = ImGui::ButtonGroup("##label_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->label = m_label;
          ImGui::CloseCurrentPopup();
          setOpen(false);
        } else if (ret == 1) {
          ImGui::CloseCurrentPopup();
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }

  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/CommonUI/ObjectPicker.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/Label.hpp"

struct Dialog_Label : IEventDialogController {
  Dialog_Label() = delete;
  explicit Dialog_Label(const std::string& name, const std::shared_ptr<LabelCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new LabelCommand());
    }
    m_label = m_command->label;
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return m_command; };

private:
  std::string m_label;

  bool m_confirmed{false};
  std::shared_ptr<LabelCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_Loop.hpp"
#include <tuple>

std::tuple<bool, bool> Dialog_Loop::draw() {
  if (isOpen()) {
    setOpen(false);
    m_confirmed = true;
  }
  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/EventDummy.hpp"
#include "Database/EventCommands/Loop.hpp"
#include "Database/EventCommands/RepeatAbove.hpp"

struct Dialog_Loop : IEventDialogController {
  Dialog_Loop() = delete;
  explicit Dialog_Loop(const std::string& name, const std::shared_ptr<LoopCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new LoopCommand());
    }
    m_open = false;
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return m_command; }

  std::vector<std::shared_ptr<IEventCommand>> getBatchCommands() override {
    std::vector<std::shared_ptr<IEventCommand>> eventCommands;
    std::shared_ptr<IEventCommand> sharedCommand = getCommand();
    eventCommands.push_back(sharedCommand);
    eventCommands.back()->setIndent(getParentIndent().value());
    eventCommands.push_back(std::make_shared<EventDummy>());
    eventCommands.back()->setIndent(getParentIndent().value() + 1);
    eventCommands.push_back(std::make_shared<RepeatAboveCommand>());
    eventCommands.back()->setIndent(getParentIndent().value());
    return eventCommands;
  }

private:
  bool m_confirmed{true};
  std::shared_ptr<LoopCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_MovePicture.hpp"

#include "Database/Database.hpp"
#include "imgui.h"
#include <tuple>

std::tuple<bool, bool> Dialog_MovePicture::draw() {
  if (isOpen()) {
    ImGui::OpenPopup(m_name.c_str());
  }
  ImVec2 center = ImGui::GetMainViewport()->GetCenter();
  ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  ImGui::SetNextWindowSize(ImVec2{400, 347}, ImGuiCond_Appearing);
  if (ImGui::BeginPopupModal(m_name.c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {

    if (picker) {
      auto [closed, confirmed] = picker->draw();
      if (closed) {
        if (confirmed) {
          if (xOrY)
            m_value2 = picker->selection();
          else
            m_value1 = picker->selection();
        }
        picker.reset();
      }
    }

    ImGui::SeparatorText("Picture");
    ImGui::BeginGroup();
    {
      ImGui::Text("Number:");
      ImGui::SetNextItemWidth(100);
      if (ImGui::InputInt("##movepicture_id", &m_number, 1, 100)) {
        if (m_number < 1)
          m_number = 1;
        if (m_number > 999)
          m_number = 999;
      }
      ImGui::EndGroup();
    }
    ImVec2 cursorPos = ImGui::GetCursorPos();
    ImGui::SeparatorText("Position and Scale");
    ImGui::Text("Origin:");
    ImGui::PushItemWidth((160));
    if (ImGui::BeginCombo("##movepicture_origin", DecodeEnumName(magic_enum::enum_value<PictureOrigin>(m_origin)).c_str())) {
      for (auto& origin : magic_enum::enum_values<PictureOrigin>()) {
        bool is_selected = m_origin == magic_enum::enum_index(origin).value();
        if (ImGui::Selectable(DecodeEnumName(magic_enum::enum_name(origin)).c_str(), is_selected)) {
          m_origin = magic_enum::enum_index(origin).value();
          if (is_selected)
            ImGui::SetItemDefaultFocus();
        }
      }
      ImGui::EndCombo();
    }
    // Direct Designation: Type 0
    ImGui::RadioButton("Direct Designation", &m_type, 0);
    ImGui::BeginGroup();
    {
      ImGui::Text("X:");
      ImGui::SetCursorPosY(ImGui::GetCursorPos().y + 8.f);
      ImGui::Text("Y:");
      ImGui::EndGroup();
    }
    ImGui::SameLine();
    ImGui::BeginGroup();
    {
      ImGui::BeginDisabled(m_type != 0);
      ImGui::SetNextItemWidth(100);
      ImGui::InputInt("##movepicture_directdesig_x", &m_constant1, 1, 100);
      ImGui::SetNextItemWidth(100);
      ImGui::InputInt("##movepicture_directdesig_y", &m_constant2, 1, 100);
      ImGui::EndDisabled();
      ImGui::EndGroup();
    }
    // Designation with Variables Type 1
    ImGui::RadioButton("Designation with variables", &m_type, 1);
    ImGui::BeginGroup();
    {
      ImGui::Text("X:");
      ImGui::SetCursorPosY(ImGui::GetCursorPos().y + 8.f);
      ImGui::Text("Y:");
      ImGui::EndGroup();
    }
    ImGui::SameLine();
    ImGui::BeginGroup();
    {
      ImGui::BeginDisabled(m_type != 1);
      ImGui::PushID("##movepicture_vardesig_x");
      if (ImGui::Button(m_type == 1 ? Database::instance()->variableNameOrId(m_value1).c_str() : "", ImVec2{((ImGui::GetWindowContentRegionMax().x / 2)) - 15, 0})) {
        xOrY = false;
        picker.emplace("Variables", Database::instance()->system.variables(), m_value1);
        picker->setOpen(true);
      }
      ImGui::PopID();
      ImGui::PushID("##movepicture_vardesig_y");
      if (ImGui::Button(m_type == 1 ? Database::instance()->variableNameOrId(m_value2).c_str() : "", ImVec2{((ImGui::GetWindowContentRegionMax().x / 2)) - 15, 0})) {
        xOrY = true;
        picker.emplace("Variables", Database::instance()->system.variables(), m_value2);
        picker->setOpen(true);
      }
      ImGui::PopID();
      ImGui::EndDisabled();
      ImGui::EndGroup();
    }
    ImGui::BeginGroup();
    {
      ImGui::SeparatorText("Duration");
      ImGui::SetNextItemWidth(100);
      if (ImGui::InputInt("##movepicture_duration", &m_duration)) {
        if (m_duration < 1)
          m_duration = 1;
        if (m_duration > 999)
          m_duration = 999;
      }
      ImGui::SameLine();
      ImGui::Text("frames 1/60 sec");
      ImGui::SameLine();
      // ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 80.f);
      ImGui::Checkbox("Wait for Completion", &m_waitForCompletion);

      ImGui::EndGroup();
    }
    // ImGui::SetCursorPosX(cursorPos.x);

    // Set Cursor
    ImGui::SetCursorPos(ImVec2(cursorPos.x + 235, cursorPos.y));
    ImGui::BeginGroup();
    {
      ImGui::SeparatorText("");
      ImGui::Text("Width %%");
      ImGui::SetNextItemWidth(100);
      if (ImGui::InputInt("##movepicture_width", &m_zoomX, 1, 100)) {
        if (m_zoomX < -2000)
          m_zoomX = -2000;
        if (m_zoomX > 2000)
          m_zoomX = 2000;
      }
      ImGui::Text("Height %%");
      ImGui::SetNextItemWidth(100);
      if (ImGui::InputInt("##movepicture_height", &m_zoomY, 1, 100)) {
        if (m_zoomY < -2000)
          m_zoomY = -2000;
        if (m_zoomY > 2000)
          m_zoomY = 2000;
      }
      ImGui::SeparatorText("Blend");
      ImGui::Text("Opacity:");
      ImGui::SetNextItemWidth(100);
      if (ImGui::InputInt("##movepicture_opacity", &m_opacityValue, 1, 100)) {
        if (m_opacityValue < 0)
          m_opacityValue = -0;
        if (m_opacityValue > 255)
          m_opacityValue = 255;
      }
      ImGui::PushItemWidth((75));
      if (ImGui::BeginCombo("##movepicture_blendmode", DecodeEnumName(magic_enum::enum_value<Blend>(m_blendMode)).c_str())) {
        for (auto& blend : magic_enum::enum_values<Blend>()) {
          bool is_selected = m_blendMode == magic_enum::enum_index(blend).value();
          if (ImGui::Selectable(DecodeEnumName(magic_enum::enum_name(blend)).c_str(), is_selected)) {
            m_blendMode = magic_enum::enum_index(blend).value();
            if (is_selected)
              ImGui::SetItemDefaultFocus();
          }
        }
        ImGui::EndCombo();
      }
    }
    ImGui::EndGroup();
    ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 80);
    ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 100);
    if (ImGui::Button("OK")) {
      m_confirmed = true;
      command->picture = m_number;
      command->origin = static_cast<PictureOrigin>(m_origin);
      command->pictureLocation = static_cast<PictureDesignationSource>(m_type);
      if (command->pictureLocation == PictureDesignationSource::Direct_designation) {
        command->x = m_constant1;
        command->y = m_constant2;
      } else {
        command->x = m_value1;
        command->y = m_value2;
      }
      command->width = m_zoomX;
      command->height = m_zoomY;
      command->opacity = m_opacityValue;
      command->blendMode = static_cast<Blend>(m_blendMode);
      command->duration = m_duration;
      command->waitForCompletion = m_waitForCompletion;
      ImGui::CloseCurrentPopup();
      setOpen(false);
    }
    ImGui::SameLine();
    if (ImGui::Button("Cancel")) {
      ImGui::CloseCurrentPopup();
      setOpen(false);
    }
    ImGui::EndPopup();
  }

  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/CommonUI/VariableSwitchPicker.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/MovePicture.hpp"
#include "Database/EventCommands/ShowPicture.hpp"

struct Dialog_MovePicture : IEventDialogController {
  Dialog_MovePicture() = delete;
  explicit Dialog_MovePicture(const std::string& name, const std::shared_ptr<MovePictureCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new MovePictureCommand());
    }
    m_number = command->picture;
    m_origin = static_cast<int>(command->origin);
    m_type = static_cast<int>(command->pictureLocation);
    m_value1 = command->x;
    m_value2 = command->y;
    m_zoomX = command->width;
    m_zoomY = command->height;
    m_opacityValue = command->opacity;
    m_blendMode = static_cast<int>(command->blendMode);
    m_duration = command->duration;
    m_waitForCompletion = command->waitForCompletion;
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return command; };

private:
  int m_number;
  int m_origin;
  int m_type;
  int m_value1; // direct X value or indirect from global variables
  int m_value2; // direct Y value or indirect from global variables
  int m_zoomX;
  int m_zoomY;
  int m_opacityValue;
  int m_blendMode;
  int m_duration;
  bool m_waitForCompletion;

  bool xOrY{false};
  int m_constant1{0};
  int m_constant2{0};

  bool m_confirmed{false};
  std::optional<VariableSwitchPicker> picker;
  std::shared_ptr<MovePictureCommand> command;
  std::tuple<bool, bool> result;
};


code:
#include "Core/EventCommands/Dialog_NameInputProcessing.hpp"

#include "Core/CommonUI/GroupBox.hpp"
#include "Core/ImGuiExt/ImGuiUtils.hpp"
#include "Database/Database.hpp"

#include <imgui.h>
#include <imgui_internal.h>
#include <tuple>

void Dialog_NameInputProcessing::drawPickers() {
  if (m_actorPicker) {
    if (const auto [closed, confirmed] = m_actorPicker->draw(); closed) {
      if (confirmed) {
        m_actor = m_actorPicker->selection();
      }
      m_actorPicker.reset();
    }
  }
}
std::tuple<bool, bool> Dialog_NameInputProcessing::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###NameInputProcessing");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 30) + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetFrameHeightWithSpacing() * 7) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});

  if (ImGui::BeginPopupModal(std::format("{}###NameInputProcessing", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    drawPickers();

    ImGui::BeginVertical("##name_input_processing_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      GroupBox actorGroupBox(trNOOP("Actor"), "##name_input_processing_actor_group", {-1, 0});
      if (actorGroupBox.begin()) {
        if (ImGui::EllipsesButton(Database::instance()->actorNameAndId(m_actor).c_str(), ImVec2{-1, 0})) {
          m_actorPicker = ObjectPicker(trNOOP("Actor"), Database::instance()->actors.actorList(), m_actor);
          m_actorPicker->setOpen(true);
        }
      }
      actorGroupBox.end();
      GroupBox maxCharGroupBox(trNOOP("Max characters"), "##name_input_processing_max_char_group", {-1, 0});
      if (maxCharGroupBox.begin()) {
        ImGui::SetNextItemWidth(-1);
        if (ImGui::SpinInt("##name_input_processing_max_chars", &m_maxChar, 1, 1)) {
          m_maxChar = std::clamp(m_maxChar, 1, 16);
        }
      }
      maxCharGroupBox.end();

      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##name_input_processing_button_layout", {-1, 0}, 0);
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##name_input_processing_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->actorId = m_actor;
          m_command->maxChar = m_maxChar;
          ImGui::CloseCurrentPopup();
          setOpen(false);
        } else if (ret == 1) {
          ImGui::CloseCurrentPopup();
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();

    ImGui::EndPopup();
  }

  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/CommonUI/ObjectPicker.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"

#include "Database/Actor.hpp"
#include "Database/EventCommands/NameInput.hpp"

struct Dialog_NameInputProcessing : IEventDialogController {
  Dialog_NameInputProcessing() = delete;
  explicit Dialog_NameInputProcessing(const std::string& name, const std::shared_ptr<NameInputCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new NameInputCommand());
    }
    m_actor = m_command->actorId;
    m_maxChar = m_command->maxChar;
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return m_command; };

private:
  void drawPickers();

  int m_actor;
  int m_maxChar;

  bool m_confirmed{false};
  std::optional<ObjectPicker<Actor>> m_actorPicker;
  std::shared_ptr<NameInputCommand> m_command;
  std::tuple<bool, bool> m_result;
};


code:
#include "Core/EventCommands/Dialog_OpenMenuScreen.hpp"
#include <tuple>

std::tuple<bool, bool> Dialog_OpenMenuScreen::draw() {
  if (isOpen()) {
    setOpen(false);
    m_confirmed = true;
  }
  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/OpenMenu.hpp"

struct Dialog_OpenMenuScreen : IEventDialogController {
  Dialog_OpenMenuScreen() = delete;
  explicit Dialog_OpenMenuScreen(const std::string& name, const std::shared_ptr<OpenMenuCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new OpenMenuCommand());
    }
    m_open = false;
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return command; };

private:
  bool m_confirmed{true};
  std::shared_ptr<OpenMenuCommand> command;
  std::tuple<bool, bool> result;
};


code:
#include "Core/EventCommands/Dialog_OpenSaveScreen.hpp"
#include <tuple>

std::tuple<bool, bool> Dialog_OpenSaveScreen::draw() {
  if (isOpen()) {
    setOpen(false);
    m_confirmed = true;
  }
  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/OpenSave.hpp"

struct Dialog_OpenSaveScreen : IEventDialogController {
  Dialog_OpenSaveScreen() = delete;
  explicit Dialog_OpenSaveScreen(const std::string& name, const std::shared_ptr<OpenSaveCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new OpenSaveCommand());
    }
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return command; };

private:
  bool m_confirmed{true};
  std::shared_ptr<OpenSaveCommand> command;
  std::tuple<bool, bool> result;
};


code:
#include "Core/EventCommands/Dialog_PlayBGM.hpp"

std::tuple<bool, bool> Dialog_PlayBGM::draw() {
  if (const auto [closed, confirmed] = m_audioRenderer.value().draw(m_name, "PlayBGM"); closed) {
    m_confirmed = confirmed;
    setOpen(false);
  }
  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Core/Log.hpp"
#include "Core/ResourceManager.hpp"
#include "Core/Settings.hpp"

#include "Core/CommonUI/AudioEditor.hpp"
#include "Core/CommonUI/Directory.hpp"
#include "Core/Sound.hpp"
#include "Database/Database.hpp"
#include "Database/EventCommands/PlayBGM.hpp"

#include <iostream>

namespace fs = std::filesystem;
struct Dialog_PlayBGM : IEventDialogController {
  Dialog_PlayBGM() = delete;
  explicit Dialog_PlayBGM(const std::string& name, const std::shared_ptr<PlayBGMCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new PlayBGMCommand());
    }
    m_audioRenderer.emplace(m_command->code(), m_command->audio);
  }
  std::tuple<bool, bool> draw() override;
  [[nodiscard]] std::shared_ptr<IEventCommand> getCommand() override { return m_command; }

  void setOpen(const bool open) override {
    IEventDialogController::setOpen(open);
    m_audioRenderer->setOpen(open);
  }

private:
  bool m_confirmed{false};
  std::optional<AudioEditor> m_audioRenderer;
  std::shared_ptr<PlayBGMCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_PlayBGS.hpp"

std::tuple<bool, bool> Dialog_PlayBGS::draw() {
  if (const auto [closed, confirmed] = m_audioRenderer.value().draw(m_name, "PlayBGS"); closed) {
    m_confirmed = confirmed;
    setOpen(false);
  }

  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/CommonUI/AudioEditor.hpp"
#include "Core/CommonUI/Directory.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Core/Log.hpp"
#include "Core/ResourceManager.hpp"
#include "Core/Settings.hpp"
#include "Core/Sound.hpp"
#include "Database/Database.hpp"
#include "Database/EventCommands/PlayBGS.hpp"
#include <iostream>
#include <SFML/Audio.hpp>

namespace fs = std::filesystem;
struct Dialog_PlayBGS : IEventDialogController {
  Dialog_PlayBGS() = delete;
  explicit Dialog_PlayBGS(const std::string& name, const std::shared_ptr<PlayBGSCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new PlayBGSCommand());
    }
    m_audioRenderer.emplace(m_command->code(), m_command->audio);
  }
  std::tuple<bool, bool> draw() override;
  [[nodiscard]] std::shared_ptr<IEventCommand> getCommand() override { return m_command; }

  void setOpen(const bool open) override {
    IEventDialogController::setOpen(open);
    m_audioRenderer->setOpen(open);
  }

private:
  bool m_confirmed{false};
  std::optional<AudioEditor> m_audioRenderer;
  std::shared_ptr<PlayBGSCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_PlayME.hpp"

std::tuple<bool, bool> Dialog_PlayME::draw() {
  if (const auto [closed, confirmed] = m_audioRenderer.value().draw(m_name, "PlayME"); closed) {
    m_confirmed = confirmed;
    setOpen(false);
  }

  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/CommonUI/AudioEditor.hpp"
#include "Core/CommonUI/Directory.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Core/Log.hpp"
#include "Core/ResourceManager.hpp"
#include "Core/Settings.hpp"
#include "Core/Sound.hpp"
#include "Database/Database.hpp"
#include "Database/EventCommands/PlayME.hpp"
#include <iostream>
#include <SFML/Audio.hpp>

namespace fs = std::filesystem;
struct Dialog_PlayME : IEventDialogController {
  Dialog_PlayME() = delete;
  explicit Dialog_PlayME(const std::string& name, const std::shared_ptr<PlayMECommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new PlayMECommand());
    }
    m_audioRenderer.emplace(m_command->code(), m_command->audio);
  }
  std::tuple<bool, bool> draw() override;
  [[nodiscard]] std::shared_ptr<IEventCommand> getCommand() override { return m_command; }

  void setOpen(const bool open) override {
    IEventDialogController::setOpen(open);
    m_audioRenderer->setOpen(open);
  }

private:
  bool m_confirmed{false};
  std::shared_ptr<PlayMECommand> m_command;
  std::optional<AudioEditor> m_audioRenderer;
};


code:
#include "Core/EventCommands/Dialog_PlayMovie.hpp"

#include "Core/ImGuiExt/ImGuiUtils.hpp"
#include "imgui.h"
#include <tuple>

#include "imgui_internal.h"
#include <IconsFontAwesome6.h>

std::tuple<bool, bool> Dialog_PlayMovie::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###PlayMovie");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 32) + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetTextLineHeightWithSpacing() * 19) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});
  if (ImGui::BeginPopupModal(std::format("{}###PlayMovie", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {

    ImGui::BeginVertical("##play_move_main_layout", ImGui::GetContentRegionAvail());
    {
      ImGui::BeginVertical("##play_move_file_list_layout", {-1, 0});
      {
        if (ImGui::BeginTable("##movie_contents", 1, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY,
                              ImVec2{-1, ImGui::GetTextLineHeightWithSpacing() * 16})) {

          ImGui::TableSetupScrollFreeze(1, 0);
          ImGui::TableSetupColumn(trNOOP("File"));
          ImGui::TableNextRow();
          ImGui::TableNextColumn();

          ImGui::BeginDisabled(m_movieDir.value().isParentDirectory());
          if (ImGui::Selectable("\u21B0 ..", false, static_cast<int>(ImGuiSelectableFlags_SelectOnNav) | ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SelectOnClick)) {
            if (ImGui::GetMouseClickedCount(ImGuiMouseButton_Left) >= 2) {
              m_movieDir.value().moveUp();
              m_movies = m_movieDir->getDirectoryContents();
              m_folders = m_movieDir.value().getDirectories();
              m_selected = 0;
              m_selectedFolder = -1;
            }
          }
          ImGui::EndDisabled();
          for (int i = 0; i < m_folders.size(); ++i) {
            const auto& folderName = std::format("{} {}", ICON_FA_FOLDER_OPEN, m_folders[i]);
            if (ImGui::Selectable(folderName.c_str(), m_selectedFolder == i,
                                  static_cast<int>(ImGuiSelectableFlags_SelectOnNav) | ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SelectOnClick)) {
              m_selectedFolder = i;
            }
            if (m_selectedFolder == i && ImGui::GetMouseClickedCount(ImGuiMouseButton_Left) >= 2) {
              m_movieDir->setDirectory(i);
              m_folders = m_movieDir.value().getDirectories();
              m_movies = m_movieDir.value().getDirectoryContents();
              m_selected = 0;
              m_selectedFolder = -1;
            }
          }

          if (ImGui::SelectableWithBorder(trNOOP("None"), m_selected == 0, ImGuiSelectableFlags_AllowOverlap | ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick)) {
            if (ImGui::GetMouseClickedCount(ImGuiMouseButton_Left) >= 2) {
              m_confirmed = true;
              m_command->name = m_movie;
              ImGui::CloseCurrentPopup();
              setOpen(false);
            }
            m_selected = 0;
            m_movie = "";
          }
          if (m_selected == 0) {
            ImGui::SetItemDefaultFocus();
          }

          for (int n = 0; n < m_movies.size(); n++) {
            ImGui::TableNextColumn();
            const bool isSelected = (m_selected == n + 1);
            if (ImGui::SelectableWithBorder(m_movies.at(n).c_str(), isSelected, ImGuiSelectableFlags_AllowOverlap | ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick)) {
              if (ImGui::GetMouseClickedCount(ImGuiMouseButton_Left) >= 2) {
                m_confirmed = true;
                m_command->name = m_movie;
                ImGui::CloseCurrentPopup();
                setOpen(false);
              }
              m_selected = n + 1;
              m_movie = m_movies.at(m_selected - 1);
              if (isSelected)
                ImGui::SetItemDefaultFocus();
            }
          }
          ImGui::EndTable();
        }
      }
      ImGui::EndVertical();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##play_movie_buttons_layout", {-1, -1});
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##play_movie_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->name = m_movie;
          ImGui::CloseCurrentPopup();
          setOpen(false);
        } else if (ret == 1) {
          ImGui::CloseCurrentPopup();
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }

  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/CommonUI/Directory.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Core/Log.hpp"
#include "Core/Settings.hpp"
#include "Database/Database.hpp"
#include "Database/EventCommands/PlayMovie.hpp"

#include <iostream>

namespace fs = std::filesystem;
struct Dialog_PlayMovie : IEventDialogController {
  Dialog_PlayMovie() = delete;
  explicit Dialog_PlayMovie(const std::string& name, const std::shared_ptr<PlayMovieCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (!m_command) {
      m_command = std::make_shared<PlayMovieCommand>();
    }
    m_movieDir.emplace("movies", ".mp4", m_command->name); // TODO: Add multiple filter format, include .webm
    m_movies = m_movieDir.value().getDirectoryContents();
    m_folders = m_movieDir.value().getDirectories();
  }
  std::tuple<bool, bool> draw() override;
  [[nodiscard]] std::shared_ptr<IEventCommand> getCommand() override { return m_command; }

  bool playMovie(const char* path) {

    // TODO

    // if (!buffer.loadFromFile(Database::instance()->basePath + path + m_movieDir.value().extFilter)) {
    //   // error loading file
    //   return false;
    // }
    return false;
  }

private:
  bool m_confirmed{false};

  int m_selected = 0;
  std::string m_movie;

  std::shared_ptr<PlayMovieCommand> m_command;
  std::tuple<bool, bool> result;
  std::vector<std::string> m_movies;

  int m_selectedFolder{-1};
  std::optional<Directory> m_movieDir;
  std::vector<std::string> m_folders;
};


code:
#include "Core/EventCommands/Dialog_PlaySE.hpp"

std::tuple<bool, bool> Dialog_PlaySE::draw() {
  if (const auto [closed, confirmed] = m_audioRenderer.value().draw(m_name, "PlaySE"); closed) {
    m_confirmed = confirmed;
    setOpen(false);
  }
  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/CommonUI/AudioEditor.hpp"
#include "Core/CommonUI/Directory.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Core/Log.hpp"
#include "Core/ResourceManager.hpp"
#include "Core/Settings.hpp"
#include "Core/Sound.hpp"
#include "Database/Database.hpp"
#include "Database/EventCommands/PlaySE.hpp"
#include <iostream>
#include <SFML/Audio.hpp>

namespace fs = std::filesystem;
struct Dialog_PlaySE : IEventDialogController {
  Dialog_PlaySE() = delete;
  explicit Dialog_PlaySE(const std::string& name, const std::shared_ptr<PlaySECommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new PlaySECommand());
    }
    m_audioRenderer.emplace(m_command->code(), m_command->audio);
  }
  std::tuple<bool, bool> draw() override;
  [[nodiscard]] std::shared_ptr<IEventCommand> getCommand() override { return m_command; }

  void setOpen(const bool open) override {
    IEventDialogController::setOpen(open);
    m_audioRenderer->setOpen(open);
  }

private:
  bool m_confirmed{false};
  std::optional<AudioEditor> m_audioRenderer;
  std::shared_ptr<PlaySECommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_RecoverAll.hpp"

#include "Database/Database.hpp"

#include "Core/CommonUI/GroupBox.hpp"
#include "Core/ImGuiExt/ImGuiUtils.hpp"

#include <imgui.h>
#include <imgui_internal.h>

#include <tuple>

std::tuple<bool, bool> Dialog_RecoverAll::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###RecoverAll");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize =
      ImVec2{ImGui::CalcTextSize("#############################").x + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetFrameHeightWithSpacing() * 6) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});

  if (ImGui::BeginPopupModal(std::format("{}###RecoverAll", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    drawPickers();
    ImGui::BeginVertical("##recover_all_main_layout", ImGui::GetContentRegionAvail());
    {
      GroupBox actorGroupBox(trNOOP("Actor"), "##recover_all_actor_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (actorGroupBox.begin()) {
        ImGui::BeginHorizontal("##recover_all_actor_layout");
        {
          ImGui::BeginVertical("##recover_all_actor_source_layout", {-1, -1});
          {
            ImGui::RadioButton(trNOOP("Fixed"), &m_source, 0);
            ImGui::RadioButton(trNOOP("Variable"), &m_source, 1);
          }
          ImGui::EndVertical();

          ImGui::BeginVertical("##recover_all_source_layout", {-1, -1});
          {
            // Actor Button
            ImGui::BeginDisabled(m_source != 0);
            ImGui::SetNextItemWidth(-1);
            std::string text = m_source != 0 ? "##recover_all_actor_empty" : Database::instance()->actorNameAndId(m_actor);
            ImGui::PushID("##recover_all_selection_actor");
            if (ImGui::EllipsesButton(text.c_str(), ImVec2{-1, 0})) {
              m_actorPicker = ObjectPicker(trNOOP("Actor"), Database::instance()->actors.actorList(), m_actor);
              m_actorPicker->setUseDummyEntry(trNOOP("Entire Party"));
              m_actorPicker->setOpen(true);
            }
            ImGui::PopID();
            ImGui::EndDisabled();

            // Variable Button
            ImGui::BeginDisabled(m_source != 1);
            ImGui::SetNextItemWidth(100);
            text = m_source != 1 ? "##recover_all_variable_empty" : Database::instance()->variableNameAndId(m_variable);
            ImGui::PushID("##recover_all_variable");
            if (ImGui::EllipsesButton(text.c_str(), ImVec2{-1, 0})) {
              m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_variable);
              m_variablePicker->setOpen(true);
            }
            ImGui::PopID();
            ImGui::EndDisabled();
          }
          ImGui::EndVertical();
        }
        ImGui::EndHorizontal();
      }
      actorGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5));
      ImGui::BeginHorizontal("##recover_all_buttons", {-1, -1});
      {
        ImGui::Spring();

        if (const auto ret = ImGui::ButtonGroup("##recover_all_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->comparison = static_cast<ActorComparisonSource>(m_source);
          if (m_command->comparison == ActorComparisonSource::Fixed) {
            m_command->value = m_actor;
          } else {
            m_command->value = m_variable;
          }
          ImGui::CloseCurrentPopup();
          setOpen(false);
        } else if (ret == 1) {
          ImGui::CloseCurrentPopup();
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }

  return std::make_tuple(!m_open, m_confirmed);
}

void Dialog_RecoverAll::drawPickers() {
  if (m_variablePicker) {
    if (const auto [closed, confirmed] = m_variablePicker->draw(); closed) {
      if (confirmed) {
        m_variable = m_variablePicker->selection();
      }
      m_variablePicker.reset();
    }
  }
  if (m_actorPicker) {
    auto [closed, confirmed] = m_actorPicker->draw();
    if (closed) {
      if (confirmed) {
        m_actor = m_actorPicker->selection();
      }
      m_actorPicker.reset();
    }
  }
}


code:
#pragma once
#include "Core/CommonUI/ObjectPicker.hpp"
#include "Core/CommonUI/VariableSwitchPicker.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"

#include "Database/Actor.hpp"
#include "Database/EventCommands/RecoverAll.hpp"

struct Dialog_RecoverAll : IEventDialogController {
  Dialog_RecoverAll() = delete;
  explicit Dialog_RecoverAll(const std::string& name, const std::shared_ptr<RecoverAllCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new RecoverAllCommand());
    }
    m_actor = m_command->value;
    m_variable = m_command->value;
    m_source = static_cast<int>(m_command->comparison);
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return m_command; };

private:
  void drawPickers();
  int m_actor;
  int m_variable;
  int m_source;

  bool m_confirmed{false};
  std::optional<ObjectPicker<Actor>> m_actorPicker;
  std::optional<VariableSwitchPicker> m_variablePicker;
  std::shared_ptr<RecoverAllCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_ReplayBGM.hpp"
#include <tuple>

std::tuple<bool, bool> Dialog_ReplayBGM::draw() {
  if (isOpen()) {
    setOpen(false);
    m_confirmed = true;
  }
  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/ResumeBGM.hpp"

struct Dialog_ReplayBGM : IEventDialogController {
  Dialog_ReplayBGM() = delete;
  explicit Dialog_ReplayBGM(const std::string& name, const std::shared_ptr<ResumeBGMCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new ResumeBGMCommand());
    }
    m_open = false;
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return command; };

private:
  bool m_confirmed{true};
  std::shared_ptr<ResumeBGMCommand> command;
  std::tuple<bool, bool> result;
};


code:
#include "Core/EventCommands/Dialog_ReturnToTitle.hpp"
#include <tuple>

std::tuple<bool, bool> Dialog_ReturnToTitle::draw() {
  if (isOpen()) {
    setOpen(false);
    m_confirmed = true;
  }
  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/ReturnToTitle.hpp"

struct Dialog_ReturnToTitle : IEventDialogController {
  Dialog_ReturnToTitle() = delete;
  explicit Dialog_ReturnToTitle(const std::string& name, const std::shared_ptr<ReturnToTitleCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ReturnToTitleCommand());
    }
    m_open = false;
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return m_command; };

private:
  std::shared_ptr<ReturnToTitleCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_RotatePicture.hpp"

#include "imgui.h"
#include <tuple>

std::tuple<bool, bool> Dialog_RotatePicture::draw() {
  if (isOpen()) {
    ImGui::OpenPopup(m_name.c_str());
  }
  ImVec2 center = ImGui::GetMainViewport()->GetCenter();
  ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  ImGui::SetNextWindowSize(ImVec2{131, 140}, ImGuiCond_Appearing);
  if (ImGui::BeginPopupModal(m_name.c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {

    ImGui::SeparatorText("Picture Number");
    ImGui::SetNextItemWidth(120);
    if (ImGui::InputInt("##rotatepicture_id", &m_picture)) {
      if (m_picture > 999) {
        m_picture = 999;
      } else if (m_picture < 1)
        m_picture = 1;
    }
    ImGui::SeparatorText("Rotation Speed   ");
    ImGui::SetNextItemWidth(120);
    if (ImGui::InputInt("##rotatepicture_speed", &m_rotation)) {
      if (m_rotation > 999) {
        m_rotation = 999;
      } else if (m_rotation < 1)
        m_rotation = 1;
    }

    if (ImGui::Button("OK")) {
      m_confirmed = true;
      command->picture = m_picture;
      command->rotation = m_rotation;
      ImGui::CloseCurrentPopup();
      setOpen(false);
    }
    ImGui::SameLine();
    if (ImGui::Button("Cancel")) {
      ImGui::CloseCurrentPopup();
      setOpen(false);
    }
    ImGui::EndPopup();
  }

  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/RotatePicture.hpp"

struct Dialog_RotatePicture : IEventDialogController {
  Dialog_RotatePicture() = delete;
  explicit Dialog_RotatePicture(const std::string& name, const std::shared_ptr<RotatePictureCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new RotatePictureCommand());
    }
    m_picture = command->picture;
    m_rotation = command->rotation;
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return command; };

private:
  bool m_confirmed{false};
  int m_picture;
  int m_rotation;
  std::shared_ptr<RotatePictureCommand> command;
  std::tuple<bool, bool> result;
};


code:
#include "Core/EventCommands/Dialog_SaveBGM.hpp"
#include <tuple>

std::tuple<bool, bool> Dialog_SaveBGM::draw() {
  if (isOpen()) {
    setOpen(false);
    m_confirmed = true;
  }

  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/SaveBGM.hpp"

struct Dialog_SaveBGM : IEventDialogController {
  Dialog_SaveBGM() = delete;
  explicit Dialog_SaveBGM(const std::string& name, const std::shared_ptr<SaveBGMCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new SaveBGMCommand());
    }
    m_open = false;
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return command; };

private:
  bool m_confirmed{true};
  std::shared_ptr<SaveBGMCommand> command;
  std::tuple<bool, bool> result;
};


code:
#include "Core/EventCommands/Dialog_Script.hpp"
#include "Core/Application.hpp"
#include "Core/ImGuiExt/ImGuiUtils.hpp"

#include <imgui.h>
#include <imgui_internal.h>

std::tuple<bool, bool> Dialog_Script::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###Script");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 40) + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetFrameHeightWithSpacing() * 12) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});

  if (ImGui::BeginPopupModal(std::format("{}###Script", m_name).c_str(), &m_open)) {
    ImGui::BeginVertical("##script_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      ImGui::PushFont(App::APP->getMonoFont());
      m_textEditor.Render("TextEditor", {0, ImGui::GetContentRegionAvail().y - ImGui::GetFrameHeightWithSpacing()}, true);
      ImGui::PopFont();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##script_buttons_layout", {-1, 0}, 0);
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##script_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          const auto script = m_textEditor.GetText();
          std::vector<std::string> scripts = splitString(script, '\n');

          m_command->script = scripts.front();
          if (scripts.size() > 1) {
            m_command->moreScript.clear();
            m_command->moreScript.reserve(scripts.size());
            for (auto str = std::next(scripts.begin()); str != scripts.end(); ++str) {
              m_command->moreScript.emplace_back(std::make_shared<NextScriptCommand>())->script = *str;
              m_command->moreScript.back()->setIndent(m_command->indent().value());
            }
            m_command->moreScript.shrink_to_fit();
          }
          ImGui::CloseCurrentPopup();
          setOpen(false);
          m_confirmed = true;
        } else if (ret == 1) {
          ImGui::CloseCurrentPopup();
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }

  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/CommonUI/TextEditor.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/Script.hpp"

struct Dialog_Script : IEventDialogController {
  Dialog_Script() = delete;
  explicit Dialog_Script(const std::string& name, const std::shared_ptr<ScriptCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ScriptCommand());
    }
    std::string text = m_command->script;
    for (const auto& next : m_command->moreScript) {
      text += !text.empty() ? "\n" + next->script : next->script;
    }
    if (!text.empty()) {
      m_textEditor.SetText(text);
    }
    m_textEditor.SetLanguageDefinition(TextEditor::LanguageDefinition::Javascript());
    m_textEditor.SetHandleKeyboardInputs(true);
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return m_command; };

private:
  TextEditor m_textEditor;
  bool m_confirmed{false};
  std::shared_ptr<ScriptCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_ScrollMap.hpp"

#include "imgui.h"
#include <tuple>

std::tuple<bool, bool> Dialog_ScrollMap::draw() {
  if (isOpen()) {
    ImGui::OpenPopup(m_name.c_str());
  }
  ImVec2 center = ImGui::GetMainViewport()->GetCenter();
  ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  ImGui::SetNextWindowSize(ImVec2{0, 0}, ImGuiCond_Appearing);
  if (ImGui::BeginPopupModal(m_name.c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    const auto buttonsSize = ImGui::CalcTextSize("OKCANCEL");
    ImGui::SeparatorText("Direction                Distance");

    ImGui::PushItemWidth(ImGui::GetContentRegionMax().x / 2);

    auto dir = magic_enum::enum_cast<Direction>(m_direction);
    if (ImGui::BeginCombo("##scrollmap_direction", DecodeEnumName(magic_enum::enum_name(dir.value())).c_str())) {
      for (auto& direction : magic_enum::enum_values<Direction>()) {
        if (magic_enum::enum_integer(direction) == 0)
          continue;

        bool is_selected = m_direction == magic_enum::enum_integer(direction);
        if (ImGui::Selectable(DecodeEnumName(magic_enum::enum_name(direction)).c_str(), is_selected)) {
          m_direction = magic_enum::enum_integer(direction);
          if (is_selected)
            ImGui::SetItemDefaultFocus();
        }
      }
      ImGui::EndCombo();
    }
    ImGui::SameLine();

    ImGui::SetNextItemWidth(ImGui::GetContentRegionMax().x - ImGui::GetStyle().FramePadding.x * 14);
    if (ImGui::InputInt("##scrollmap_distance", &m_distance, 0)) {
      if (m_distance > 100) {
        m_distance = 100;
      } else if (m_distance < 1)
        m_distance = 1;
    }

    ImGui::SeparatorText("Speed");
    ImGui::PushItemWidth(180);

    if (ImGui::BeginCombo("##scrollmap_speed", DecodeEnumName(static_cast<MovementSpeed>(m_speed)).c_str())) {
      for (auto& speed : magic_enum::enum_values<MovementSpeed>()) {

        bool is_selected = m_speed == magic_enum::enum_integer(speed);
        if (ImGui::Selectable(DecodeEnumName(magic_enum::enum_name(speed)).c_str(), is_selected)) {
          m_speed = magic_enum::enum_integer(speed);
          if (is_selected)
            ImGui::SetItemDefaultFocus();
        }
      }
      ImGui::EndCombo();
    }
    ImGui::BeginGroup();
    {
      ImGui::SetCursorPosX(ImGui::GetContentRegionMax().x - (buttonsSize.x + (ImGui::GetStyle().FramePadding.x * 4) + ImGui::GetStyle().ItemSpacing.x));
      if (ImGui::Button("OK")) {
        m_confirmed = true;
        command->direction = static_cast<Direction>(m_direction);
        command->distance = m_distance;
        command->speed = static_cast<MovementSpeed>(m_speed);

        ImGui::CloseCurrentPopup();
        setOpen(false);
      }
      ImGui::SameLine();
      if (ImGui::Button("Cancel")) {
        ImGui::CloseCurrentPopup();
        setOpen(false);
      }
    }
    ImGui::EndGroup();
    ImGui::EndPopup();
  }

  return std::make_tuple(!m_open, m_confirmed);
}


code:
#pragma once
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/ScrollMap.hpp"

struct Dialog_ScrollMap : IEventDialogController {
  Dialog_ScrollMap() = delete;
  explicit Dialog_ScrollMap(const std::string& name, const std::shared_ptr<ScrollMapCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new ScrollMapCommand());
    }

    m_direction = static_cast<int>(command->direction);
    m_distance = command->distance;
    m_speed = static_cast<int>(command->speed);
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return command; };

private:
  int m_direction;
  int m_distance;
  int m_speed;

  bool m_confirmed{false};
  std::shared_ptr<ScrollMapCommand> command;
  std::tuple<bool, bool> result;
};


code:
#include "Core/EventCommands/Dialog_SelectItem.hpp"

#include "Core/CommonUI/GroupBox.hpp"
#include "Core/ImGuiExt/ImGuiUtils.hpp"
#include "Database/Database.hpp"

#include <imgui.h>
#include <imgui_internal.h>
#include <tuple>

std::tuple<bool, bool> Dialog_SelectItem::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###SelectItem");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 30) + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetFrameHeightWithSpacing() * 7) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});

  if (ImGui::BeginPopupModal(std::format("{}###SelectItem", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    drawPickers();
    ImGui::BeginVertical("##select_item_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      GroupBox variableGroupBox(trNOOP("Variable"), "##select_item_variable_group_box", {-1, 0});
      if (variableGroupBox.begin()) {
        if (ImGui::EllipsesButton(Database::instance()->variableNameAndId(m_variable).c_str(), {-1, 0})) {
          m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_variable);
          m_variablePicker->setOpen(true);
        }
      }
      variableGroupBox.end();
      GroupBox itemTypeGroupBox(trNOOP("Item Type"), "##input_number_item_type_group_box", {-1, 0});
      if (itemTypeGroupBox.begin()) {
        ImGui::SetNextItemWidth(-1);
        if (ImGui::BeginCombo("##input_number_item_type_selection", DecodeEnumName(magic_enum::enum_cast<ItemType>(m_type).value_or(ItemType::Key_Item)).c_str())) {
          for (const auto& itemType : magic_enum::enum_values<ItemType>()) {
            bool selected = m_type == static_cast<int>(itemType);
            if (ImGui::Selectable(DecodeEnumName(itemType).c_str(), selected)) {
              m_type = static_cast<int>(itemType);
            }
            if (selected) {
              ImGui::SetItemDefaultFocus();
            }
          }
          ImGui::EndCombo();
        }
      }
      itemTypeGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##select_item_button_layout");
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##select_item_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->item = m_variable;
          m_command->type = static_cast<ItemType>(m_type);
          ImGui::CloseCurrentPopup();
          setOpen(false);
        } else if (ret == 1) {
          ImGui::CloseCurrentPopup();
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }

  return std::make_tuple(!m_open, m_confirmed);
}

void Dialog_SelectItem::drawPickers() {
  if (m_variablePicker) {
    if (const auto [closed, confirmed] = m_variablePicker->draw(); closed) {
      if (confirmed) {
        m_variable = m_variablePicker->selection();
      }
      m_variablePicker.reset();
    }
  }
}


code:
#pragma once
#include "Core/CommonUI/VariableSwitchPicker.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/InputNumber.hpp"
#include "Database/EventCommands/SelectItem.hpp"

struct Dialog_SelectItem : IEventDialogController {
  Dialog_SelectItem() = delete;
  explicit Dialog_SelectItem(const std::string& name, const std::shared_ptr<SelectItemCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new SelectItemCommand());
    }
    m_variable = m_command->item;
    m_type = static_cast<int>(m_command->type);
  }
  void drawPickers();
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return m_command; };

private:
  int m_variable;
  int m_type;

  bool m_confirmed{false};
  std::optional<VariableSwitchPicker> m_variablePicker;
  std::shared_ptr<SelectItemCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_SetEventLocation.hpp"

#include "Core/CommonUI/GroupBox.hpp"
#include "Core/ImGuiExt/ImGuiUtils.hpp"
#include "Database/Database.hpp"
#include <imgui.h>
#include <imgui_internal.h>

#include <tuple>

std::tuple<bool, bool> Dialog_SetEventLocation::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###SetEventLocation");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 40) + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetFrameHeightWithSpacing() * 18) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});

  if (ImGui::BeginPopupModal(std::format("{}###SetEventLocation", m_name).c_str(), &m_open, ImGuiWindowFlags_NoResize)) {
    drawPickers();
    ImGui::BeginVertical("##set_event_location_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      GroupBox eventGroup(trNOOP("Event"), "##set_event_location_event_group", {-1, 0});
      if (eventGroup.begin()) {
        ImGui::SetNextItemWidth(-1);
        if (ImGui::BeginCombo("##set_event_location_event_list", Database::instance()->eventNameOrId(m_event).c_str())) {
          for (int i = 0; i < Database::instance()->mapInfos.currentMap()->map()->events().size(); ++i) {
            if (i > 0 && !Database::instance()->mapInfos.currentMap()->map()->event(i)) {
              continue;
            }

            if (ImGui::Selectable(Database::instance()->eventNameOrId(i).c_str(), i == m_event)) {
              m_event = i;
            }

            if (i == m_event) {
              ImGui::SetItemDefaultFocus();
            }
          }
          ImGui::EndCombo();
        }
      }
      eventGroup.end();
      GroupBox locationGroup(trNOOP("Location"), "##set_event_location_location_group", {-1, 0});
      if (locationGroup.begin()) {
        ImGui::RadioButton(trNOOP("Direct Designation"), &m_mode, 0);
        ImGui::Dummy({ImGui::GetFrameHeight(), ImGui::GetFrameHeight()});
        ImGui::SameLine();
        ImGui::BeginDisabled(m_mode != 0);
        {
          ImGui::PushID("#transfer_coord_selection");
          if (ImGui::EllipsesButton(m_mode == 0 ? std::format("{} ({},{})", Database::instance()->mapNameOrId(Database::instance()->mapInfos.currentMap()->id()), m_x, m_y).c_str() : "",
                                    ImVec2{-1, 0})) {
            m_eventTilePicker.emplace(Database::instance()->mapInfos.currentMap()->id(), false);
            m_eventTilePicker->setOpen(true);
          }
          ImGui::PopID();
        }
        ImGui::EndDisabled();
        ImGui::RadioButton(trNOOP("Designation with variables"), &m_mode, 1);
        ImGui::BeginDisabled(m_mode != 1);
        {
          ImGui::BeginHorizontal("##set_event_location_location_variables", {-1, 0}, 0);
          {
            ImGui::Dummy({ImGui::GetFrameHeight(), ImGui::GetFrameHeight()});
            ImGui::BeginVertical("##set_event_location_location_variables_inner", {-1, 0}, 0);
            {
              GroupBox xPosGroup("X", "##set_event_location_location_variables_x", {-1, 0});
              if (xPosGroup.begin()) {
                ImGui::PushID("##set_event_location_variables_x");
                if (ImGui::EllipsesButton(m_mode == 1 ? Database::instance()->variableNameAndId(m_xVar).c_str() : "", {-1, 0})) {
                  m_variableSelection = 0;
                  m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_xVar);
                  m_variablePicker->setOpen(true);
                }
                ImGui::PopID();
              }
              xPosGroup.end();
              GroupBox yPosGroup("Y", "##set_event_location_location_variables_y", {-1, 0});
              if (yPosGroup.begin()) {
                ImGui::PushID("##set_event_location_variables_y");
                if (ImGui::EllipsesButton(m_mode == 1 ? Database::instance()->variableNameAndId(m_yVar).c_str() : "", {-1, 0})) {
                  m_variableSelection = 1;
                  m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_yVar);
                  m_variablePicker->setOpen(true);
                }
                ImGui::PopID();
              }
              yPosGroup.end();
            }
            ImGui::EndVertical();
          }
          ImGui::EndHorizontal();
        }
        ImGui::EndDisabled();
        ImGui::RadioButton(trNOOP("Exchange with another event"), &m_mode, 2);
        ImGui::BeginDisabled(m_mode != 2);
        {
          ImGui::BeginHorizontal("##set_event_location_location_other_event", {-1, 0}, 0);
          {
            ImGui::Dummy({ImGui::GetFrameHeight(), ImGui::GetFrameHeight()});
            ImGui::SetNextItemWidth(-1);
            if (ImGui::BeginCombo("##set_event_location_other_event_list", m_mode == 2 ? Database::instance()->eventNameOrId(m_otherEvent).c_str() : "")) {
              for (int i = 0; i < Database::instance()->mapInfos.currentMap()->map()->events().size(); ++i) {
                if (i > 0 && !Database::instance()->mapInfos.currentMap()->map()->event(i)) {
                  continue;
                }

                if (ImGui::Selectable(Database::instance()->eventNameOrId(i).c_str(), i == m_otherEvent)) {
                  m_otherEvent = i;
                }

                if (i == m_otherEvent) {
                  ImGui::SetItemDefaultFocus();
                }
              }
              ImGui::EndCombo();
            }
          }
          ImGui::EndHorizontal();
        }
        ImGui::EndDisabled();
        ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
        GroupBox directionGroup(trNOOP("Direction"), "##set_event_location_direction", {ImGui::GetContentRegionAvail().x, 0});
        if (directionGroup.begin()) {
          ImGui::PushItemWidth(-1);
          if (ImGui::BeginCombo("##direction_selection", DecodeEnumName(magic_enum::enum_cast<Direction>(m_direction).value_or(Direction::Retain)).c_str())) {
            for (auto& direction : magic_enum::enum_values<Direction>()) {
              bool selected = m_direction == static_cast<int>(direction);
              if (ImGui::Selectable(DecodeEnumName(direction).c_str(), selected)) {
                m_direction = static_cast<int>(direction);
              }
              if (selected) {
                ImGui::SetItemDefaultFocus();
              }
            }
            ImGui::EndCombo();
          }
        }
        directionGroup.end();
      }
      locationGroup.end();

      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##set_event_location_button_layout", {-1, 0}, 0);
      {
        ImGui::Spring();

        if (const auto ret = ImGui::ButtonGroup("##set_event_location_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;

          m_command->mode = static_cast<TransferMode>(m_mode);
          if (m_command->mode == TransferMode::Direct) {
            m_command->event = m_event;
            m_command->x = m_x;
            m_command->y = m_y;
          } else if (m_command->mode == TransferMode::Variable_Designation) {
            m_command->event = m_event;
            m_command->x = m_xVar;
            m_command->y = m_yVar;
          } else {
            m_command->event = m_event;
            m_command->x = m_otherEvent;
            m_command->y = 0;
          }
          m_command->direction = static_cast<Direction>(m_direction);

          ImGui::CloseCurrentPopup();
          setOpen(false);
        } else if (ret == 1) {
          ImGui::CloseCurrentPopup();
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }

  return std::make_tuple(!m_open, m_confirmed);
}

void Dialog_SetEventLocation::drawPickers() {
  if (m_variablePicker) {
    if (const auto [closed, confirmed] = m_variablePicker->draw(); closed) {
      if (confirmed) {
        switch (m_variableSelection) {
        case 0:
          m_xVar = m_variablePicker->selection();
          break;
        case 1:
          m_yVar = m_variablePicker->selection();
          break;
        default:
          break;
        }
      }
      m_variablePicker.reset();
    }
  }

  if (m_eventTilePicker) {
    if (const auto [closed, confirmed] = m_eventTilePicker->draw(); closed) {
      if (confirmed) {
        m_x = m_eventTilePicker->selectedTile().x();
        m_y = m_eventTilePicker->selectedTile().y();
      }

      m_eventTilePicker.reset();
    }
  }
}


code:
#pragma once
#include "Core/CommonUI/EventTilePicker.hpp"
#include "Core/CommonUI/VariableSwitchPicker.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/SetEventLocation.hpp"

struct Dialog_SetEventLocation : IEventDialogController {
  Dialog_SetEventLocation() = delete;
  explicit Dialog_SetEventLocation(const std::string& name, const std::shared_ptr<SetEventLocationCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new SetEventLocationCommand());
    }
    m_mode = static_cast<int>(m_command->mode);
    m_event = m_command->event;

    if (m_command->mode == TransferMode::Variable_Designation) {
      m_xVar = m_command->x;
      m_yVar = m_command->y;
    } else if (m_command->mode == TransferMode::Exchange_With_Another_Event) {
      m_otherEvent = m_command->x;
      m_yVar = 0;
    } else {
      m_x = m_command->x;
      m_y = m_command->y;
    }
    m_direction = static_cast<int>(m_command->direction);
  }
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return m_command; };

private:
  void drawPickers();
  // If exchanging, it uses x_var for event id
  int m_event{};
  int m_mode{};
  int m_x{};
  int m_y{};
  int m_direction{};

  int m_xVar{1};
  int m_yVar{1};
  int m_otherEvent{0};
  int m_variableSelection{};

  bool m_confirmed{false};
  std::shared_ptr<SetEventLocationCommand> m_command;
  std::optional<VariableSwitchPicker> m_variablePicker;
  std::optional<EventTilePicker> m_eventTilePicker;
};