code:
#include "Core/EventCommands/Dialog_ChangeParameter.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_ChangeParameter::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ChangeParameter");
  }
  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() * 13) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});
  if (ImGui::BeginPopupModal(std::format("{}###ChangeParameter", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    drawPickers();
    ImGui::BeginVertical("##change_parameter_main_layout", ImGui::GetContentRegionAvail());
    {
      GroupBox actorGroupBox(trNOOP("Actor"), "##change_parameter_actor_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (actorGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_parameter_actor_group_main_layout", {-1, -1});
        {
          ImGui::BeginVertical("##change_parameter_actor_group_comparison_layout", {-1, -1});
          {
            ImGui::RadioButton("Fixed", &m_comparison, 0);
            ImGui::RadioButton("Variable", &m_comparison, 1);
          }
          ImGui::EndVertical();
          ImGui::BeginVertical("##change_parameter_actor_group_object_layout", {-1, -1});
          {
            ImGui::BeginDisabled(m_comparison != 0);
            ImGui::PushID("##change_parameter_actor");
            if (ImGui::EllipsesButton(m_comparison == 0 ? Database::instance()->actorNameAndId(m_value).c_str() : "", ImVec2{-1, 0})) {
              m_actorPicker = ObjectPicker("Actor"sv, Database::instance()->actors.actorList(), m_value);
              m_actorPicker->setOpen(true);
            }
            ImGui::PopID();
            ImGui::EndDisabled();

            ImGui::BeginDisabled(m_comparison != 1);
            ImGui::PushID("##change_parameter_var");
            if (ImGui::EllipsesButton(m_comparison == 1 ? Database::instance()->variableNameAndId(m_value_var).c_str() : "", ImVec2{-1, 0})) {
              m_isOperand = false;
              m_variablePicker.emplace("Variables", Database::instance()->system.variables(), m_value_var);
              m_variablePicker->setOpen(true);
            }
            ImGui::PopID();
            ImGui::EndDisabled();
          }
          ImGui::EndVertical();
        }
        ImGui::EndHorizontal();
      }
      actorGroupBox.end();
      GroupBox parameterGroupBox(trNOOP("Parameter"), "##change_parameter_parameter_group", {-1, 0}, nullptr,
                                 ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (parameterGroupBox.begin()) {
        ImGui::SetNextItemWidth(-1);
        if (ImGui::BeginCombo("##parameter_selection", DecodeEnumName(magic_enum::enum_value<ParameterSource>(m_parameterSource)).c_str())) {
          for (auto& parameter : magic_enum::enum_values<ParameterSource>()) {
            if (bool isSelected = m_parameterSource == magic_enum::enum_index(parameter).value(); ImGui::Selectable(DecodeEnumName(parameter).c_str(), isSelected)) {
              m_parameterSource = static_cast<int>(parameter);
              if (isSelected)
                ImGui::SetItemDefaultFocus();
            }
          }
          ImGui::EndCombo();
        }
      }
      parameterGroupBox.end();

      GroupBox operationGroupBox(trNOOP("Operation"), "##change_parameter_operation_group", {-1, 0}, nullptr,
                                 ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (operationGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_parameter_operation_group_operation_layout", {ImGui::GetContentRegionAvail().x, -1});
        {
          ImGui::Spring(.33f);
          ImGui::RadioButton("Increase", &m_quantityOp, 0);
          ImGui::Spring(.33f);
          ImGui::RadioButton("Decrease", &m_quantityOp, 1);
          ImGui::Spring(.33f);
        }
        ImGui::EndHorizontal();
      }
      operationGroupBox.end();

      GroupBox operandGroupBox(trNOOP("Operand"), "##change_parameter_operand_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (operandGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_parameter_operand_main_layout", {-1, -1});
        {
          ImGui::BeginVertical("##change_parameter_operand_source_layout", {-1, -1});
          {
            ImGui::RadioButton("Constant", &m_quantitySource, 0);
            ImGui::RadioButton("Variable##2", &m_quantitySource, 1);
          }
          ImGui::EndVertical();
          ImGui::BeginVertical("##change_parameter_operand_value_layout", {-1, -1});
          {
            ImGui::BeginDisabled(m_quantitySource != 0);
            ImGui::SetNextItemWidth(-1);
            if (ImGui::SpinInt("##change_parameter_constant", &m_quantity, 1, 100, m_quantitySource == 0 ? nullptr : "")) {
              m_quantity = std::clamp(m_quantity, 1, 9999);
            }
            ImGui::EndDisabled();

            ImGui::BeginDisabled(m_quantitySource != 1);
            ImGui::PushID("##change_parameter_quant_var");
            if (ImGui::EllipsesButton(m_quantitySource == 1 ? Database::instance()->variableNameAndId(m_quantityVar).c_str() : "", ImVec2{-1, 0})) {
              m_isOperand = true;
              m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_quantityVar);
              m_variablePicker->setOpen(true);
            }
            ImGui::PopID();
            ImGui::EndDisabled();
          }
          ImGui::EndVertical();
        }
        ImGui::EndHorizontal();
      }
      operandGroupBox.end();

      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##change_parameter_buttons");
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##change_parameter_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;

          m_command->comparison = static_cast<ActorComparisonSource>(m_comparison);
          m_command->quantityOp = static_cast<QuantityChangeOp>(m_quantityOp);
          m_command->quantitySource = static_cast<QuantityChangeSource>(m_quantitySource);
          m_command->param = static_cast<ParameterSource>(m_parameterSource);

          if (m_command->comparison == ActorComparisonSource::Variable)
            m_command->value = m_value_var;
          else
            m_command->value = m_value;

          if (m_command->quantitySource == QuantityChangeSource::Variable)
            m_command->quantity = m_quantityVar;
          else
            m_command->quantity = m_quantity;

          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_ChangeParameter::drawPickers() {
  if (m_actorPicker) {
    if (const auto [closed, confirmed] = m_actorPicker->draw(); closed) {
      if (confirmed) {
        m_value = m_actorPicker->selection();
      }
      m_actorPicker.reset();
    }
  }
  if (m_variablePicker) {
    if (const auto [closed, confirmed] = m_variablePicker->draw(); closed) {
      if (confirmed) {
        if (m_isOperand)
          m_quantityVar = m_variablePicker->selection();
        else
          m_value_var = m_variablePicker->selection();
      }
      m_variablePicker.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/ChangeParameter.hpp"

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

    m_comparison = static_cast<int>(m_command->comparison);
    m_quantityOp = static_cast<int>(m_command->quantityOp);
    m_quantitySource = static_cast<int>(m_command->quantitySource);
    m_parameterSource = static_cast<int>(m_command->param);

    if (m_command->comparison == ActorComparisonSource::Variable)
      m_value_var = m_command->value;
    else
      m_value = m_command->value;

    if (m_command->quantitySource == QuantityChangeSource::Variable)
      m_quantityVar = m_command->quantity;
    else
      m_quantity = m_command->quantity;
  }
  void drawPickers();
  std::tuple<bool, bool> draw() override;

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

private:
  int m_comparison;
  int m_value{1};
  int m_value_var{1};
  int m_quantityOp;
  int m_quantitySource;
  int m_quantity{1};
  int m_quantityVar{1};
  bool m_isOperand{false};
  int m_parameterSource;

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

repo_name: Antidote/openrpgeditor

license: mit


code:
#include "Core/EventCommands/Dialog_ChangePartyMember.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_ChangePartyMember::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ChangePartyMember");
  }
  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() * 7) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});

  if (ImGui::BeginPopupModal(std::format("{}###ChangePartyMember", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    drawPickers();
    ImGui::BeginVertical("##change_party_member_main_layout", ImGui::GetContentRegionAvail());
    {
      GroupBox actorGroupBox(trNOOP("Actor"), "##change_party_member_actor_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (actorGroupBox.begin()) {
        ImGui::SetNextItemWidth(-1);
        ImGui::PushID("##change_party_member_actor_selection");
        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);
        }
        ImGui::PopID();
      }
      actorGroupBox.end();

      GroupBox operationGroupBox(trNOOP("Operation"), "##change_party_member_operation_group", {-1, 0}, nullptr,
                                 ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (operationGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_party_member_operation_group_layout", {ImGui::GetContentRegionAvail().x, -1});
        {
          ImGui::Spring(.33f);
          ImGui::RadioButton("Add", &m_operation, 0);
          ImGui::Spring(.33f);
          ImGui::RadioButton("Remove", &m_operation, 1);
          ImGui::Spring(.33f);
        }
        ImGui::EndHorizontal();
      }
      operationGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5));
      ImGui::BeginHorizontal("##change_party_member_buttons", {-1, -1});
      {
        ImGui::BeginDisabled(m_operation != 0);
        ImGui::Checkbox("Initialize", &m_isInit);
        ImGui::EndDisabled();

        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##change_party_member_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->member = m_actor;
          m_command->operation = static_cast<PartyMemberOperation>(m_operation);
          m_command->initialize = m_isInit;
          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_ChangePartyMember::drawPickers() {
  if (m_actorPicker) {
    if (const auto [closed, confirmed] = m_actorPicker->draw(); closed) {
      if (confirmed) {
        m_actor = m_actorPicker->selection();
      }
      m_actorPicker.reset();
    }
  }
}


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

#include "Database/Actor.hpp"
#include "Database/EventCommands/ChangePartyMember.hpp"
#include "Database/States.hpp"

struct Dialog_ChangePartyMember : IEventDialogController {
  Dialog_ChangePartyMember() = delete;
  explicit Dialog_ChangePartyMember(const std::string& name, const std::shared_ptr<ChangePartyMemberCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ChangePartyMemberCommand());
    }
    m_actor = m_command->member;
    m_operation = static_cast<int>(m_command->operation);
    m_isInit = m_command->initialize;
  }
  void drawPickers();
  std::tuple<bool, bool> draw() override;

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

private:
  int m_actor;
  int m_operation;
  bool m_isInit;

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


code:
#include "Core/EventCommands/Dialog_ChangePlayerFollowers.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_ChangePlayerFollowers::draw() {
  if (isOpen()) {
    ImGui::OpenPopup(m_name.c_str());
  }
  ImVec2 center = ImGui::GetMainViewport()->GetCenter();
  ImGui::SetNextWindowPos(center, 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(m_name.c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {

    ImGui::BeginVertical("##change_player_followers_vert_layout", ImGui::GetContentRegionAvail());
    {
      GroupBox operationGroupBox(trNOOP("Player Followers"), "##change_player_followers_layout", {-1, 0}, nullptr,
                                 ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (operationGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_player_followers_group_horizontal", {ImGui::GetContentRegionAvail().x, -1});
        {
          ImGui::Spring(.5);
          ImGui::RadioButton(trNOOP("ON"), &m_checkIfOn, 0);
          ImGui::RadioButton(trNOOP("OFF"), &m_checkIfOn, 1);
          ImGui::Spring(.5);
        }
        ImGui::EndHorizontal();
      }
      operationGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5));
      ImGui::BeginHorizontal("##change_player_followers_dialog_buttons", {-1, -1});
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##change_player_followers_dialog_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          command->followersEnabled = m_checkIfOn == 0 ? ValueControl::ON : ValueControl::OFF;
          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/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/ChangePlayerFollowers.hpp"

struct Dialog_ChangePlayerFollowers : IEventDialogController {
  Dialog_ChangePlayerFollowers() = delete;
  explicit Dialog_ChangePlayerFollowers(const std::string& name, const std::shared_ptr<ChangePlayerFollowersCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new ChangePlayerFollowersCommand());
    }
    m_checkIfOn = static_cast<int>(command->followersEnabled);
  }
  std::tuple<bool, bool> draw() override;

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

private:
  int m_checkIfOn;
  bool m_confirmed{false};
  std::shared_ptr<ChangePlayerFollowersCommand> command;
  std::tuple<bool, bool> result;
};


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

#include "Core/ImGuiExt/ImGuiUtils.hpp"

#include <imgui.h>
#include <imgui_internal.h>
#include <misc/cpp/imgui_stdlib.h>
#include <tuple>

std::tuple<bool, bool> Dialog_ChangePluginCommand::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ChangePlugin");
  }
  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() * 4) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});

  if (ImGui::BeginPopupModal(std::format("{}###ChangePlugin", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    ImGui::BeginVertical("##plugin_command_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      ImGui::SetNextItemWidth(-1);
      ImGui::InputText("##plugin_input", &m_pluginText);
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##plugin_command_button_layout", {-1, 0}, 0);
      {
        ImGui::Spring();

        if (const auto ret = ImGui::ButtonGroup("##plugin_command_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->command = m_pluginText;
          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/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/Plugin.hpp"

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

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

private:
  std::string m_pluginText;

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


code:
#include "Core/EventCommands/Dialog_ChangeProfile.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_ChangeProfile::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ChangeProfile");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 60) + (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("{}###ChangeProfile", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    drawPickers();
    ImGui::BeginVertical("##change_profile_main_layout");
    {
      GroupBox actorGroupBox(trNOOP("Actor"), "##change_profile_actor_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (actorGroupBox.begin()) {
        ImGui::PushID("##change_profile_selection_actor");
        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);
        }
        ImGui::PopID();
      }
      actorGroupBox.end();
      GroupBox profileGroupBox(trNOOP("Profile"), "##change_profile_profile_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (profileGroupBox.begin()) {
        ImGui::InputTextMultiline("##profile_input", &m_profile, ImVec2{-1, ImGui::GetTextLineHeightWithSpacing() * 2}, ImGuiInputTextFlags_CallbackEdit, multilineTextCallback);
      }
      profileGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##change_profile_buttons", {-1, -1});
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##change_profile_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->actor = m_actor;
          m_command->profile = m_profile;
          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_ChangeProfile::drawPickers() {
  if (m_actorPicker) {
    auto [closed, confirmed] = m_actorPicker->draw();
    if (closed) {
      if (confirmed) {
        m_actor = m_actorPicker->selection();
        m_actorPicker.reset();
      }
      m_actorPicker.reset();
    }
  }
}

int Dialog_ChangeProfile::multilineTextCallback(ImGuiInputTextCallbackData* data) {
  std::string multilineText;
  multilineText.resize(data->BufTextLen);
  strncpy(multilineText.data(), data->Buf, data->BufTextLen);

  auto profileLines = splitString(multilineText, '\n');
  multilineText.clear();
  bool dirty = false;
  if (profileLines.size() >= 2) {
    profileLines.resize(2);
    dirty = true;
  }
  for (int i = 0; const auto& line : profileLines) {
    multilineText += i > 0 ? "\n" + line : line;
    ++i;
  }

  if (dirty) {
    memset(data->Buf, 0, data->BufSize);
    strncpy(data->Buf, multilineText.c_str(), multilineText.length());
    data->BufTextLen = strlen(data->Buf);
    data->BufDirty = true;
    data->CursorPos = data->BufTextLen;
  }
  return 0;
}


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

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

struct Dialog_ChangeProfile : IEventDialogController {
  Dialog_ChangeProfile() = delete;
  explicit Dialog_ChangeProfile(const std::string& name, const std::shared_ptr<ChangeProfileCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ChangeProfileCommand());
    }
    m_actor = m_command->actor;
    m_profile = m_command->profile;
  }
  std::tuple<bool, bool> draw() override;

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

private:
  friend int multilineTextCallback(ImGuiInputTextCallbackData* data);

  void drawPickers();
  static int multilineTextCallback(ImGuiInputTextCallbackData* data);

  int m_actor;
  std::string m_profile;

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


code:
#include "Core/EventCommands/Dialog_ChangeSaveAccess.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_ChangeSaveAccess::draw() {
  if (isOpen()) {
    ImGui::OpenPopup(m_name.c_str());
  }

  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(m_name.c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {

    ImGui::BeginVertical("##change_save_access_vert_layout", ImGui::GetContentRegionAvail());
    {
      GroupBox operationGroupBox(trNOOP("Save Access"), "##change_save_access_layout", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (operationGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_save_access_group_horizontal", {ImGui::GetContentRegionAvail().x, -1});
        {
          ImGui::Spring(.5);
          ImGui::RadioButton(trNOOP("OFF"), &isDisabled, 0);
          ImGui::RadioButton(trNOOP("ON"), &isDisabled, 1);
          ImGui::Spring(.5);
        }
        ImGui::EndHorizontal();
      }
      operationGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5));
      ImGui::BeginHorizontal("##change_save_access_dialog_buttons", {-1, -1});
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##change_save_access_dialog_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          command->access = isDisabled == 0 ? AccessMode::Disable : AccessMode::Enable;
          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/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/ChangeSaveAccess.hpp"

struct Dialog_ChangeSaveAccess : IEventDialogController {
  Dialog_ChangeSaveAccess() = delete;
  explicit Dialog_ChangeSaveAccess(const std::string& name, const std::shared_ptr<ChangeSaveAccessCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new ChangeSaveAccessCommand());
    }
    isDisabled = static_cast<int>(command->access);
  }
  std::tuple<bool, bool> draw() override;

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

private:
  int isDisabled;
  bool m_confirmed{false};
  std::shared_ptr<ChangeSaveAccessCommand> command;
  std::tuple<bool, bool> result;
};


code:
#include "Core/EventCommands/Dialog_ChangeSkill.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_ChangeSkill::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ChangeSkill");
  }
  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() * 10) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});

  if (ImGui::BeginPopupModal(std::format("{}###ChangeSkill", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    drawPickers();
    ImGui::BeginVertical("##change_skill_main_layout", ImGui::GetContentRegionAvail());
    {
      GroupBox actorGroupBox(trNOOP("Actor"), "##change_skill_actor_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (actorGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_skill_actor_group_horizontal", {-1, -1});
        {
          ImGui::BeginVertical("##change_skill_actor_group_radios", {-1, -1});
          {
            ImGui::RadioButton(trNOOP("Fixed"), &m_comparison, 0);
            ImGui::RadioButton(trNOOP("Variable"), &m_comparison, 1);
          }
          ImGui::EndVertical();
          ImGui::Spring();
          ImGui::BeginVertical("##change_skill_actor_group_buttons", {-1, -1});
          {
            ImGui::BeginDisabled(m_comparison != 0);
            ImGui::PushID("##change_skill_actor_group_fixed_button");
            if (ImGui::EllipsesButton(m_comparison == 0 ? Database::instance()->actorNameAndId(m_actor).c_str() : "", {-1, 0})) {
              m_actorPicker = ObjectPicker(trNOOP("Actor"), Database::instance()->actors.actorList(), m_actor);
              m_actorPicker->setOpen(true);
            }
            ImGui::PopID();
            ImGui::EndDisabled();
            ImGui::BeginDisabled(m_comparison != 1);
            ImGui::PushID("##change_skill_actor_group_var");
            if (ImGui::EllipsesButton(m_comparison == 1 ? Database::instance()->variableNameAndId(m_var).c_str() : "", {-1, 0})) {
              m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_var);
              m_variablePicker->setOpen(true);
            }
            ImGui::PopID();
            ImGui::EndDisabled();
          }
          ImGui::EndVertical();
        }
        ImGui::EndHorizontal();
      }
      actorGroupBox.end();
      GroupBox operationGroupBox(trNOOP("Operation"), "##change_skill_operation_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (operationGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_skill_operation_group_horizontal", {ImGui::GetContentRegionAvail().x, -1});
        {
          ImGui::Spring(0.33f);
          ImGui::RadioButton(trNOOP("Forget"), &m_skillOp, 0);
          ImGui::Spring(0.33f);
          ImGui::RadioButton(trNOOP("Learn"), &m_skillOp, 1);
          ImGui::Spring(0.33f);
        }
        ImGui::EndHorizontal();
      }
      operationGroupBox.end();
      GroupBox skillGroupBox(trNOOP("Skill"), "##change_skill_skill_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (skillGroupBox.begin()) {
        ImGui::PushID("##change_skill_skill_selection");
        if (ImGui::EllipsesButton((std::format("{:04} ", m_skill) + Database::instance()->skillNameOrId(m_skill)).c_str(), ImVec2{-1, 0})) {
          m_skillPicker = ObjectPicker(trNOOP("Skill"), Database::instance()->skills.skills(), m_skill);
          m_skillPicker->setOpen(true);
        }
        ImGui::PopID();
      }
      skillGroupBox.end();
      ImGui::Spring();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5));
      ImGui::BeginHorizontal("##change_mp_dialog_buttons", {-1, -1});
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##change_mp_dialog_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->comparison = static_cast<ActorComparisonSource>(m_comparison);
          m_command->skill = m_skill;
          m_command->skillOp = static_cast<SkillOperation>(m_skillOp);
          if (m_command->comparison == ActorComparisonSource::Fixed) {
            m_command->value = m_actor;
          } else {
            m_command->value = m_var;
          }

          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_ChangeSkill::drawPickers() {
  if (m_actorPicker) {
    if (const auto [closed, confirmed] = m_actorPicker->draw(); closed) {
      if (confirmed) {
        m_actor = m_actorPicker->selection();
      }
      m_actorPicker.reset();
    }
  }
  if (m_skillPicker) {
    if (const auto [closed, confirmed] = m_skillPicker->draw(); closed) {
      if (confirmed) {
        m_skill = m_skillPicker->selection();
      }
      m_skillPicker.reset();
    }
  }

  if (m_variablePicker) {
    if (const auto [closed, confirmed] = m_variablePicker->draw(); closed) {
      if (confirmed) {
        m_var = m_variablePicker->selection();
      }
      m_variablePicker.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/ChangeSkill.hpp"
#include "Database/Skill.hpp"

struct Dialog_ChangeSkill : IEventDialogController {
  Dialog_ChangeSkill() = delete;
  explicit Dialog_ChangeSkill(const std::string& name, const std::shared_ptr<ChangeSkillCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ChangeSkillCommand());
    }
    m_comparison = static_cast<int>(m_command->comparison);
    if (m_command->comparison == ActorComparisonSource::Variable)
      m_var = m_command->value;
    else
      m_actor = m_command->value;
    m_skillOp = static_cast<int>(m_command->skillOp);
    m_skill = m_command->skill;
  }
  void drawPickers();
  std::tuple<bool, bool> draw() override;

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

private:
  int m_comparison;
  int m_actor{1};
  int m_skillOp;
  int m_skill{1};

  int m_var{1};

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


code:
#include "Core/EventCommands/Dialog_ChangeState.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_ChangeState::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ChangeState");
  }
  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() * 10) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});

  if (ImGui::BeginPopupModal(std::format("{}###ChangeState", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    drawPickers();
    ImGui::BeginVertical("##change_state_main_layout", ImGui::GetContentRegionAvail());
    {
      GroupBox actorGroupBox(trNOOP("Actor"), "##change_state_actor_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (actorGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_state_actor_group_horizontal", {-1, -1});
        {
          ImGui::BeginVertical("##change_state_actor_group_radios", {-1, -1});
          {
            ImGui::RadioButton(trNOOP("Fixed"), &m_comparison, 0);
            ImGui::RadioButton(trNOOP("Variable"), &m_comparison, 1);
          }
          ImGui::EndVertical();
          ImGui::Spring();
          ImGui::BeginVertical("##change_state_actor_group_buttons", {-1, -1});
          {
            ImGui::BeginDisabled(m_comparison != 0);
            ImGui::PushID("##change_state_actor_group_fixed_button");
            if (ImGui::EllipsesButton(m_comparison == 0 ? Database::instance()->actorNameAndId(m_actor).c_str() : "", {-1, 0})) {
              m_actorPicker = ObjectPicker(trNOOP("Actor"), Database::instance()->actors.actorList(), m_actor);
              m_actorPicker->setOpen(true);
            }
            ImGui::PopID();
            ImGui::EndDisabled();
            ImGui::BeginDisabled(m_comparison != 1);
            ImGui::PushID("##change_state_actor_group_var");
            if (ImGui::EllipsesButton(m_comparison == 1 ? Database::instance()->variableNameAndId(m_var).c_str() : "", {-1, 0})) {
              m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_var);
              m_variablePicker->setOpen(true);
            }
            ImGui::PopID();
            ImGui::EndDisabled();
          }
          ImGui::EndVertical();
        }
        ImGui::EndHorizontal();
      }
      actorGroupBox.end();
      GroupBox operationGroupBox(trNOOP("Operation"), "##change_state_operation_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (operationGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_state_operation_group_horizontal", {ImGui::GetContentRegionAvail().x, -1});
        {
          ImGui::Spring(0.33f);
          ImGui::RadioButton(trNOOP("Add"), &m_stateOp, 0);
          ImGui::Spring(0.33f);
          ImGui::RadioButton(trNOOP("Remove"), &m_stateOp, 1);
          ImGui::Spring(0.33f);
        }
        ImGui::EndHorizontal();
      }
      operationGroupBox.end();
      GroupBox skillGroupBox(trNOOP("Skill"), "##change_state_state_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (skillGroupBox.begin()) {
        ImGui::PushID("##change_state_state_selection");
        if (ImGui::EllipsesButton(Database::instance()->stateNameAndId(m_state).c_str(), ImVec2{-1, 0})) {
          m_statePicker = ObjectPicker(trNOOP("State"), Database::instance()->states.states(), m_state);
          m_statePicker->setOpen(true);
        }
        ImGui::PopID();
      }
      skillGroupBox.end();
      ImGui::Spring();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5));
      ImGui::BeginHorizontal("##change_mp_dialog_buttons", {-1, -1});
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##change_mp_dialog_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->comparison = static_cast<ActorComparisonSource>(m_comparison);
          m_command->state = m_state;
          m_command->stateOp = static_cast<PartyMemberOperation>(m_stateOp);
          if (m_command->comparison == ActorComparisonSource::Fixed) {
            m_command->value = m_actor;
          } else {
            m_command->value = m_var;
          }

          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_ChangeState::drawPickers() {
  if (m_actorPicker) {
    if (const auto [closed, confirmed] = m_actorPicker->draw(); closed) {
      if (confirmed) {
        m_actor = m_actorPicker->selection();
      }
      m_actorPicker.reset();
    }
  }
  if (m_statePicker) {
    if (const auto [closed, confirmed] = m_statePicker->draw(); closed) {
      if (confirmed) {
        m_state = m_statePicker->selection();
      }
      m_statePicker.reset();
    }
  }

  if (m_variablePicker) {
    if (const auto [closed, confirmed] = m_variablePicker->draw(); closed) {
      if (confirmed) {
        m_var = m_variablePicker->selection();
      }
      m_variablePicker.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/ChangeState.hpp"
#include "Database/State.hpp"

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

    m_state = m_command->state;
    m_stateOp = static_cast<int>(m_command->stateOp);
    m_comparison = static_cast<int>(m_command->comparison);

    if (m_command->comparison == ActorComparisonSource::Variable)
      m_var = m_command->value;
    else
      m_actor = m_command->value;
  }
  std::tuple<bool, bool> draw() override;

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

private:
  void drawPickers();
  int m_state;
  int m_stateOp;
  int m_comparison;
  int m_actor{1};
  int m_var{1};

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


code:
#include "Core/EventCommands/Dialog_ChangeTP.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_ChangeTP::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ChangeTP");
  }
  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() * 11) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});
  if (ImGui::BeginPopupModal(std::format("{}###ChangeTP", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    drawPickers();
    ImGui::BeginVertical("##change_tp_main_layout", ImGui::GetContentRegionAvail());
    {
      GroupBox actorGroupBox(trNOOP("Actor"), "##change_tp_actor_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (actorGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_tp_actor_group_horizontal", {-1, -1});
        {
          ImGui::BeginVertical("##change_tp_actor_group_radios", {-1, -1});
          {
            ImGui::RadioButton(trNOOP("Fixed"), &m_comparison, 0);
            ImGui::RadioButton(trNOOP("Variable"), &m_comparison, 1);
          }
          ImGui::EndVertical();
          ImGui::Spring();
          ImGui::BeginVertical("##change_tp_actor_group_buttons", {-1, -1});
          {
            ImGui::BeginDisabled(m_comparison != 0);
            ImGui::PushID("##change_tp_actor_group_fixed_button");
            if (ImGui::EllipsesButton(m_comparison == 0 ? Database::instance()->actorNameAndId(m_value).c_str() : "", {-1, 0})) {
              m_actorPicker = ObjectPicker(trNOOP("Actor"), Database::instance()->actors.actorList(), m_value);
              m_actorPicker->setOpen(true);
            }
            ImGui::PopID();
            ImGui::EndDisabled();
            ImGui::BeginDisabled(m_comparison != 1);
            ImGui::PushID("##change_tp_actor_group_var");
            if (ImGui::EllipsesButton(m_comparison == 1 ? Database::instance()->variableNameAndId(m_value).c_str() : "", {-1, 0})) {
              m_isOperand = false;
              m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_value);
              m_variablePicker->setOpen(true);
            }
            ImGui::PopID();
            ImGui::EndDisabled();
          }
          ImGui::EndVertical();
        }
        ImGui::EndHorizontal();
      }
      actorGroupBox.end();
      GroupBox operationGroupBox(trNOOP("Operation"), "##change_tp_operation_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (operationGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_tp_operation_group_horizontal", {ImGui::GetContentRegionAvail().x, -1});
        {
          ImGui::Spring(0.33f);
          ImGui::RadioButton(trNOOP("Increase"), &m_quantityOp, 0);
          ImGui::Spring(0.33f);
          ImGui::RadioButton(trNOOP("Decrease"), &m_quantityOp, 1);
          ImGui::Spring(0.33f);
        }
        ImGui::EndHorizontal();
      }
      operationGroupBox.end();
      GroupBox operandGroupBox(trNOOP("Operand"), "##change_tp_operand", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (operandGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_tp_operand_horizontal", {-1, -1});
        {
          ImGui::BeginVertical("##change_tp_operand_radios", {-1, -1});
          {
            ImGui::RadioButton(trNOOP("Constant"), &m_quantitySource, 0);
            ImGui::RadioButton(std::format("{}##operand", tr("Variable")).c_str(), &m_quantitySource, 1);
          }
          ImGui::EndVertical();
          ImGui::Spring();
          ImGui::BeginVertical("##change_tp_operand_buttons", {-1, -1});
          {
            ImGui::BeginDisabled(m_quantitySource != 0);
            ImGui::SetNextItemWidth(-1);
            if (ImGui::SpinInt("##change_tp_operand_constant", &m_quantity, 1, 100, m_quantitySource == 0 ? nullptr : "")) {
              m_quantity = std::clamp(m_quantitySource, 1, 100);
            }
            ImGui::EndDisabled();

            ImGui::BeginDisabled(m_quantitySource != 1);
            ImGui::PushID("##change_tp_operand_quantity_variable");
            if (ImGui::EllipsesButton(m_quantitySource == 1 ? Database::instance()->variableNameAndId(m_quantityVar).c_str() : "", ImVec2{-1, 0})) {
              m_isOperand = true;
              m_variablePicker.emplace("Variables", Database::instance()->system.variables(), m_quantityVar);
              m_variablePicker->setOpen(true);
            }
            ImGui::PopID();
            ImGui::EndDisabled();
          }
          ImGui::EndVertical();
        }
        ImGui::EndHorizontal();
      }
      operandGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5));
      ImGui::BeginHorizontal("##change_tp_dialog_buttons", {-1, -1});
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##change_tp_dialog_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->comparison = static_cast<ActorComparisonSource>(m_comparison);
          m_command->quantityOp = static_cast<QuantityChangeOp>(m_quantityOp);
          m_command->quantitySource = static_cast<QuantityChangeSource>(m_quantitySource);
          if (m_command->comparison == ActorComparisonSource::Fixed) {
            m_command->value = m_value;
          } else {
            m_command->value = m_valueVar;
          }
          if (m_command->quantitySource == QuantityChangeSource::Constant) {
            m_command->quantity = m_quantity;
          } else {
            m_command->quantity = m_quantityVar;
          }

          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_ChangeTP::drawPickers() {
  if (m_actorPicker) {
    if (const auto [closed, confirmed] = m_actorPicker->draw(); closed) {
      if (confirmed) {
        m_value = m_actorPicker->selection();
      }
      m_actorPicker.reset();
    }
  }
  if (m_variablePicker) {
    if (const auto [closed, confirmed] = m_variablePicker->draw(); closed) {
      if (confirmed) {
        if (m_isOperand) {
          m_quantityVar = m_variablePicker->selection();
        } else {
          m_valueVar = m_variablePicker->selection();
        }
      }
      m_variablePicker.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/ChangeTP.hpp"

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

    m_comparison = static_cast<int>(m_command->comparison);
    m_quantityOp = static_cast<int>(m_command->quantityOp);
    m_quantitySource = static_cast<int>(m_command->quantitySource);
    if (m_command->comparison == ActorComparisonSource::Fixed) {
      m_value = m_command->value;
    } else {
      m_valueVar = m_command->value;
    }
    if (m_command->quantitySource == QuantityChangeSource::Constant) {
      m_quantity = m_command->quantity;
    } else {
      m_quantityVar = m_command->quantity;
    }
  }
  std::tuple<bool, bool> draw() override;

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

private:
  void drawPickers();

  int m_comparison;
  int m_value{1};
  int m_valueVar{1};
  int m_quantityOp;
  int m_quantitySource;
  int m_quantity{1};
  int m_quantityVar{1};
  bool m_isOperand{false};

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


code:
#include "Core/EventCommands/Dialog_ChangeTileset.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_ChangeTileset::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ChangeTileset");
  }
  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("{}###ChangeTileset", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {

    if (m_tilesetPicker) {
      if (const auto [closed, confirmed] = m_tilesetPicker->draw(); closed) {
        if (confirmed) {
          m_tileset = m_tilesetPicker->selection();
        }
        m_tilesetPicker.reset();
      }
    }

    ImGui::BeginVertical("##change_tileset_main_layout", ImGui::GetContentRegionAvail());
    {
      GroupBox operationGroupBox(trNOOP("Tileset"), "##change_tileset_layout", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (operationGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_tileset_group_horizontal", {ImGui::GetContentRegionAvail().x, -1});
        {
          ImGui::Spring(.5);
          ImGui::PushID("##tileset_selection");
          if (ImGui::EllipsesButton(Database::instance()->tilesetNameAndId(m_tileset).c_str(), ImVec2{-1, 0})) {
            m_tilesetPicker = ObjectPicker(trNOOP("Tileset"), Database::instance()->tilesets.tilesets(), m_tileset);
            m_tilesetPicker->setOpen(true);
          }
          ImGui::PopID();
          ImGui::Spring(.5);
        }
        ImGui::EndHorizontal();
      }
      operationGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5));
      ImGui::BeginHorizontal("##change_tileset_dialog_buttons", {-1, -1});
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##change_tileset_dialog_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->tileset = m_tileset;
          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/Class.hpp"
#include "Database/EventCommands/ChangeTileset.hpp"
#include "Database/Tilesets.hpp"

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

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

private:
  int m_tileset;

  bool m_confirmed{false};
  std::optional<ObjectPicker<Tileset>> m_tilesetPicker;
  std::shared_ptr<ChangeTilesetCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_ChangeTransparency.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_ChangeTransparency::draw() {
  if (isOpen()) {
    ImGui::OpenPopup(m_name.c_str());
  }
  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(m_name.c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {

    ImGui::BeginVertical("##change_transparency_vert_layout", ImGui::GetContentRegionAvail());
    {
      GroupBox operationGroupBox(trNOOP("Formation Access"), "##change_transparency_layout", {-1, 0}, nullptr,
                                 ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (operationGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_transparency_group_horizontal", {ImGui::GetContentRegionAvail().x, -1});
        {
          ImGui::Spring(.5);
          ImGui::RadioButton(trNOOP("ON"), &isDisabled, 0);
          ImGui::RadioButton(trNOOP("OFF"), &isDisabled, 1);
          ImGui::Spring(.5);
        }
        ImGui::EndHorizontal();
      }
      operationGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5));
      ImGui::BeginHorizontal("##change_transparency_dialog_buttons", {-1, -1});
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##change_transparency_dialog_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          command->transparency = isDisabled == 0 ? ValueControl::ON : ValueControl::OFF;
          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/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/ChangeTransparency.hpp"

struct Dialog_ChangeTransparency : IEventDialogController {
  Dialog_ChangeTransparency() = delete;
  explicit Dialog_ChangeTransparency(const std::string& name, const std::shared_ptr<ChangeTransparencyCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new ChangeTransparencyCommand());
    }
    isDisabled = static_cast<int>(command->transparency);
  }
  std::tuple<bool, bool> draw() override;

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

private:
  int isDisabled;
  bool m_confirmed{false};
  std::shared_ptr<ChangeTransparencyCommand> command;
  std::tuple<bool, bool> result;
};


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

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

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


code:
#pragma once
#include "Core/CommonUI/AudioEditor.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/Database.hpp"
#include "Database/EventCommands/ChangeVehicleBGM.hpp"
#include <iostream>
#include <SFML/Audio.hpp>

namespace fs = std::filesystem;
struct Dialog_ChangeVehicleBGM : IEventDialogController {
  Dialog_ChangeVehicleBGM() = delete;
  explicit Dialog_ChangeVehicleBGM(const std::string& name, const std::shared_ptr<ChangeVehicleBGMCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ChangeVehicleBGMCommand());
    }
    m_audioRenderer.emplace(m_command->code(), m_command->bgm);
  }
  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<ChangeVehicleBGMCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_ChangeVehicleImage.hpp"
#include "Core/Application.hpp"

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

std::tuple<bool, bool> Dialog_ChangeVehicleImage::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{125, 225}, ImGuiCond_Appearing);
  if (ImGui::BeginPopupModal(m_name.c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {

    if (const auto [closed, confirmed] = m_characterPicker.draw(); closed) {
      if (closed) {
        if (confirmed) {
          m_characterPicker.accept();
          m_character = m_characterPicker.character();
          m_image = m_characterPicker.selectedSheet();
          m_characterSheet = CharacterSheet(m_image);
        }
      }
    }
    ImGui::BeginGroup();
    {
      ImGui::Text("Vehicle:");
      ImGui::PushItemWidth((100));
      if (ImGui::BeginCombo("##vehicle_location_selection", DecodeEnumName(magic_enum::enum_value<VehicleType>(m_vehicle)).c_str())) {
        for (auto& vehicle : magic_enum::enum_values<VehicleType>()) {
          bool is_selected = m_vehicle == magic_enum::enum_index(vehicle).value();
          if (ImGui::Selectable(DecodeEnumName(magic_enum::enum_name(vehicle)).c_str(), is_selected)) {
            m_vehicle = magic_enum::enum_index(vehicle).value();
            if (is_selected)
              ImGui::SetItemDefaultFocus();
          }
        }
        ImGui::EndCombo();
      }
      ImGui::EndGroup();
    }

    const auto buttonSize = ImVec2{144, 144};
    const auto buttonCenter = (buttonSize / 2);
    ImGui::SeparatorText("Image");
    ImGui::BeginGroup();
    {
      auto cursorPos = ImGui::GetCursorPos();
      if (ImGui::ImageButton("##event_image", static_cast<ImTextureID>(m_buttonBack), ImVec2{80.f, 102.f})) {
        m_characterPicker.setCharacterInfo(m_image, m_character);
        m_characterPicker.setOpen(true);
      }
      if (m_characterSheet && m_characterSheet->texture()) {
        if (m_characterSheet->characterWidth() < 72 || m_characterSheet->characterHeight() < 96) {
          ImGui::SetCursorPos(cursorPos + (ImVec2{m_characterSheet->characterWidth() / 2.f, m_characterSheet->characterHeight() / 2.f}));
        } else {
          ImGui::SetCursorPos(cursorPos);
        }
        const auto [min, max] = m_characterSheet->getRectForCharacter(m_character);
        ImGui::Image(m_characterSheet->texture(), ImVec2{static_cast<float>(m_characterSheet->characterWidth()), static_cast<float>(m_characterSheet->characterHeight())}, min, max);
      }
    }
    ImGui::SameLine();
    ImGui::Dummy(ImVec2{20, 0});
    ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 2.f);
    ImGui::Dummy(ImVec2{0, 10});
    ImGui::BeginGroup();
    {
      if (ImGui::Button("OK")) {
        m_confirmed = true;
        command->vehicle = static_cast<VehicleType>(m_vehicle);
        command->picture = m_image;
        command->pictureIndex = m_character;
        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/CommonUI/CharacterPicker.hpp"
#include "Core/CommonUI/TextEditor.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Core/Graphics/CharacterSheet.hpp"

#include "Database/EventCommands/ChangeVehicleImage.hpp"

struct Dialog_ChangeVehicleImage : IEventDialogController {
  Dialog_ChangeVehicleImage() = delete;
  explicit Dialog_ChangeVehicleImage(const std::string& name, const std::shared_ptr<ChangeVehicleImageCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new ChangeVehicleImageCommand());
    }
    m_image = command->picture;
    m_character = command->pictureIndex;
    m_vehicle = static_cast<int>(command->vehicle);
  }
  std::tuple<bool, bool> draw() override;

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

private:
  std::string m_image;
  int m_character;
  int m_vehicle;

  std::optional<CharacterSheet> m_characterSheet;
  CheckerboardTexture m_buttonBack{80, 102, CellSizes::_64, 255, 200};
  CharacterPicker m_characterPicker{CharacterPicker::PickerMode::Character};

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


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

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

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


code:
#pragma once
#include "Core/CommonUI/AudioEditor.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/Database.hpp"
#include "Database/EventCommands/ChangeVictoryME.hpp"
#include <iostream>
#include <SFML/Audio.hpp>

namespace fs = std::filesystem;
struct Dialog_ChangeVictoryME : IEventDialogController {
  Dialog_ChangeVictoryME() = delete;
  explicit Dialog_ChangeVictoryME(const std::string& name, const std::shared_ptr<ChangeVictoryMECommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ChangeVictoryMECommand());
    }
    m_audioRenderer.emplace(m_command->code(), m_command->me);
  }
  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<ChangeVictoryMECommand> m_command;
};


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

#include "Database/Database.hpp"
#include "Database/Weapons.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_ChangeWeapons::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ChangeWeapons");
  }
  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() * 10) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});

  if (ImGui::BeginPopupModal(std::format("{}###ChangeWeapons", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    drawPickers();
    ImGui::BeginVertical("##change_weapons_main_layout", ImGui::GetContentRegionAvail());
    {
      GroupBox weaponGroupBox(trNOOP("Weapon"), "##change_weapons_item_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (weaponGroupBox.begin()) {
        ImGui::PushID("##change_weapons_item");
        if (ImGui::EllipsesButton(Database::instance()->weaponNameAndId(m_item).c_str(), ImVec2{-1, 0})) {
          m_weaponPicker = ObjectPicker(trNOOP("Weapon"), Database::instance()->weapons.weaponList(), m_item);
          m_weaponPicker->setOpen(true);
        }
        ImGui::PopID();
      }
      weaponGroupBox.end();

      GroupBox operationGroupBox(trNOOP("Operation"), "##change_weapons_operation_group", {-1, 0}, nullptr,
                                 ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (operationGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_weapons_operation_group_layout", {ImGui::GetContentRegionAvail().x, -1});
        {
          ImGui::Spring(.33);
          ImGui::RadioButton("Increase", &m_operation, 0);
          ImGui::Spring(.33);
          ImGui::RadioButton("Decrease", &m_operation, 1);
          ImGui::Spring(.33);
        }
        ImGui::EndHorizontal();
      }
      operationGroupBox.end();

      GroupBox operandGroupBox(trNOOP("Operand"), "##change_weapons_operand_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (operandGroupBox.begin()) {
        ImGui::BeginHorizontal("##change_weapons_operand_group_layout", {ImGui::GetContentRegionAvail().x, -1});
        {
          ImGui::BeginVertical("##change_weapons_operand_source", {-1, -1});
          {
            ImGui::RadioButton(trNOOP("Constant"), &m_operandSource, 0);
            ImGui::RadioButton(trNOOP("Variable"), &m_operandSource, 1);
          }
          ImGui::EndVertical();
          ImGui::BeginVertical("##change_weapons_operand_value", {-1, -1});
          {
            ImGui::BeginDisabled(m_operandSource != 0);
            ImGui::SetNextItemWidth(-1);
            if (ImGui::SpinInt("##change_weapons_constant", &m_quantity, 1, 100, m_operandSource == 0 ? nullptr : "")) {
              m_quantity = std::clamp(m_quantity, 1, 9999);
            }
            ImGui::EndDisabled();

            ImGui::BeginDisabled(m_operandSource != 1);
            ImGui::PushID("##change_weapons_quant_var");
            if (ImGui::EllipsesButton(m_operandSource == 1 ? Database::instance()->variableNameAndId(m_quantityVar).c_str() : "", ImVec2{-1, 0})) {
              m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_quantityVar);
              m_variablePicker->setOpen(true);
            }
            ImGui::PopID();
            ImGui::EndDisabled();
          }
          ImGui::EndVertical();
        }
        ImGui::EndHorizontal();
      }
      operandGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5));
      ImGui::BeginHorizontal("##change_weapons_buttons", {-1, -1});
      {
        ImGui::BeginDisabled(m_operation == 0);
        ImGui::Checkbox(trNOOP("Include Equipment"), &m_includeEquipment);
        ImGui::EndDisabled();
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##change_weapons_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;

          m_command->item = m_item;
          m_command->operation = static_cast<QuantityChangeOp>(m_operation);
          m_command->operandSource = static_cast<QuantityChangeSource>(m_operandSource);
          m_command->includeEquipment = m_includeEquipment;

          if (m_command->operandSource == QuantityChangeSource::Variable)
            m_command->operand = m_quantityVar;
          else
            m_command->operand = m_quantity;

          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_ChangeWeapons::drawPickers() {
  if (m_variablePicker) {
    if (const auto [closed, confirmed] = m_variablePicker->draw(); closed) {
      if (confirmed) {
        m_quantityVar = m_variablePicker->selection();
      }
      m_variablePicker.reset();
    }
  }

  if (m_weaponPicker) {
    if (const auto [closed, confirmed] = m_weaponPicker->draw(); closed) {
      if (confirmed) {
        m_item = m_weaponPicker->selection();
      }
      m_weaponPicker.reset();
    }
  }
}


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

struct Weapon;
struct Dialog_ChangeWeapons : IEventDialogController {
  Dialog_ChangeWeapons() = delete;
  explicit Dialog_ChangeWeapons(const std::string& name, const std::shared_ptr<ChangeWeaponsCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ChangeWeaponsCommand());
    }

    m_item = m_command->item;
    m_operation = static_cast<int>(m_command->operation);
    m_operandSource = static_cast<int>(m_command->operandSource);
    m_includeEquipment = m_command->includeEquipment;

    if (m_command->operandSource == QuantityChangeSource::Variable)
      m_quantityVar = m_command->operand;
    else
      m_quantity = m_command->operand;
  }
  std::tuple<bool, bool> draw() override;

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

private:
  void drawPickers();

  int m_item;
  int m_operation;
  int m_operandSource;
  int m_quantity{1};
  int m_quantityVar{1};
  bool m_includeEquipment{false};

  bool m_confirmed{false};
  std::optional<ObjectPicker<Weapon>> m_weaponPicker;
  std::optional<VariableSwitchPicker> m_variablePicker;
  std::shared_ptr<ChangeWeaponsCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_ChangeWindowColor.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_ChangeWindowColor::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ChangeWindowColor");
  }
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 60) + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetFrameHeightWithSpacing() * 10) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});
  if (ImGui::BeginPopupModal(std::format("{}###ChangeWindowColor", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    ImGui::BeginVertical("##change_window_color_main_layout", ImGui::GetContentRegionAvail());
    {
      m_colorPicker.draw({ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x, (ImGui::GetContentRegionAvail().y * .8f)});
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5));
      ImGui::BeginHorizontal("##change_window_color_dialog_buttons", {-1, -1});
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##change_window_color_dialog_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          command->r = m_colorPicker.r();
          command->g = m_colorPicker.g();
          command->b = m_colorPicker.b();
          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/GameWindowColorPicker.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/ChangeWindowColor.hpp"

struct Dialog_ChangeWindowColor : IEventDialogController {
  Dialog_ChangeWindowColor() = delete;
  explicit Dialog_ChangeWindowColor(const std::string& name, const std::shared_ptr<ChangeWindowColorCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new ChangeWindowColorCommand());
    }
    red = command->r;
    green = command->g;
    blue = command->b;
    m_colorPicker.setValues(red, green, blue);
  }
  std::tuple<bool, bool> draw() override;

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

private:
  int red;
  int green;
  int blue;

  bool m_confirmed{false};
  std::shared_ptr<ChangeWindowColorCommand> command;
  std::tuple<bool, bool> result;
  GameWindowColorPicker m_colorPicker;
};


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

#include "Core/ImGuiExt/ImGuiUtils.hpp"
#include "Core/Log.hpp"

#include "misc/cpp/imgui_stdlib.h"
#include <imgui.h>
#include <imgui_internal.h>
#include <tuple>

std::tuple<bool, bool> Dialog_Comment::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###Comment");
  }
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 40) + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetTextLineHeightWithSpacing() * 9) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});
  if (ImGui::BeginPopupModal(std::format("{}###Comment", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    ImGui::BeginVertical("##comment_main_layout", ImGui::GetContentRegionAvail());
    {
      static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput;
      ImGui::InputTextMultiline("##source", &m_comment, ImVec2{-1, (ImGui::GetTextLineHeight() * 6) + (ImGui::GetStyle().FramePadding.y * 2)}, flags);
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##comment_buttons_layout");
      {
        ImGui::Spring();
        auto ret = ImGui::ButtonGroup("##comment_buttons", {trNOOP("OK"), trNOOP("Cancel")});
        if (std::ranges::count(m_comment, '\n') >= 6) {
          ret = 0;
        }

        if (ret == 0) {
          std::vector<std::string> texts = splitString(m_comment, '\n');
          // This should never happen but just to make sure we only get 6 lines per comment
          if (texts.size() > 6) {
            texts.resize(6);
          }

          if (texts.size() > 0) {
            m_command->text = texts.front();
          }
          if (texts.size() > 1) {
            m_command->nextComments.clear();
            m_command->nextComments.reserve(texts.size());
            for (auto str = std::next(texts.begin()); str != texts.end(); ++str) {
              m_command->nextComments.emplace_back(std::make_shared<NextCommentCommand>())->text = *str;
            }
            m_command->nextComments.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/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/Comment.hpp"
#include "imgui.h"

struct Dialog_Comment : IEventDialogController {
  Dialog_Comment() = delete;
  explicit Dialog_Comment(const std::string& name, const std::shared_ptr<CommentCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new CommentCommand());
    }
    m_comment = m_command->text.c_str();
  }
  std::tuple<bool, bool> draw() override;

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

private:
  std::string m_comment;
  bool m_confirmed{false};
  std::shared_ptr<CommentCommand> m_command;
  std::tuple<bool, bool> result;
};


code:
#include "Core/EventCommands/Dialog_CommonEvent.hpp"
#include "Core/Log.hpp"

template <>
inline int ObjectPicker<std::optional<CommonEvent>>::getId(const std::optional<CommonEvent>& value) {
  return value ? value->id() : 0;
}

static const std::string InvalidCommonEvent = "Invalid Common Event";
template <>
inline const std::string& ObjectPicker<std::optional<CommonEvent>>::getName(const std::optional<CommonEvent>& value) {
  return value ? value->name() : InvalidCommonEvent;
}

std::tuple<bool, bool> Dialog_CommonEvent::draw() {
  if (m_picker) {
    auto [closed, confirmed] = m_picker->draw();
    if (closed) {
      if (confirmed) {
        command->event = m_picker->selection();
        m_confirmed = true;
        setOpen(false);
        ImGui::CloseCurrentPopup();
      }
      m_picker.reset();
    }
  }
  return std::make_tuple(!m_open, m_confirmed);
}


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

#include "Database/CommonEvent.hpp"
#include "Database/Database.hpp"
#include "Database/EventCommands/CommonEvent.hpp"

using namespace std::string_view_literals;

class Dialog_CommonEvent final : public IEventDialogController {
public:
  Dialog_CommonEvent() = delete;
  explicit Dialog_CommonEvent(const std::string& name, const std::shared_ptr<CommonEventCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new CommonEventCommand());
    }
    eventId = command->event;
    m_picker = ObjectPicker("Common Events"sv, Database::instance()->commonEvents.events(), eventId);
    m_picker->setOpen(true);
  }
  std::tuple<bool, bool> draw() override;

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

private:
  int eventId;
  bool m_confirmed{false};
  std::shared_ptr<CommonEventCommand> command;
  std::optional<ObjectPicker<std::optional<CommonEvent>>> m_picker;
  std::tuple<bool, bool> result;
};