code:
#include "Core/EventCommands/Dialog_SetMovementRoute.hpp"
#include "Core/EventCommands/MovementRoute/Dialog_MovementChangeBlendMode.hpp"
#include "Core/EventCommands/MovementRoute/Dialog_MovementChangeFrequency.hpp"
#include "Core/EventCommands/MovementRoute/Dialog_MovementChangeImage.hpp"
#include "Core/EventCommands/MovementRoute/Dialog_MovementChangeOpacity.hpp"
#include "Core/EventCommands/MovementRoute/Dialog_MovementChangeSpeed.hpp"
#include "Core/EventCommands/MovementRoute/Dialog_MovementJump.hpp"
#include "Core/EventCommands/MovementRoute/Dialog_MovementScript.hpp"
#include "Core/EventCommands/MovementRoute/Dialog_MovementSwitchOFF.hpp"
#include "Core/EventCommands/MovementRoute/Dialog_MovementSwitchON.hpp"
#include "Core/EventCommands/MovementRoute/Dialog_MovementWait.hpp"
#include "Core/ImGuiExt/ImGuiUtils.hpp"
#include "Database/Database.hpp"
#include "Database/EventCommands/MovementRoute/DirectionFixOFF.hpp"
#include "Database/EventCommands/MovementRoute/DirectionFixON.hpp"
#include "Database/EventCommands/MovementRoute/Move1StepBackward.hpp"
#include "Database/EventCommands/MovementRoute/Move1StepForward.hpp"
#include "Database/EventCommands/MovementRoute/MoveAtRandom.hpp"
#include "Database/EventCommands/MovementRoute/MoveAwayFromPlayer.hpp"
#include "Database/EventCommands/MovementRoute/MoveDown.hpp"
#include "Database/EventCommands/MovementRoute/MoveLeft.hpp"
#include "Database/EventCommands/MovementRoute/MoveLowerLeft.hpp"
#include "Database/EventCommands/MovementRoute/MoveLowerRight.hpp"
#include "Database/EventCommands/MovementRoute/MoveRight.hpp"
#include "Database/EventCommands/MovementRoute/MoveTowardPlayer.hpp"
#include "Database/EventCommands/MovementRoute/MoveUp.hpp"
#include "Database/EventCommands/MovementRoute/MoveUpperLeft.hpp"
#include "Database/EventCommands/MovementRoute/MoveUpperRight.hpp"
#include "Database/EventCommands/MovementRoute/PlaySE.hpp"
#include "Database/EventCommands/MovementRoute/SteppingAnimationOFF.hpp"
#include "Database/EventCommands/MovementRoute/SteppingAnimationON.hpp"
#include "Database/EventCommands/MovementRoute/ThroughOFF.hpp"
#include "Database/EventCommands/MovementRoute/ThroughON.hpp"
#include "Database/EventCommands/MovementRoute/TransparentOFF.hpp"
#include "Database/EventCommands/MovementRoute/TransparentON.hpp"
#include "Database/EventCommands/MovementRoute/Turn180Deg.hpp"
#include "Database/EventCommands/MovementRoute/Turn90DegLeft.hpp"
#include "Database/EventCommands/MovementRoute/Turn90DegLeftOrRight.hpp"
#include "Database/EventCommands/MovementRoute/Turn90DegRight.hpp"
#include "Database/EventCommands/MovementRoute/TurnAtRandom.hpp"
#include "Database/EventCommands/MovementRoute/TurnAwayFromPlayer.hpp"
#include "Database/EventCommands/MovementRoute/TurnDown.hpp"
#include "Database/EventCommands/MovementRoute/TurnLeft.hpp"
#include "Database/EventCommands/MovementRoute/TurnRight.hpp"
#include "Database/EventCommands/MovementRoute/TurnTowardPlayer.hpp"
#include "Database/EventCommands/MovementRoute/TurnUp.hpp"
#include "Database/EventCommands/MovementRoute/WalkingAnimationOFF.hpp"
#include "Database/EventCommands/MovementRoute/WalkingAnimationON.hpp"
#include "imgui.h"
#include "MovementRoute/Dialogue_MovementPlaySE.hpp"

#include <clip.h>
#include <tuple>

static clip::format OREMovementCommand = -1;
std::tuple<bool, bool> Dialog_SetMovementRoute::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({ImGui::GetMainViewport()->Size.x / 2, ImGui::GetMainViewport()->Size.y / 2}, ImGuiCond_Appearing);
  if (ImGui::BeginPopupModal(m_name.c_str(), &m_open, ImGuiWindowFlags_NoScrollbar)) {
    const auto buttonsSize = ImGui::CalcTextSize("OKCANCEL");
    // Character Selection
    ImGui::BeginChild("##movementroute_top_child", {0, ImGui::GetContentRegionAvail().y - (buttonsSize.y + (ImGui::GetStyle().FramePadding.y * 2) + ImGui::GetStyle().ItemSpacing.y)});
    {
      m_hasFocus = ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_NoPopupHierarchy);
      const auto calc = ImGui::CalcTextSize("#######################");
      ImGui::BeginChild("##movementroute_inner_left_child", ImVec2{calc.x, 0}, ImGuiChildFlags_ResizeX | ImGuiChildFlags_Borders);
      {
        ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x);
        ImGui::BeginDisabled(m_isEventRoute);
        if (ImGui::BeginCombo("##showroute_character", m_isEventRoute ? "" : Database::instance()->eventNameOrId(m_character).c_str())) {

          if (ImGui::Selectable(trNOOP("Player"), m_character == -1)) {
            m_character = -1;
            ImGui::SetItemDefaultFocus();
          }
          if (ImGui::Selectable(trNOOP("This Event"), m_character == 0)) {
            m_character = 0;
            ImGui::SetItemDefaultFocus();
          }

          for (auto& dataSource : Database::instance()->mapInfos.currentMap()->map()->events()) {
            if (!dataSource)
              continue;

            bool is_selected = m_character == dataSource->id();
            if (ImGui::Selectable(Database::instance()->instance()->eventNameOrId(dataSource->id()).c_str(), is_selected)) {
              m_character = dataSource->id();
              if (is_selected)
                ImGui::SetItemDefaultFocus();
            }
          }
          ImGui::EndCombo();
        }
        ImGui::EndDisabled();

        if (ImGui::BeginTable("##route_commands", 1, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY,
                              {ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x, (calc.y + ImGui::GetStyle().ItemSpacing.y) * 16})) {
          ImGui::TableSetupScrollFreeze(1, 0);
          ImGui::TableSetupColumn(trNOOP("Step"));
          ImGui::TableNextRow();
          ImGui::TableNextColumn();

          for (int n = 0; n < m_route->list().size(); n++) {
            ImGui::TableNextColumn();
            const bool isSelected = m_selected == n || (m_selectedEnd != -1 && n > m_selected && n <= m_selectedEnd);
            char text[4096];
            sprintf(text, "%s##cmd%i", m_route->list().at(n)->stringRep(*Database::instance()).c_str(), n);
            if (ImGui::SelectableWithBorder(text, isSelected, ImGuiSelectableFlags_AllowOverlap | ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick)) {
              if (ImGui::GetMouseClickedCount(ImGuiMouseButton_Left) >= 2) {
                if (m_route->list().at(m_selected)->code() == EventCode::Jump) {
                  m_isNewEntry = false;
                  auto movementCmd = std::dynamic_pointer_cast<MovementJumpCommand>(m_route->list().at(m_selected));
                  m_movementRouteDialog = std::make_shared<Dialog_MovementJump>(trNOOP("Jump"), movementCmd);
                  m_movementRouteDialog->setOpen(true);
                }
                if (m_route->list().at(m_selected)->code() == EventCode::Wait_del_Movement) {
                  m_isNewEntry = false;
                  auto movementCmd = std::dynamic_pointer_cast<MovementWaitCommand>(m_route->list().at(m_selected));
                  m_movementRouteDialog = std::make_shared<Dialog_MovementWait>(trNOOP("Wait"), movementCmd);
                  m_movementRouteDialog->setOpen(true);
                }
                if (m_route->list().at(m_selected)->code() == EventCode::Switch_ON) {
                  m_isNewEntry = false;
                  auto movementCmd = std::dynamic_pointer_cast<MovementSwitchONCommand>(m_route->list().at(m_selected));
                  m_movementRouteDialog = std::make_shared<Dialog_MovementSwitchON>(trNOOP("Switch ON"), movementCmd);
                  m_movementRouteDialog->setOpen(true);
                }
                if (m_route->list().at(m_selected)->code() == EventCode::Switch_OFF) {
                  m_isNewEntry = false;
                  auto movementCmd = std::dynamic_pointer_cast<MovementSwitchOFFCommand>(m_route->list().at(m_selected));
                  m_movementRouteDialog = std::make_shared<Dialog_MovementSwitchOFF>(trNOOP("Switch OFF"), movementCmd);
                  m_movementRouteDialog->setOpen(true);
                }
                if (m_route->list().at(m_selected)->code() == EventCode::Speed) {
                  m_isNewEntry = false;
                  auto movementCmd = std::dynamic_pointer_cast<MovementSpeedCommand>(m_route->list().at(m_selected));
                  m_movementRouteDialog = std::make_shared<Dialog_MovementChangeSpeed>(trNOOP("Change Speed"), movementCmd);
                  m_movementRouteDialog->setOpen(true);
                }
                if (m_route->list().at(m_selected)->code() == EventCode::Frequency) {
                  m_isNewEntry = false;
                  auto movementCmd = std::dynamic_pointer_cast<MovementFrequencyCommand>(m_route->list().at(m_selected));
                  m_movementRouteDialog = std::make_shared<Dialog_MovementChangeFrequency>(trNOOP("Change Frequency"), movementCmd);
                  m_movementRouteDialog->setOpen(true);
                }
                if (m_route->list().at(m_selected)->code() == EventCode::Change_Image) {
                  m_isNewEntry = false;
                  auto movementCmd = std::dynamic_pointer_cast<MovementChangeImageCommand>(m_route->list().at(m_selected));
                  m_movementRouteDialog = std::make_shared<Dialog_MovementChangeImage>(trNOOP("Image"), movementCmd);
                  m_movementRouteDialog->setOpen(true);
                }
                if (m_route->list().at(m_selected)->code() == EventCode::Change_Opacity) {
                  m_isNewEntry = false;
                  auto movementCmd = std::dynamic_pointer_cast<MovementChangeOpacityCommand>(m_route->list().at(m_selected));
                  m_movementRouteDialog = std::make_shared<Dialog_MovementChangeOpacity>(trNOOP("Opacity"), movementCmd);
                  m_movementRouteDialog->setOpen(true);
                }
                if (m_route->list().at(m_selected)->code() == EventCode::Change_Blend_Mode) {
                  m_isNewEntry = false;
                  auto movementCmd = std::dynamic_pointer_cast<MovementChangeBlendModeCommand>(m_route->list().at(m_selected));
                  m_movementRouteDialog = std::make_shared<Dialog_MovementChangeBlendMode>(trNOOP("Blend"), movementCmd);
                  m_movementRouteDialog->setOpen(true);
                }
                if (m_route->list().at(m_selected)->code() == EventCode::Play_SE_del_Movement) {
                  m_isNewEntry = false;
                  auto movementCmd = std::dynamic_pointer_cast<MovementPlaySECommand>(m_route->list().at(m_selected));
                  m_movementRouteDialog = std::make_shared<Dialog_MovementPlaySE>(trNOOP("Play SE"), movementCmd);
                  m_movementRouteDialog->setOpen(true);
                }
                if (m_route->list().at(m_selected)->code() == EventCode::Script_del_Movement) {
                  m_isNewEntry = false;
                  auto movementCmd = std::dynamic_pointer_cast<MovementScriptCommand>(m_route->list().at(m_selected));
                  m_movementRouteDialog = std::make_shared<Dialog_MovementScript>(trNOOP("Script"), movementCmd);
                  m_movementRouteDialog->setOpen(true);
                }
              }

              if (!ImGui::IsKeyDown(ImGuiKey_LeftShift) && !ImGui::IsKeyDown(ImGuiKey_RightShift)) {
                m_selected = n;
              }

              if (isSelected)
                ImGui::SetItemDefaultFocus();

              if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) {
                if (m_selected == -1) {
                  m_selected = n;
                }
                if (n < m_selected) {
                  // m_selected = n;
                  if (m_selectedEnd == -1) {
                    m_selectedEnd = m_selected;
                    m_selected = n;
                  } else {
                    m_selected = n;
                  }
                } else {
                  m_selectedEnd = n;
                  // m_selected = m_selected;
                }
              } else {
                m_selectedEnd = -1;
              }
            }
          }
          ImGui::EndTable();
        }
        handleClipboardInteraction();
        if (ImGui::IsKeyPressed((ImGuiKey_Delete)) && m_hasFocus) {
          if (m_route->list().at(m_selected)->code() != EventCode::Event_Dummy) {
            int start = m_selected;
            // int end = m_selectedEnd == -1 ? m_selected + 1 : m_selectedEnd + 1;
            m_route->list().erase(m_route->list().begin() + start, m_route->list().begin() + (start + 1));
          }
        }
        ImGui::TextUnformatted(trNOOP("Options"));
        bool tmp = m_route->repeat();
        if (ImGui::Checkbox(trNOOP("Repeat Movements"), &tmp)) {
          m_route->setRepeat(tmp);
        }
        tmp = m_route->skippable();
        if (ImGui::Checkbox(trNOOP("Skip If Cannot Move"), &tmp)) {
          m_route->setSkippable(tmp);
        }
        tmp = m_route->wait();
        ImGui::BeginDisabled(m_isEventRoute);
        if (ImGui::Checkbox(trNOOP("Wait for Completion"), &tmp)) {
          m_route->setWait(tmp);
        }
        ImGui::EndDisabled();
      }
      ImGui::EndChild();
      ImGui::SameLine();
      ImGui::BeginChild("##movementroute_inner_right_child");
      {
        ImGui::SeparatorText("Movement Commands");
        ImGui::BeginGroup();
        {
          if (ImGui::Button(trNOOP("Move Down"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementMoveDownCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Move Left"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementMoveLeftCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Move Right"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementMoveRightCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Move Up"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementMoveUpCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Move Lower Left"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementMoveLowerLeftCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Move Lower Right"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementMoveLowerRightCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Move Upper Left"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementMoveUpperLeftCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Move Upper Right"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementMoveUpperRightCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Move at Random"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementMoveAtRandomCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Move toward Player"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementMoveTowardPlayerCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Move away from Player"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementMoveAwayFromPlayerCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("1 Step Forward"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementMove1StepForwardCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("1 Step Backward"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementMove1StepBackwardCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Jump..."), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_movementRouteDialog = std::make_shared<Dialog_MovementJump>(trNOOP("Jump"));
            m_movementRouteDialog->setOpen(true);
          }
          if (ImGui::Button(trNOOP("Wait..."), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_movementRouteDialog = std::make_shared<Dialog_MovementWait>(trNOOP("Wait"));
            m_movementRouteDialog->setOpen(true);
          }
        }
        ImGui::EndGroup();
        ImGui::SameLine();
        ImGui::BeginGroup();
        {
          if (ImGui::Button(trNOOP("Turn Down"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementTurnDownCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Turn Left"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementTurnLeftCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Turn Right"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementTurnRightCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Turn Up"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementTurnUpCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Turn 90° Right"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementTurn90DegRightCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Turn 90° Left"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementTurn90DegLeftCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Turn 180°"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementTurn180DegCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Turn 90° Right or Left"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementTurn90DegLeftOrRightCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Turn at Random"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementTurnAtRandomCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Turn toward Player"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementTurnTowardPlayerCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Turn away from Player"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementTurnAwayFromPlayerCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Switch ON..."), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_movementRouteDialog = std::make_shared<Dialog_MovementSwitchON>(trNOOP("Switch ON"));
            m_movementRouteDialog->setOpen(true);
          }
          if (ImGui::Button(trNOOP("Switch OFF..."), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_movementRouteDialog = std::make_shared<Dialog_MovementSwitchOFF>(trNOOP("Switch OFF"));
            m_movementRouteDialog->setOpen(true);
          }
          if (ImGui::Button(trNOOP("Change Speed..."), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_movementRouteDialog = std::make_shared<Dialog_MovementChangeSpeed>(trNOOP("Change Speed"));
            m_movementRouteDialog->setOpen(true);
          }
          if (ImGui::Button(trNOOP("Change Frequency..."), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_movementRouteDialog = std::make_shared<Dialog_MovementChangeFrequency>(trNOOP("Change Frequency"));
            m_movementRouteDialog->setOpen(true);
          }
          ImGui::EndGroup();
        }
        ImGui::SameLine();
        ImGui::BeginGroup();
        {
          if (ImGui::Button(trNOOP("Walking Animation ON"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementWalkingAnimationONCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Walking Animation OFF"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementWalkingAnimationOFFCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Stepping Animation ON"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementSteppingAnimationONCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Stepping Animation OFF"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementSteppingAnimationOFFCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Direction Fix ON"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementDirectionFixONCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Direction Fix OFF"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementDirectionFixOFFCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Through ON"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementThroughONCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Through OFF"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementThroughOFFCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Transparent ON"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementTransparentONCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Transparent OFF"), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_selected = m_route->addCommand(std::make_shared<MovementTransparentOFFCommand>(), m_selected);
          }
          if (ImGui::Button(trNOOP("Change Image..."), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_movementRouteDialog = std::make_shared<Dialog_MovementChangeImage>(trNOOP("Image"));
            m_movementRouteDialog->setOpen(true);
          }
          if (ImGui::Button(trNOOP("Change Opacity..."), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_movementRouteDialog = std::make_shared<Dialog_MovementChangeOpacity>(trNOOP("Opacity"));
            m_movementRouteDialog->setOpen(true);
          }
          if (ImGui::Button(trNOOP("Change Blend Mode..."), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_movementRouteDialog = std::make_shared<Dialog_MovementChangeBlendMode>(trNOOP("Blend"));
            m_movementRouteDialog->setOpen(true);
          }
          if (ImGui::Button(trNOOP("Play SE..."), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_movementRouteDialog = std::make_shared<Dialog_MovementPlaySE>(trNOOP("Play SE"));
            m_movementRouteDialog->setOpen(true);
          }
          if (ImGui::Button(trNOOP("Script..."), ImVec2{(ImGui::GetContentRegionMax().x / 3) - ImGui::GetStyle().FramePadding.x, 0})) {
            m_movementRouteDialog = std::make_shared<Dialog_MovementScript>(trNOOP("Script"));
            m_movementRouteDialog->setOpen(true);
          }
          ImGui::EndGroup();
        }
      }
      ImGui::EndChild();
    }
    ImGui::EndChild();
    ImGui::BeginChild("##movementroute_bottom_child");
    {
      ImGui::SetCursorPosX(ImGui::GetContentRegionMax().x - (buttonsSize.x + (ImGui::GetStyle().FramePadding.x * 3) + ImGui::GetStyle().ItemSpacing.x));
      if (ImGui::Button(trNOOP("OK"))) {
        m_confirmed = true;
        if (m_isEventRoute) {
          m_page->setMoveRoute(*m_route);
        } else {
          m_command->character = m_character;
          // m_command->route = m_route;
        }
        ImGui::CloseCurrentPopup();
        setOpen(false);
      }
      ImGui::SameLine();
      if (ImGui::Button(trNOOP("Cancel"))) {
        ImGui::CloseCurrentPopup();
        setOpen(false);
      }
    }
    ImGui::EndChild();

    if (m_movementRouteDialog) {
      if (const auto [closed, confirmed] = m_movementRouteDialog->draw(); closed) {
        if (confirmed) {
          if (m_isNewEntry) {
            m_selected = m_route->addCommand(m_movementRouteDialog->getCommand(), m_selected);
          } else {
            m_route->list().at(m_selected) = m_movementRouteDialog->getCommand();
          }
          m_isNewEntry = true;
        }
        m_movementRouteDialog.reset();
      }
    }
    ImGui::EndPopup();
  }

  return std::make_tuple(!m_open, m_confirmed);
}
void Dialog_SetMovementRoute::handleClipboardInteraction() const {
  if (!m_hasFocus) {
    return;
  }
  if (OREMovementCommand == -1) {
    OREMovementCommand = clip::register_format("application/ore-MovementCommand");
  }
  if (ImGui::IsKeyPressed(ImGuiKey_V) && (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl))) {

    clip::lock l;
    if (l.is_convertible(OREMovementCommand)) {
      auto len = l.get_data_length(OREMovementCommand);
      std::string cmd;
      cmd.resize(len);
      if (l.get_data(OREMovementCommand, cmd.data(), len)) {
        nlohmann::ordered_json cmdJson = nlohmann::ordered_json::parse(cmd);
        CommandParser parser;
        auto commands = parser.parse(cmdJson);
        int curIndent = m_selected > 0 ? *m_route->list().at(m_selected)->indent() : 0;
        int nestedCount = 0;

        for (auto& command : commands) {
          if (!command->indent()) {
            command->setIndent(0);
          }

          command->setIndent(curIndent);
        }
        m_route->list().insert(m_route->list().begin() + m_selected, commands.begin(), commands.end());
      }
    }

  } else if (ImGui::IsKeyPressed(ImGuiKey_C) && (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl))) {
    clip::lock l;
    int start = m_selected;
    int end = m_selectedEnd == -1 ? m_selected + 1 : m_selectedEnd + 1;
    if (m_route->list().at(end - 1)->code() == EventCode::Event_Dummy) {
      end -= 1; // We don't want to copy or cut a dummy
    }
    std::vector<std::shared_ptr<IEventCommand>> commands(m_route->list().begin() + start, m_route->list().begin() + end);
    nlohmann::ordered_json cmdJson;
    CommandParser::serialize(cmdJson, commands);
    auto v = cmdJson.dump();
    l.set_data(OREMovementCommand, v.data(), v.size());
  } else if (ImGui::IsKeyPressed(ImGuiKey_X) && (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl))) {
    if (m_route->list().at(m_selected)->code() != EventCode::Event_Dummy) {
      clip::lock l;
      int start = m_selected;
      int end = m_selectedEnd == -1 ? m_selected + 1 : m_selectedEnd + 1;
      if (m_route->list().at(end - 1)->code() == EventCode::Event_Dummy) {
        end -= 1; // We don't want to copy or cut a dummy
      }
      std::vector<std::shared_ptr<IEventCommand>> commands(m_route->list().begin() + start, m_route->list().begin() + end);
      nlohmann::ordered_json cmdJson;
      CommandParser::serialize(cmdJson, commands);
      auto v = cmdJson.dump();
      l.set_data(OREMovementCommand, v.data(), v.size());
      m_route->list().erase(m_route->list().begin() + start, m_route->list().begin() + end);
    }
  }
}


code:
#pragma once
#include <utility>

#include "Core/CommonUI/VariableSwitchPicker.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/EventDummy.hpp"
#include "Database/EventCommands/MovementRoute/Frequency.hpp"
#include "Database/EventCommands/SetEventLocation.hpp"
#include "Database/EventCommands/SetMovementRoute.hpp"
#include "Database/EventPage.hpp"

struct Dialog_SetMovementRoute : IEventDialogController {
  Dialog_SetMovementRoute() = delete;
  explicit Dialog_SetMovementRoute(const std::string& name, const std::shared_ptr<SetMovementRouteCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new SetMovementRouteCommand());
    }
    m_character = m_command->character;
    m_route = &m_command->route;
    m_editNodes = m_command->editNodes;
    if (m_route->list().empty()) {
      m_route->addCommand(std::make_shared<EventDummy>(), 0);
    }
  }
  explicit Dialog_SetMovementRoute(const std::string& name, EventPage* page)
  : IEventDialogController(name)
  , m_page(page) {
    m_isEventRoute = true;
    m_route = &m_page->moveRoute();
    if (m_route->list().empty()) {
      m_route->addCommand(std::make_shared<EventDummy>(), 0);
    } else {
      if (m_route->list().back()->code() != EventCode::Event_Dummy) {
        m_route->addCommand(std::make_shared<EventDummy>(), m_route->list().size());
      }
    }
  }
  std::tuple<bool, bool> draw() override;
  void handleClipboardInteraction() const;

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

  void setPage(EventPage* page) {
    m_isEventRoute = true;
    m_route = &m_page->moveRoute();
    if (m_route->list().empty()) {
      m_route->addCommand(std::make_shared<EventDummy>(), 0);
    }
  }

private:
  int m_character{-1};
  int m_selected{0};
  int m_selectedEnd{0};

  EventPage* m_page = nullptr; // For event routes only
  MovementRoute* m_route;
  std::vector<std::shared_ptr<MovementRouteStepCommand>> m_editNodes;

  bool m_confirmed{false};
  bool m_isEventRoute{false};
  std::shared_ptr<SetMovementRouteCommand> m_command;
  std::shared_ptr<IEventDialogController> m_movementRouteDialog;
  std::optional<VariableSwitchPicker> picker;
  std::tuple<bool, bool> result;
  bool m_hasFocus{false};

  bool m_isNewEntry{true};
};

repo_name: Antidote/openrpgeditor

license: mit


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

  if (ImGui::BeginPopupModal(std::format("{}###SetVehicleLocation", m_name).c_str(), &m_open, ImGuiWindowFlags_NoResize)) {
    drawPickers();
    ImGui::BeginVertical("##set_vehicle_location_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      GroupBox vehicleGroupBox(trNOOP("Vehicle"), "##set_vehicle_location_vehicle_group", {-1, 0});
      if (vehicleGroupBox.begin()) {
        ImGui::PushItemWidth(-1);
        if (ImGui::BeginCombo("##set_vehicle_location_vehicle_selection", DecodeEnumName(magic_enum::enum_cast<VehicleType>(m_vehicle).value_or(VehicleType::Boat)).c_str())) {
          for (auto& vehicle : magic_enum::enum_values<VehicleType>()) {
            bool selected = m_vehicle == static_cast<int>(vehicle);
            if (ImGui::Selectable(DecodeEnumName(vehicle).c_str(), selected)) {
              m_vehicle = static_cast<int>(vehicle);
            }
            if (selected) {
              ImGui::SetItemDefaultFocus();
            }
          }
          ImGui::EndCombo();
        }
      }
      vehicleGroupBox.end();
      GroupBox locationGroupBox(trNOOP("Location"), "##set_vehicle_location_location_group", {-1, 0});
      if (locationGroupBox.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());
            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_vehicle_location_location_variables", {-1, 0}, 0);
          {
            ImGui::Dummy({ImGui::GetFrameHeight(), ImGui::GetFrameHeight()});
            ImGui::BeginVertical("##set_vehicle_location_location_variables_inner", {-1, 0}, 0);
            {

              GroupBox idPosGroup("ID", "##set_vehicle_location_location_variables_id", {-1, 0});
              if (idPosGroup.begin()) {
                ImGui::PushID("##set_vehicle_location_variables_id");
                if (ImGui::EllipsesButton(m_mode == 1 ? Database::instance()->variableNameAndId(m_mapIdVar).c_str() : "", {-1, 0})) {
                  m_variableSelection = 0;
                  m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_mapIdVar);
                  m_variablePicker->setOpen(true);
                }
                ImGui::PopID();
              }
              idPosGroup.end();

              GroupBox xPosGroup("X", "##set_vehicle_location_location_variables_x", {-1, 0});
              if (xPosGroup.begin()) {
                ImGui::PushID("##set_vehicle_location_variables_x");
                if (ImGui::EllipsesButton(m_mode == 1 ? Database::instance()->variableNameAndId(m_xVar).c_str() : "", {-1, 0})) {
                  m_variableSelection = 1;
                  m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_xVar);
                  m_variablePicker->setOpen(true);
                }
                ImGui::PopID();
              }
              xPosGroup.end();
              GroupBox yPosGroup("Y", "##set_vehicle_location_location_variables_y", {-1, 0});
              if (yPosGroup.begin()) {
                ImGui::PushID("##set_vehicle_location_variables_y");
                if (ImGui::EllipsesButton(m_mode == 1 ? Database::instance()->variableNameAndId(m_yVar).c_str() : "", {-1, 0})) {
                  m_variableSelection = 2;
                  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();
      }
      locationGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##set_vehicle_location_button_layout", {-1, 0}, 0);
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##set_vehicle_location_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->vehicle = static_cast<VehicleType>(m_vehicle);
          m_command->mode = static_cast<TransferMode>(m_mode);
          if (m_command->mode == TransferMode::Variable_Designation) {
            m_command->mapId = m_mapIdVar;
            m_command->x = m_xVar;
            m_command->y = m_yVar;
          } else {
            m_command->mapId = m_mapId;
            m_command->x = m_x;
            m_command->y = m_y;
          }

          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_SetVehicleLocation::drawPickers() {
  if (m_variablePicker) {
    if (const auto [closed, confirmed] = m_variablePicker->draw(); closed) {
      if (confirmed) {
        switch (m_variableSelection) {
        case 0:
          m_mapIdVar = m_variablePicker->selection();
          break;
        case 1:
          m_xVar = m_variablePicker->selection();
          break;
        case 2:
          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/SetVehicleLocation.hpp"
#include "Database/EventCommands/TransferPlayer.hpp"

struct Dialog_SetVehicleLocation : IEventDialogController {
  Dialog_SetVehicleLocation() = delete;
  explicit Dialog_SetVehicleLocation(const std::string& name, const std::shared_ptr<SetVehicleLocationCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new SetVehicleLocationCommand());
    }
    m_mode = static_cast<int>(m_command->mode);
    m_vehicle = static_cast<int>(m_command->vehicle);
    if (m_command->mode == TransferMode::Variable_Designation) {
      m_mapIdVar = m_command->mapId;
      m_xVar = m_command->x;
      m_yVar = m_command->y;
    } else {
      m_mapId = m_command->mapId;
      m_x = m_command->x;
      m_y = m_command->y;
    }
  }
  void drawPickers();
  std::tuple<bool, bool> draw() override;

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

private:
  int m_vehicle{};
  int m_mode{};
  int m_mapId{};
  int m_x{};
  int m_y{};

  int m_mapIdVar{1};
  int m_xVar{1};
  int m_yVar{1};
  int m_variableSelection{};

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


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

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

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

    ImGui::SeparatorText("Weather");
    ImGui::BeginGroup();
    {
      ImGui::Text("Type:");
      ImGui::SetCursorPosY(ImGui::GetCursorPos().y + 8.f);
      ImGui::Text("Power:");
    }
    ImGui::EndGroup();
    ImGui::SameLine();
    ImGui::BeginGroup();
    {
      ImGui::PushItemWidth((160));
      if (ImGui::BeginCombo("##weather_effect_selection", DecodeEnumName(magic_enum::enum_value<WeatherEffect>(m_effect)).c_str())) {
        for (auto& effect : magic_enum::enum_values<WeatherEffect>()) {
          bool is_selected = m_effect == magic_enum::enum_index(effect).value();
          if (ImGui::Selectable(DecodeEnumName(magic_enum::enum_name(effect)).c_str(), is_selected)) {
            m_effect = magic_enum::enum_index(effect).value();
            if (is_selected)
              ImGui::SetItemDefaultFocus();
          }
        }
        ImGui::EndCombo();
      }
      ImGui::PushItemWidth((160));
      ImGui::SliderInt("##weather_effect_power", &m_power, 1, 9, "", ImGuiSliderFlags_NoInput);
      ImGui::SameLine();
      ImGui::PushItemWidth((80));
      if (ImGui::InputInt("##weather_effect_power_int", &m_power)) {
        if (m_power > 9)
          m_power = 9;
        if (m_power < 1)
          m_power = 1;
      }
    }
    ImGui::EndGroup();
    ImGui::SeparatorText("Duration");
    ImGui::SetNextItemWidth(100);
    if (ImGui::InputInt("##tintscreen_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->effect = static_cast<WeatherEffect>(m_effect);
      command->power = m_power;
      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/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/SetWeatherEffect.hpp"

struct Dialog_SetWeatherEffect : IEventDialogController {
  Dialog_SetWeatherEffect() = delete;
  explicit Dialog_SetWeatherEffect(const std::string& name, const std::shared_ptr<SetWeatherEffectCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new SetWeatherEffectCommand());
    }
    m_effect = static_cast<int>(command->effect);
    m_power = command->power;
    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_effect;
  int m_power;
  int m_duration;
  bool m_waitForCompletion;

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


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

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

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

    ImGui::SeparatorText("Shake");
    ImGui::BeginGroup();
    {
      ImGui::Text("Power:");
      ImGui::SetCursorPosY(ImGui::GetCursorPos().y + 8.f);
      ImGui::Text("Speed:");
    }
    ImGui::EndGroup();
    ImGui::SameLine();
    ImGui::BeginGroup();
    {
      ImGui::SetNextItemWidth(150);
      ImGui::SliderInt("##shakescreen_power", &m_power, -1, 9, "", ImGuiSliderFlags_NoInput);
      ImGui::SameLine();
      ImGui::SetNextItemWidth(75);
      if (ImGui::InputInt("##shakescreen_power_int", &m_power, 1, 100)) {
        if (m_power < 1)
          m_power = 1;
        if (m_power > 9)
          m_power = 9;
      }

      ImGui::SetNextItemWidth(150);
      ImGui::SliderInt("##shakescreen_speed", &m_speed, 1, 9, "", ImGuiSliderFlags_NoInput);
      ImGui::SameLine();
      ImGui::SetNextItemWidth(75);
      if (ImGui::InputInt("##shakescreen_speed_int", &m_speed, 1, 100)) {
        if (m_speed < 1)
          m_speed = 1;
        if (m_speed > 9)
          m_speed = 9;
      }
    }
    ImGui::EndGroup();
    ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 4.f);
    ImGui::PushItemWidth(390);
    if (ImGui::BeginCombo("##flashscreen_presets", "Future presets go in this list")) {
      // TODO: Template system
      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->power = m_power;
      command->speed = m_speed;
      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/EventCommands/IEventDialogController.hpp"
#include "Database/EventCommands/ShakeScreen.hpp"

struct Dialog_ShakeScreen : IEventDialogController {
  Dialog_ShakeScreen() = delete;
  explicit Dialog_ShakeScreen(const std::string& name, const std::shared_ptr<ShakeScreenCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new ShakeScreenCommand());
    }
    m_power = command->power;
    m_speed = command->speed;
    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_power;
  int m_speed;
  int m_duration;
  bool m_waitForCompletion;

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


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

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

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

  if (ImGui::BeginPopupModal(std::format("{}###ShopProcessing", m_name).c_str(), &m_open, ImGuiWindowFlags_NoResize)) {
    drawPickers();
    ImGui::BeginVertical("##shop_processing_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      if (ImGui::IsKeyPressed(ImGuiKey_Delete) && !m_goods.empty() && m_selection >= 0) {
        m_goods.erase(m_goods.begin() + m_selection);
        if (m_selection >= m_goods.size()) {
          m_selection = std::max<int>(-1, m_goods.size() - 1);
        }
      }

      if (ImGui::BeginTable("##shop_processing_main", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY,
                            ImVec2{-1, ImGui::GetContentRegionAvail().y - (ImGui::GetFrameHeightWithSpacing() + (ImGui::GetStyle().FramePadding.y * 2))})) {
        ImGui::TableSetupScrollFreeze(2, 1);
        ImGui::TableSetupColumn(trNOOP("Merchandise"), ImGuiTableColumnFlags_WidthStretch, 0.5f);
        ImGui::TableSetupColumn(trNOOP("Price"), ImGuiTableColumnFlags_WidthStretch, 0.5f);
        ImGui::TableHeadersRow();
        ImGui::TableNextRow();

        for (int n = 0; n < m_goods.size(); n++) {
          ImGui::TableNextRow();
          const int itemId = m_goods.at(n)->id;
          if (ImGui::TableNextColumn()) {
            std::string text = m_goods.at(n)->type == ShopType::Armor  ? Database::instance()->armorName(itemId)
                               : m_goods.at(n)->type == ShopType::Item ? Database::instance()->itemName(itemId)
                                                                       : Database::instance()->weaponName(itemId);
            const auto selected = (m_selection == n);
            if (ImGui::SelectableWithBorder(std::format("{}##{}", text, n).c_str(), selected,
                                            ImGuiSelectableFlags_AllowOverlap | ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick)) {
              if (ImGui::GetMouseClickedCount(ImGuiMouseButton_Left) >= 2) {
                m_goodsDialog.emplace(trNOOP("Goods Processing"), m_goods.at(n));
                m_goodsDialog->setOpen(true);
              }
              m_selection = n;
            }
            if (selected) {
              ImGui::SetItemDefaultFocus();
            }
          }
          if (ImGui::TableNextColumn()) {
            std::string text = m_goods.at(n)->priceType == PriceType::Specific ? std::to_string(m_goods.at(n)->price)
                                                                               : (m_goods.at(n)->type == ShopType::Armor  ? std::to_string(Database::instance()->armors.armor(itemId)->price())
                                                                                : m_goods.at(n)->type == ShopType::Item ? std::to_string(Database::instance()->items.item(itemId)->price())
                                                                                : std::to_string(Database::instance()->weapons.weapon(itemId)->price()));
            ImGui::Text("%s", text.c_str());
          }
        }

        ImGui::TableNextRow();
        if (ImGui::TableNextColumn()) {
          const auto selected = m_selection == -1;
          if (ImGui::SelectableWithBorder("##dummy_shop_processing_selection", selected,
                                          ImGuiSelectableFlags_AllowOverlap | ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick)) {

            if (ImGui::GetMouseClickedCount(ImGuiMouseButton_Left) >= 2) {
              m_goodsDialog.emplace(trNOOP("Goods Processing"));
              m_goodsDialog->setOpen(true);
            }
            m_selection = -1;
          }
          if (selected) {
            ImGui::SetItemDefaultFocus();
          }
        }
        ImGui::TableNextColumn();
        ImGui::EndTable();
      }
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##shop_processing_button_layout", {-1, 0}, 0);
      {
        ImGui::Checkbox(trNOOP("Purchase Only"), &m_purchaseOnly);
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##shop_processing_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          // If we don't have any goods we don't want to create a command, this differs from MV/MZ on purpose so we don't create an invalid shop by accident.
          if (!m_goods.empty()) {
            m_confirmed = true;
            // Grab and erase the first good
            const auto firstGood = std::dynamic_pointer_cast<ShopProcessingGoodCommand>(m_goods.front()->clone());
            m_goods.erase(m_goods.begin());
            m_command->id = firstGood->id;
            m_command->purchaseOnly = m_purchaseOnly;
            m_command->priceType = firstGood->priceType;
            m_command->type = firstGood->type;
            m_command->price = firstGood->price;
            m_command->goods = m_goods;
          } else {
            m_confirmed = false;
          }
          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_ShopProcessing::drawPickers() {
  if (m_goodsDialog) {
    if (const auto [closed, confirmed] = m_goodsDialog->draw(); closed) {
      if (confirmed) {
        if (m_selection == -1) {
          m_goods.emplace_back(std::dynamic_pointer_cast<ShopProcessingGoodCommand>(m_goodsDialog->getCommand()->clone()));
          m_selection = std::max<int>(0, m_goods.size() - 1);
        }
      }
      m_goodsDialog.reset();
    }
  }
}


code:
#pragma once
#include "Core/EventCommands/Dialog_ShopProcessing_Goods.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Core/Log.hpp"
#include "Database/EventCommands/ShopProcessing.hpp"

struct Dialog_ShopProcessing : IEventDialogController {
  Dialog_ShopProcessing() = delete;
  explicit Dialog_ShopProcessing(const std::string& name, const std::shared_ptr<ShopProcessingCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ShopProcessingCommand());
    } else {
      const auto& good = m_goods.emplace_back(new ShopProcessingGoodCommand());
      good->id = m_command->id;
      good->type = m_command->type;
      good->price = m_command->price;
      good->priceType = m_command->priceType;
      for (const auto& g : m_command->goods) {
        m_goods.emplace_back(std::dynamic_pointer_cast<ShopProcessingGoodCommand>(g->clone()));
      }
    }
    m_purchaseOnly = m_command->purchaseOnly;
  }

  void drawPickers();
  std::tuple<bool, bool> draw() override;

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

private:
  int m_selection{0};
  std::vector<std::shared_ptr<ShopProcessingGoodCommand>> m_goods;
  bool m_purchaseOnly;

  bool m_confirmed{false};
  std::shared_ptr<ShopProcessingCommand> m_command;
  std::optional<Dialog_ShopProcessing_Goods> m_goodsDialog;
};


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

  if (ImGui::BeginPopupModal(std::format("{}###ShopProcessing_Goods", m_name).c_str(), &m_open, ImGuiWindowFlags_NoResize)) {
    drawPickers();
    ImGui::BeginVertical("##shop_processing_goods_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      GroupBox merchandiseGroupBox(trNOOP("Merchandise"), "##shop_processing_goods_merchandise_group", {-1, 0});
      if (merchandiseGroupBox.begin()) {
        ImGui::BeginHorizontal("##shop_processing_goods_merchandise_group_main_layout", {-1, 0}, 0);
        {
          ImGui::BeginVertical("##shop_processing_goods_merchandise_group_left_layout", {-1, 0}, 0);
          {
            for (const auto type : magic_enum::enum_values<ShopType>()) {
              ImGui::RadioButton(DecodeEnumName(type).c_str(), &m_typeSelection, static_cast<int>(type));
            }
          }
          ImGui::EndVertical();
          ImGui::BeginVertical("##shop_processing_goods_merchandise_group_right_layout", {-1, 0}, 0);
          {
            ImGui::BeginDisabled(m_typeSelection != 0);
            {
              if (ImGui::EllipsesButton(m_typeSelection != 0 ? "##shop_processing_goods_merchandise_item_button" : Database::instance()->itemNameAndId(m_itemSelection).c_str(), ImVec2{-1, 0})) {
                m_itemPicker.emplace(trNOOP("Items"), Database::instance()->items.items(), m_itemSelection);
                m_itemPicker->setOpen(true);
              }
            }
            ImGui::EndDisabled();
            ImGui::BeginDisabled(m_typeSelection != 1);
            {
              if (ImGui::EllipsesButton(m_typeSelection != 1 ? "##shop_processing_goods_merchandise_weapon_button" : Database::instance()->weaponNameAndId(m_weaponSelection).c_str(), ImVec2{-1, 0})) {
                m_weaponPicker.emplace(trNOOP("Weapons"), Database::instance()->weapons.weapons(), m_weaponSelection);
                m_weaponPicker->setOpen(true);
              }
            }
            ImGui::EndDisabled();
            ImGui::BeginDisabled(m_typeSelection != 2);
            {
              if (ImGui::EllipsesButton(m_typeSelection != 2 ? "##shop_processing_goods_merchandise_armor_button" : Database::instance()->armorNameAndId(m_armorSelection).c_str(), ImVec2{-1, 0})) {
                m_armorPicker.emplace(trNOOP("Armors"), Database::instance()->armors.armors(), m_armorSelection);
                m_armorPicker->setOpen(true);
              }
            }
            ImGui::EndDisabled();
          }
          ImGui::EndVertical();
        }
        ImGui::EndHorizontal();
      }
      merchandiseGroupBox.end();
      GroupBox priceGroupBox(trNOOP("Price"), "##shop_processing_goods_price_group", {-1, 0});
      if (priceGroupBox.begin()) {
        ImGui::BeginHorizontal("##shop_processing_goods_price_group_main_layout", {-1, 0}, 0);
        {
          ImGui::BeginVertical("##shop_processing_goods_price_group_left_layout", {-1, 0}, 0);
          {
            for (const auto type : magic_enum::enum_values<PriceType>()) {
              ImGui::RadioButton(DecodeEnumName(type).c_str(), &m_priceOperation, static_cast<int>(type));
            }
          }
          ImGui::EndVertical();
          ImGui::BeginVertical("##shop_processing_goods_price_group_right_layout", {-1, 0}, 0);
          {
            ImGui::Dummy({0, ImGui::GetFrameHeightWithSpacing()});
            ImGui::BeginChild("##price_input", {-1, 0}, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_NavFlattened,
                              ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoScrollbar);
            {
              ImGui::BeginDisabled(m_priceOperation != 1);
              ImGui::SetNextItemWidth(-1);
              if (ImGui::SpinInt("##shop_processing_price", &m_priceConstant, 1, 100, m_priceOperation != 1 ? "" : nullptr)) {
                m_priceConstant = std::clamp(m_priceConstant, 0, 999999);
              }
              ImGui::EndDisabled();
            }
            ImGui::EndChild();
          }
          ImGui::EndVertical();
        }
        ImGui::EndHorizontal();
      }
      priceGroupBox.end();

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

          m_command->type = static_cast<ShopType>(m_typeSelection);
          m_command->priceType = static_cast<PriceType>(m_priceOperation);
          switch (m_command->type) {
          case ShopType::Armor:
            m_command->id = m_armorSelection;
            break;
          case ShopType::Weapon:
            m_command->id = m_weaponSelection;
            break;
          case ShopType::Item:
            m_command->id = m_itemSelection;
            break;
          }

          if (m_command->priceType == PriceType::Standard) {
            switch (m_command->type) {
            case ShopType::Armor:
              m_command->price = Database::instance()->armors.armor(m_command->id)->price();
              break;
            case ShopType::Weapon:
              m_command->price = Database::instance()->weapons.weapon(m_command->id)->price();
              break;
            case ShopType::Item:
              m_command->price = Database::instance()->items.item(m_command->id)->price();
              break;
            }
          } else {
            m_command->price = m_priceConstant;
          }
          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_ShopProcessing_Goods::drawPickers() {
  if (m_armorPicker) {
    if (const auto [closed, confirmed] = m_armorPicker->draw(); closed) {
      if (confirmed) {
        m_armorSelection = m_armorPicker->selection();
      }
      m_armorPicker.reset();
    }
  }
  if (m_itemPicker) {
    if (const auto [closed, confirmed] = m_itemPicker->draw(); closed) {
      if (confirmed) {
        m_itemSelection = m_itemPicker->selection();
      }
      m_itemPicker.reset();
    }
  }
  if (m_weaponPicker) {
    if (const auto [closed, confirmed] = m_weaponPicker->draw(); closed) {
      if (confirmed) {
        m_weaponSelection = m_weaponPicker->selection();
      }
      m_weaponPicker.reset();
    }
  }
}


code:
#pragma once
#include "Core/CommonUI/ObjectPicker.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/Armors.hpp"
#include "Database/Database.hpp"
#include "Database/EventCommands/ShopProcessing.hpp"
#include "Database/Items.hpp"
#include "Database/Weapons.hpp"

struct Dialog_ShopProcessing_Goods : IEventDialogController {
  Dialog_ShopProcessing_Goods() = delete;
  explicit Dialog_ShopProcessing_Goods(const std::string& name, const std::shared_ptr<ShopProcessingGoodCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ShopProcessingGoodCommand());
    }
    m_typeSelection = static_cast<int>(m_command->type);
    m_priceOperation = static_cast<int>(m_command->priceType);
    // ID
    if (m_command->type == ShopType::Armor) {
      m_armorSelection = m_command->id;
    } else if (m_command->type == ShopType::Weapon) {
      m_weaponSelection = m_command->id;
    } else {
      m_itemSelection = m_command->id;
    }
    // Price
    if (m_priceOperation == 0) {
      if (m_command->type == ShopType::Armor) {
        m_priceConstant = Database::instance()->armors.armor(m_armorSelection)->price();
      } else if (m_command->type == ShopType::Weapon) {
        m_priceConstant = Database::instance()->weapons.weapon(m_weaponSelection)->price();
      } else {
        m_priceConstant = Database::instance()->items.item(m_itemSelection)->price();
      }
    } else {
      m_priceConstant = m_command->price;
    }
  }
  explicit Dialog_ShopProcessing_Goods(const std::string& name, int id, const int price, const int shopType, const int priceType)
  : IEventDialogController(name) {
    m_command.reset(new ShopProcessingGoodCommand());
    if (id < 1)
      id = 1;

    m_typeSelection = shopType;
    m_priceOperation = priceType;
    // ID
    if (shopType == 2) {
      m_armorSelection = id;
    } else if (shopType == 1) {
      m_weaponSelection = id;
    } else if (shopType == 0) {
      m_itemSelection = id;
    }

    // Price
    if (priceType == 0) {
      if (shopType == 2) {
        m_priceConstant = Database::instance()->armors.armor(m_armorSelection)->price();
      } else if (shopType == 1) {
        m_priceConstant = Database::instance()->weapons.weapon(m_weaponSelection)->price();
      } else if (shopType == 0) {
        m_priceConstant = Database::instance()->items.item(m_itemSelection)->price();
      }
    } else {
      m_priceConstant = price;
    }
  }

  void drawPickers();
  std::tuple<bool, bool> draw() override;

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

private:
  int m_typeSelection{0};
  int m_itemSelection{1};
  int m_weaponSelection{1};
  int m_armorSelection{1};
  int m_priceOperation{0};
  int m_priceConstant{0};

  bool m_confirmed{false};
  std::optional<ObjectPicker<Item>> m_itemPicker;
  std::optional<ObjectPicker<Weapon>> m_weaponPicker;
  std::optional<ObjectPicker<Armor>> m_armorPicker;
  std::shared_ptr<ShopProcessingGoodCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_ShowAnimation.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_ShowAnimation::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ShowAnimation");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 36) + (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("{}###ShowAnimation", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    drawPickers();

    ImGui::BeginVertical("##show_animation_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      GroupBox characterGroupBox(trNOOP("Character"), "##show_animation_character_group", {-1, 0});
      if (characterGroupBox.begin()) {
        ImGui::SetNextItemWidth(-1);
        if (ImGui::BeginCombo("##show_animation_character_combo", Database::instance()->eventNameOrId(m_character).c_str())) {
          const auto currentMap = Database::instance()->mapInfos.currentMap();
          for (int i = -1; i < static_cast<int>(currentMap->map()->events().size()); ++i) {
            if (i > 0 && !currentMap->event(i)) {
              continue;
            }
            const auto name = Database::instance()->eventNameOrId(i);
            const auto selected = m_character == i;
            if (ImGui::Selectable(name.c_str(), selected)) {
              m_character = i;
            }
            if (selected) {
              ImGui::SetItemDefaultFocus();
            }
          }
          ImGui::EndCombo();
        }
      }
      characterGroupBox.end();
      GroupBox animationGroupBox(trNOOP("Animation"), "##show_animation_animation_group", {-1, 0});
      if (animationGroupBox.begin()) {
        if (ImGui::EllipsesButton(Database::instance()->animationNameAndId(m_animation).c_str(), {-1, 0})) {
          m_animationPicker.emplace(trNOOP("Animations"), Database::instance()->animations.animations(), m_animation);
          m_animationPicker->setOpen(true);
        }
      }
      animationGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##show_animation_button_layout", {-1, 0}, 0);
      {
        ImGui::Checkbox(trNOOP("Wait for Completion"), &m_waitCompletion);
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##show_animation_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->character = m_character;
          m_command->animation = m_animation;
          m_command->waitForCompletion = m_waitCompletion;
        } else if (ret == 1) {
          ImGui::CloseCurrentPopup();
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }

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

void Dialog_ShowAnimation::drawPickers() {
  if (m_animationPicker) {
    if (const auto [closed, confirmed] = m_animationPicker->draw(); closed) {
      if (confirmed) {
        m_animation = m_animationPicker->selection();
      }
      m_animationPicker.reset();
    }
  }
}


code:
#pragma once
#include "Core/CommonUI/ObjectPicker.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/Animation.hpp"
#include "Database/Class.hpp"
#include "Database/EventCommands/ChangeClass.hpp"
#include "Database/EventCommands/ShowAnimation.hpp"

struct Dialog_ShowAnimation : IEventDialogController {
  Dialog_ShowAnimation() = delete;
  explicit Dialog_ShowAnimation(const std::string& name, const std::shared_ptr<ShowAnimationCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ShowAnimationCommand());
    }
    m_character = m_command->character;
    m_animation = m_command->animation;
    m_waitCompletion = m_command->waitForCompletion;
  }
  void drawPickers();
  std::tuple<bool, bool> draw() override;

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

private:
  bool m_waitCompletion;
  int m_animation;
  int m_character;

  std::optional<ObjectPicker<Animation>> m_animationPicker;
  std::shared_ptr<ShowAnimationCommand> m_command;
};


code:
#include "Core/EventCommands/Dialog_ShowBalloonIcon.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_ShowBalloonIcon::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ShowBalloonIcon");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 36) + (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("{}###ShowBalloonIcon", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    ImGui::BeginVertical("##show_balloon_icon_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      GroupBox characterGroupBox(trNOOP("Character"), "##show_balloon_icon_character_group_box", {-1, 0});
      if (characterGroupBox.begin()) {
        ImGui::SetNextItemWidth(-1);
        if (ImGui::BeginCombo("##show_balloon_icon_character_combo", Database::instance()->eventNameOrId(m_character).c_str())) {
          const auto currentMap = Database::instance()->mapInfos.currentMap()->map();
          for (int i = -1; i < static_cast<int>(currentMap->events().size()); ++i) {
            const auto selected = i == m_character;
            if (i > 0 && !currentMap->event(i)) {
              continue;
            }

            if (ImGui::Selectable(Database::instance()->eventNameOrId(i).c_str(), selected)) {
              m_character = i;
            }
            if (selected) {
              ImGui::SetItemDefaultFocus();
            }
          }
          ImGui::EndCombo();
        }
      }
      characterGroupBox.end();
      GroupBox balloonGroupBox(trNOOP("Balloon Icon"), "##show_balloon_icon_balloon_group_box", {-1, 0});
      if (balloonGroupBox.begin()) {
        ImGui::SetNextItemWidth(-1);
        if (ImGui::BeginCombo("##show_balloon_icon_balloon_combo", DecodeEnumName(magic_enum::enum_cast<BalloonIcon>(m_balloonIndex).value_or(BalloonIcon::Exclamation)).c_str())) {
          for (const auto balloon : magic_enum::enum_values<BalloonIcon>()) {
            const auto selected = static_cast<int>(balloon) == m_balloonIndex;
            if (ImGui::Selectable(DecodeEnumName(balloon).c_str(), selected)) {
              m_balloonIndex = static_cast<int>(balloon);
            }
            if (selected) {
              ImGui::SetItemDefaultFocus();
            }
          }
          ImGui::EndCombo();
        }
      }
      balloonGroupBox.end();

      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##show_balloon_icon_button_layout", {-1, 0}, 0);
      {
        ImGui::Checkbox(trNOOP("Wait for Completion"), &m_waitCompletion);
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##show_balloon_icon_button_layout", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->id = m_character;
          m_command->index = static_cast<BalloonIcon>(m_balloonIndex);
          m_command->waitForCompletion = m_waitCompletion;
          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/ShowBalloonIcon.hpp"

struct Dialog_ShowBalloonIcon : IEventDialogController {
  Dialog_ShowBalloonIcon() = delete;
  explicit Dialog_ShowBalloonIcon(const std::string& name, const std::shared_ptr<ShowBalloonIconCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ShowBalloonIconCommand());
    }
    m_character = m_command->id;
    m_balloonIndex = static_cast<int>(m_command->index);
    m_waitCompletion = m_command->waitForCompletion;
  }
  std::tuple<bool, bool> draw() override;

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

private:
  int m_character;
  int m_balloonIndex;
  bool m_waitCompletion;

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


code:
#include "Core/EventCommands/Dialog_ShowBattleAnimation.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_ShowBattleAnimation::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ShowBattleAnimation");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 36) + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetFrameHeightWithSpacing() * 8) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});
  if (ImGui::BeginPopupModal(std::format("{}###ShowBattleAnimation", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    drawPickers();
    ImGui::BeginVertical("##show_battle_animation_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      GroupBox enemyGroupBox(trNOOP("Enemy"), "##show_battle_animation_enemy_group_box", {-1, 0});
      if (enemyGroupBox.begin()) {
        ImGui::BeginDisabled(m_targetAllEnemies);
        {
          ImGui::SetNextItemWidth(-1);
          if (ImGui::BeginCombo("##show_battle_animation_enemy_combo", m_targetAllEnemies ? "" : std::format("#{} {}", m_enemy + 1, Database::instance()->troopMemberName(m_troop, m_enemy)).c_str())) {
            for (int i = 0; i < 8; ++i) {
              const auto selected = i == m_enemy;
              if (ImGui::Selectable(std::format("#{} {}", i + 1, Database::instance()->troopMemberName(m_troop, m_enemy)).c_str(), selected)) {
                m_enemy = i;
              }
              if (selected) {
                ImGui::SetItemDefaultFocus();
              }
            }
            ImGui::EndCombo();
          }
        }
        ImGui::EndDisabled();
        ImGui::Checkbox(trNOOP("Target all enemies in troop?"), &m_targetAllEnemies);
      }
      enemyGroupBox.end();
      GroupBox animationGroupBox(trNOOP("Animation"), "##show_battle_animation_animation_group_box", {-1, 0});
      if (animationGroupBox.begin()) {
        if (ImGui::EllipsesButton(Database::instance()->animationNameAndId(m_animation).c_str(), {-1, 0})) {
          m_animationPicker.emplace(trNOOP("Animations"), Database::instance()->animations.animations(), m_animation);
          m_animationPicker->setOpen(true);
        }
      }
      animationGroupBox.end();

      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##show_battle_animation_button_layout");
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##show_battle_animation_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->targetAllEnemies = m_targetAllEnemies;
          m_command->enemy = m_enemy;
          m_command->animation = m_animation;
          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_ShowBattleAnimation::drawPickers() {
  if (m_animationPicker) {
    if (const auto [closed, confirmed] = m_animationPicker->draw(); closed) {
      if (confirmed) {
        m_animation = m_animationPicker->selection();
      }
      m_animationPicker.reset();
    }
  }
}


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

struct Dialog_ShowBattleAnimation : IEventDialogController {
  Dialog_ShowBattleAnimation() = delete;
  explicit Dialog_ShowBattleAnimation(const std::string& name, const std::shared_ptr<ShowBattleAnimationCommand>& cmd = nullptr, const int troopId = 0)
  : IEventDialogController(name)
  , m_troop(troopId)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ShowBattleAnimationCommand());
    }
    m_enemy = m_command->enemy;
    m_animation = m_command->animation;
    m_targetAllEnemies = m_command->targetAllEnemies;
  }
  void drawPickers();
  std::tuple<bool, bool> draw() override;

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

private:
  int m_troop{0};
  bool m_targetAllEnemies;
  int m_animation;
  int m_enemy;

  bool m_confirmed{false};
  std::optional<ObjectPicker<Animation>> m_animationPicker;
  std::shared_ptr<ShowBattleAnimationCommand> m_command;
};


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

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

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

std::tuple<bool, bool> Dialog_ShowChoice::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ShowChoice");
  }
  const auto maxSize = ImVec2{ImGui::CalcTextSize("#").x * 64 + (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("{}###ShowChoice", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    ImGui::BeginVertical("##show_choice_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      GroupBox choicesGroup(trNOOP("Choices"), "##show_choice_inner_layout", {-1, 0});
      if (choicesGroup.begin()) {
        for (int i = 0; auto& choice : m_choices) {
          ImGui::BeginHorizontal(std::format("##show_choice_choice_{}", i).c_str(), {-1, 0});
          {
            ImGui::Text("#%i:", i + 1);
            ImGui::SetNextItemWidth(-1);
            ImGui::InputText(std::format("##show_choice_choice_{}", i).c_str(), &choice);
          }
          ImGui::EndHorizontal();
          ++i;
        }
      }
      choicesGroup.end();
      ImGui::BeginHorizontal("##show_choice_configuration_layout", {-1, 0}, 0);
      {
        ImGui::Spring(0.5f);
        GroupBox windowBackgroundGroup(trNOOP("Background"), "##show_choice_window_background", {ImGui::GetContentRegionAvail().x * .25f, 0.f});
        if (windowBackgroundGroup.begin()) {
          ImGui::SetNextItemWidth(-1);
          if (ImGui::BeginCombo("##show_choice_window_position_combo", DecodeEnumName(magic_enum::enum_value<TextBackground>(m_background)).c_str())) {
            for (auto& background : magic_enum::enum_values<TextBackground>()) {
              bool selected = m_background == static_cast<int>(background);
              if (ImGui::Selectable(DecodeEnumName(background).c_str(), selected)) {
                m_background = static_cast<int>(background);
              }
              if (selected)
                ImGui::SetItemDefaultFocus();
            }
            ImGui::EndCombo();
          }
        }
        windowBackgroundGroup.end();
        ImGui::Spring(0.333f);
        GroupBox windowPositionGroup(trNOOP("Window Position"), "##show_choice_window_position", {ImGui::GetContentRegionAvail().x * .333f, 0.f});
        if (windowPositionGroup.begin()) {
          ImGui::SetNextItemWidth(-1);
          if (ImGui::BeginCombo("##show_choice_window_position_combo", DecodeEnumName(magic_enum::enum_value<ChoiceWindowPosition>(m_position)).c_str())) {
            for (auto& position : magic_enum::enum_values<ChoiceWindowPosition>()) {
              bool selected = m_position == static_cast<int>(position);
              if (ImGui::Selectable(DecodeEnumName(position).c_str(), selected)) {
                m_position = static_cast<int>(position);
              }
              if (selected)
                ImGui::SetItemDefaultFocus();
            }
            ImGui::EndCombo();
          }
        }
        windowPositionGroup.end();
        ImGui::Spring(0.333f);
        GroupBox defaultChoiceGroup(trNOOP("Default"), "##show_choice_default_choice", {ImGui::GetContentRegionAvail().x * .5f, 0.f});
        if (defaultChoiceGroup.begin()) {
          ImGui::SetNextItemWidth(-1);
          if (ImGui::BeginCombo("##show_choice_window_default_choice_combo", (m_defaultType < 0 ? trNOOP("None") : trFormat("Choice #{}", m_defaultType + 1)).c_str())) {
            for (int i{-1}; i < 6; i++) {
              bool selected = m_defaultType == i;
              if (i < 0) {
                if (ImGui::Selectable("None", selected)) {
                  m_defaultType = -1;
                }
              } else {
                if (ImGui::Selectable(trFormat("Choice #{}", i + 1).c_str(), selected)) {
                  m_defaultType = i;
                }
              }
              if (selected) {
                ImGui::SetItemDefaultFocus();
              }
            }
            ImGui::EndCombo();
          }
        }
        defaultChoiceGroup.end();

        ImGui::Spring(0.333f);
        GroupBox cancelChoiceGroup(trNOOP("Cancel"), "##show_choice_cancel_choice", {-1, 0.f});
        if (cancelChoiceGroup.begin()) {
          ImGui::SetNextItemWidth(-1);
          if (ImGui::BeginCombo("##show_choice_cancel_choice_combo", (m_cancelType == -2   ? trNOOP("Branch")
                                                                      : m_cancelType == -1 ? trNOOP("Disallow")
                                                                                : trFormat("Choice #{}", m_cancelType + 1))
                                                                         .c_str())) {
            for (int i{-2}; i < 6; i++) {
              bool selected = m_cancelType == i;
              if (i < 0) {
                if (i == -2) {
                  if (ImGui::Selectable(trNOOP("Branch"), selected)) {
                    m_cancelType = -2;
                  }
                } else {
                  if (ImGui::Selectable(trNOOP("Disallow"), selected)) {
                    m_cancelType = -1;
                  }
                }
              } else {
                if (ImGui::Selectable(trFormat("Choice #{}", i + 1).c_str(), selected)) {
                  m_cancelType = i;
                }
              }
              if (selected) {
                ImGui::SetItemDefaultFocus();
              }
            }
            ImGui::EndCombo();
          }
        }
        cancelChoiceGroup.end();

        ImGui::Spring(0.5f);
      }
      ImGui::EndHorizontal();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##show_choice_button_layout", {-1, 0}, 0);
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##show_choice_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->choices.clear();
          for (int i = 0; i < m_choices.size(); ++i) {
            if (m_choices[i].empty()) {
              continue;
            }
            m_command->choices.push_back(m_choices[i]);
          }

          if (m_command->choices.empty()) {
            m_command->choices.push_back("");
          }
          m_command->positionType = static_cast<ChoiceWindowPosition>(m_position);
          m_command->background = static_cast<TextBackground>(m_background);
          m_command->cancelType = m_cancelType;
          m_command->defaultType = m_defaultType;
          setOpen(false);
        } else if (ret == 1) {
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }

  return {!m_open, m_confirmed};
}


code:
#pragma once
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Core/Log.hpp"
#include "Database/EventCommands/EventDummy.hpp"
#include "Database/EventCommands/ShowChoice.hpp"

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

    for (int index{0}; const auto& string : m_command->choices) {
      m_choices[index] = string;
      index++;
    }

    m_background = static_cast<int>(m_command->background);
    m_position = static_cast<int>(m_command->positionType);
    m_cancelType = m_command->cancelType;
    m_defaultType = m_command->defaultType;
  }
  std::tuple<bool, bool> draw() override;

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

  std::vector<std::shared_ptr<IEventCommand>> getTemplateCommands(const EventCode code, const int intParam1 = 0) override {
    std::vector<std::shared_ptr<IEventCommand>> commandList;
    if (code == EventCode::When_Selected) {
      commandList.push_back(std::make_shared<WhenSelectedCommand>());
      commandList.back()->setIndent(getParentIndent().value());
      const auto when = static_pointer_cast<WhenSelectedCommand>(commandList.back());
      when->choice = m_command->choices.at(intParam1);
      when->param1 = intParam1;
      commandList.push_back(std::make_shared<EventDummy>());
      commandList.back()->setIndent(getParentIndent().value() + 1);
    }
    return commandList;
  }

  std::vector<std::shared_ptr<IEventCommand>> getBatchCommands() override {

    const std::shared_ptr<IEventCommand> sharedCommand = getCommand();
    m_eventCommands.push_back(sharedCommand);
    m_eventCommands.back()->setIndent(getParentIndent().value());

    for (int i{0}; i < m_command->choices.size(); i++) {
      // When "Choice"
      m_eventCommands.push_back(std::make_shared<WhenSelectedCommand>());
      m_eventCommands.back()->setIndent(getParentIndent().value());
      const auto when = static_pointer_cast<WhenSelectedCommand>(m_eventCommands.back());
      when->choice = m_command->choices.at(i);
      when->param1 = i;
      m_eventCommands.push_back(std::make_shared<EventDummy>());
      // When "Cancel"
      m_eventCommands.back()->setIndent(getParentIndent().value() + 1);
      if (m_command->cancelType == -2 && i == m_command->choices.size() - 1) {
        m_eventCommands.push_back(std::make_shared<WhenCancelCommand>());
        m_eventCommands.back()->setIndent(getParentIndent().value());
        m_eventCommands.push_back(std::make_shared<EventDummy>());
        m_eventCommands.back()->setIndent(getParentIndent().value() + 1);
      }
      // Show Choices End
      if (i == m_command->choices.size() - 1) {
        m_eventCommands.push_back(std::make_shared<ShowChoicesEndCommand>());
        m_eventCommands.back()->setIndent(getParentIndent().value());
      }
    }
    return m_eventCommands;
  };

private:
  std::array<std::string, 6> m_choices;
  int m_background;
  int m_position;
  int m_defaultType;
  int m_cancelType;

  std::vector<std::shared_ptr<IEventCommand>> m_eventCommands;

  std::shared_ptr<ShowChoiceCommand> m_command;
};