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

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

#include "Database/Database.hpp"

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

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

  if (ImGui::BeginPopupModal(std::format("{}###ConditionalBranch", m_name).c_str(), &m_open)) {
    drawPickers();
    ImGui::BeginVertical("##conditional_branch_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      if (ImGui::BeginTabBar("##conditional_branch_dialog")) {
        ImGui::BeginVertical("##conditional_branch_main_layout_tabs", {-1, ImGui::GetContentRegionAvail().y * .7f}, 0);
        {
          drawDataTab();
          drawActorTab();
          drawEntityTab();
          drawMiscTab();
        }
        ImGui::EndVertical();
        ImGui::EndTabBar();
      }
      drawDialogButtons();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }
  return std::make_tuple(!m_open, m_confirmed);
}

void Dialog_ConditionalBranch::drawDataTab() {
  if (ImGui::BeginTabItem(trNOOP("Data"), nullptr, m_selectedTab == 0 ? ImGuiTabItemFlags_SetSelected : 0)) {
    ImGui::BeginHorizontal("##conditional_branch_data_tab_main_layout", {-1, -1}, 0);
    {
      ImGui::BeginVertical("##conditional_branch_data_tab_left", {-1, 0}, 0);
      {
        ImGui::RadioButton(trNOOP("Switch"), &m_conditionType, 0);
        ImGui::RadioButton(trNOOP("Variable"), &m_conditionType, 1);
        // Constant
        ImGui::Dummy(ImVec2{-1, ImGui::GetFrameHeight()});
        // Fixed
        ImGui::Dummy(ImVec2{-1, ImGui::GetFrameHeight()});
        ImGui::RadioButton(trNOOP("Self Switch"), &m_conditionType, 2);
        ImGui::RadioButton(trNOOP("Timer"), &m_conditionType, 3);
      }
      ImGui::EndVertical();
      ImGui::BeginVertical("##conditional_branch_data_tab_right", {-1, 0}, 0);
      {
        ImGui::BeginHorizontal("##conditional_branch_data_tab_right_switch", {-1, 0}, 0);
        {
          ImGui::BeginDisabled(m_conditionType != 0);
          // Switches
          if (ImGui::EllipsesButton((m_conditionType != 0 ? "##conditional_switch_empty" : Database::instance()->switchNameAndId(m_switchId)).c_str(),
                                    ImVec2{ImGui::GetContentRegionAvail().x * .7f, 0})) {
            m_pickerType = 0;
            m_variablePicker.emplace(trNOOP("Switches"), Database::instance()->system.switches(), m_switchId);
            m_variablePicker->setOpen(true);
          }
          ImGui::TextUnformatted(trNOOP("is"));
          ImGui::PushItemWidth(-1);
          if (ImGui::BeginCombo("##conditional_switch_sub_selection", DecodeEnumName(magic_enum::enum_value<ValueControl>(m_switchValue)).c_str())) {
            for (auto& val : magic_enum::enum_values<ValueControl>()) {
              if (const bool isSelected = m_switchValue == magic_enum::enum_index(val).value(); ImGui::Selectable(DecodeEnumName(val).c_str(), isSelected)) {
                m_switchValue = static_cast<int>(val);
                if (isSelected)
                  ImGui::SetItemDefaultFocus();
              }
            }
            ImGui::EndCombo();
          }
          ImGui::EndDisabled();
        }
        ImGui::EndHorizontal();
        ImGui::BeginVertical("##conditional_branch_data_tab_right_variable", {-1, 0}, 0);
        {
          // Variables
          ImGui::BeginDisabled(m_conditionType != 1);
          {
            ImGui::BeginHorizontal("##conditional_branch_data_tab_right_variable_selection", {-1, 0}, 0);
            {
              if (ImGui::EllipsesButton((m_conditionType != 1 ? "##conditional_variable_id" : Database::instance()->variableNameAndId(m_variableId)).c_str(),
                                        ImVec2{ImGui::GetContentRegionAvail().x * .7f, 0})) {
                m_pickerType = 1;
                m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_variableId);
                m_variablePicker->setOpen(true);
              }

              ImGui::PushItemWidth(-1);
              if (ImGui::BeginCombo("##conditional_variable_sub_selection", DecodeEnumName(magic_enum::enum_value<VariableComparisonType>(m_variableValue)).c_str())) {
                for (auto& val : magic_enum::enum_values<VariableComparisonType>()) {
                  if (const bool isSelected = m_variableValue == static_cast<int>(val); ImGui::Selectable(DecodeEnumName(magic_enum::enum_name(val)).c_str(), isSelected)) {
                    m_variableValue = static_cast<int>(val);
                    if (isSelected) {
                      ImGui::SetItemDefaultFocus();
                    }
                  }
                }
                ImGui::EndCombo();
              }
            }
            ImGui::EndHorizontal();
            ImGui::BeginHorizontal("##conditional_branch_data_tab_right_variable_value", {-1, 0}, 0);
            {
              ImGui::BeginVertical("##conditional_branch_data_tab_right_variable_value_radios", {-1, 0}, 0);
              {
                ImGui::RadioButton(trNOOP("Constant"), &m_variableSubSource, 0);
                ImGui::RadioButton(trNOOP("Fixed"), &m_variableSubSource, 1);
              }
              ImGui::EndVertical();
              ImGui::BeginVertical("##conditional_branch_data_tab_right_variable_value_inputs", {-1, 0}, 0);
              {
                ImGui::BeginDisabled(m_variableSubSource != 0);
                ImGui::SetNextItemWidth(-1);
                if (ImGui::SpinInt("##conditional_var_sub_constant", &m_subConstant)) {
                  m_subConstant = std::clamp(m_subConstant, 0, 9999);
                }
                ImGui::EndDisabled();
                ImGui::BeginDisabled(m_variableSubSource != 1);
                ImGui::PushID("##conditional_var_sub_variable");
                if (ImGui::EllipsesButton(m_variableSubSource != 1 ? "" : Database::instance()->variableNameAndId(m_subVariableId).c_str(), ImVec2{-1, 0})) {
                  m_pickerType = 2;
                  m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_subVariableId);
                  m_variablePicker->setOpen(true);
                }
                ImGui::PopID();
                ImGui::EndDisabled();
              }
              ImGui::EndVertical();
            }
            ImGui::EndHorizontal();
          }
          ImGui::EndDisabled();
        }
        ImGui::EndVertical();
        ImGui::BeginHorizontal("##conditional_branch_data_tab_right_self_switch", {-1, 0}, 0);
        {
          // Self Switches
          ImGui::BeginDisabled(m_conditionType != 2);
          ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * .33f);
          if (ImGui::BeginCombo("##conditional_branch_data_tab_self_switch_list", m_conditionType != 2 ? "" : m_selfSw.c_str())) {
            for (const auto self : {"A", "B", "C", "D"}) {
              if (ImGui::Selectable(self, self == m_selfSw)) {
                m_selfSw = self;
              }
            }
            ImGui::EndCombo();
          }
          const auto label = trNOOP("is");
          ImGui::TextUnformatted(label);
          ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x * .5f - (ImGui::CalcTextSize(label).x - ImGui::GetStyle().FramePadding.x));
          if (ImGui::BeginCombo("##conditional_branch_data_tab_self_switch_sub_selection", DecodeEnumName(magic_enum::enum_value<ValueControl>(m_selfSwValue)).c_str())) {
            for (auto& dir : magic_enum::enum_values<ValueControl>()) {
              if (const bool isSelected = m_selfSwValue == static_cast<int>(dir); ImGui::Selectable(DecodeEnumName(dir).c_str(), isSelected)) {
                m_selfSwValue = static_cast<int>(dir);
                if (isSelected)
                  ImGui::SetItemDefaultFocus();
              }
            }
            ImGui::EndCombo();
          }
          ImGui::EndDisabled();
        }
        ImGui::EndHorizontal();
        ImGui::BeginChild("##conditional_branch_data_tab_right_timer", {-1, 0},
                          ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_NoBackground);
        {
          ImGui::BeginDisabled(m_conditionType != 3);
          {
            ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * .33f);
            if (ImGui::BeginCombo("##conditional_branch_timer_comparison", DecodeEnumName(magic_enum::enum_value<TimerComparisonType>(m_timerOperation)).c_str())) {
              for (auto& dir : magic_enum::enum_values<TimerComparisonType>()) {
                if (bool isSelected = m_selfSwValue == magic_enum::enum_index(dir).value(); ImGui::Selectable(DecodeEnumName(magic_enum::enum_name(dir)).c_str(), isSelected)) {
                  m_timerOperation = magic_enum::enum_index(dir).value();
                  if (isSelected)
                    ImGui::SetItemDefaultFocus();
                }
              }
              ImGui::EndCombo();
            }
            ImGui::SameLine();
            ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * .5f);
            // TL-NOTE: Minutes
            if (ImGui::SpinInt("##conditional_branch_timer_min", &m_timerMin, 1, 5, trNOOP("%d min"))) {
              m_timerMin = std::clamp(m_timerMin, 0, 99);
            }
            ImGui::SameLine();
            ImGui::SetNextItemWidth(-1);
            // TL-NOTE: Seconds
            if (ImGui::SpinInt("##conditional_branch_timer_sec", &m_timerSec, 1, 5, trNOOP("%d sec"))) {
              m_timerSec = std::clamp(m_timerSec, 0, 59);
            }
          }
          ImGui::EndDisabled();
        }
        ImGui::EndChild();
      }
      ImGui::EndVertical();
    }
    ImGui::EndHorizontal();
    ImGui::EndTabItem();
  }

  if (ImGui::IsItemClicked()) {
    m_selectedTab = 0;
  }
}

void Dialog_ConditionalBranch::drawActorTab() {
  if (ImGui::BeginTabItem(trNOOP("Actor"), nullptr, m_selectedTab == 1 ? ImGuiTabItemFlags_SetSelected : 0)) {
    ImGui::BeginHorizontal("##conditional_branch_actor_tab_main_layout", {-1, -1}, 0);
    {
      ImGui::BeginVertical("##conditional_branch_actor_tab_left", {-1, 0}, 0);
      {
        //
        ImGui::RadioButton(trNOOP("Actor"), &m_conditionType, 4);
      }
      ImGui::EndVertical();
      ImGui::BeginVertical("##conditional_branch_actor_tab_right", {-1, 0}, 0);
      {
        ImGui::BeginDisabled(m_conditionType != 4);
        {
          ImGui::PushID("##conditional_actor_condition");
          if (ImGui::EllipsesButton(m_conditionType != 4 ? "" : Database::instance()->actorNameAndId(m_actorSelection).c_str(), {-1, 0})) {

            m_actorPicker = ObjectPicker(trNOOP("Actor"), Database::instance()->actors.actorList(), m_actorSelection);
            m_actorPicker->setOpen(true);
          }
          ImGui::PopID();
          ImGui::BeginHorizontal("##conditional_branch_actor_tab_right_inner", {-1, 0}, 0);
          {
            ImGui::BeginVertical("##conditional_branch_actor_tab_right_inner_left", {-1, 0}, 0);
            {
              ImGui::RadioButton(trNOOP("In the party"), &m_actorSubSelection, 0);
              ImGui::RadioButton(trNOOP("Name"), &m_actorSubSelection, 1);
              ImGui::RadioButton(trNOOP("Class"), &m_actorSubSelection, 2);
              ImGui::RadioButton(trNOOP("Skill"), &m_actorSubSelection, 3);
              ImGui::RadioButton(trNOOP("Weapon"), &m_actorSubSelection, 4);
              ImGui::RadioButton(trNOOP("Armor"), &m_actorSubSelection, 5);
              ImGui::RadioButton(trNOOP("State"), &m_actorSubSelection, 6);
            }
            ImGui::EndVertical();
            ImGui::BeginVertical("##conditional_branch_actor_tab_right_inner_right", {-1, 0}, 0);
            {
              ImGui::Dummy({-1, ImGui::GetFrameHeight()});
              // Name Input
              ImGui::BeginDisabled(m_actorSubSelection != 1);
              ImGui::SetNextItemWidth(-1);
              ImGui::InputText("##conditional_branch_actor_tab_nameinput", &m_actorSelectionNameInput);
              ImGui::EndDisabled();

              // Class Button
              ImGui::BeginDisabled(m_actorSubSelection != 2);
              ImGui::PushID("##change_class_selection");
              if (ImGui::EllipsesButton(m_actorSubSelection != 2 ? "" : Database::instance()->classNameAndId(m_actorClass).c_str(), ImVec2{-1, 0})) {
                m_classPicker = ObjectPicker(trNOOP("Class"), Database::instance()->classes.classes(), m_actorClass);
                m_classPicker->setOpen(true);
              }
              ImGui::PopID();
              ImGui::EndDisabled();

              // Skill Button
              ImGui::BeginDisabled(m_actorSubSelection != 3);
              ImGui::PushID("##change_skill_selection");
              if (ImGui::EllipsesButton(m_actorSubSelection != 3 ? "" : Database::instance()->skillNameAndId(m_actorSkill).c_str(), ImVec2{-1, 0})) {
                m_skillPicker = ObjectPicker(trNOOP("Skill"), Database::instance()->skills.skills(), m_actorSkill);
                m_skillPicker->setOpen(true);
              }
              ImGui::PopID();
              ImGui::EndDisabled();

              // Weapons Button
              ImGui::BeginDisabled(m_actorSubSelection != 4);
              ImGui::PushID("##change_weapons_selection");
              if (ImGui::EllipsesButton(m_actorSubSelection != 4 ? "" : Database::instance()->weaponNameOrId(m_actorWeapon).c_str(), {-1, 0})) {
                m_weaponType = 0;
                m_weaponPicker = ObjectPicker(trNOOP("Weapon"), Database::instance()->weapons.weaponList(), m_actorWeapon);
                m_weaponPicker->setOpen(true);
              }
              ImGui::PopID();
              ImGui::EndDisabled();

              // Armors Button
              ImGui::BeginDisabled(m_actorSubSelection != 5);
              ImGui::PushID("##change_armors_selection");
              if (ImGui::EllipsesButton(m_actorSubSelection != 5 ? "" : Database::instance()->armorNameAndId(m_actorArmor).c_str(), {-1, 0})) {
                m_armorType = 0;
                m_armorPicker = ObjectPicker(trNOOP("Armor"), Database::instance()->armors.armorList(), m_actorArmor);
                m_actorPicker->setOpen(true);
              }
              ImGui::PopID();
              ImGui::EndDisabled();

              // State Button
              ImGui::BeginDisabled(m_actorSubSelection != 6);
              ImGui::PushID("##change_state_selection");
              if (ImGui::EllipsesButton(m_actorSubSelection != 6 ? "" : Database::instance()->stateNameAndId(m_actorState).c_str(), {-1, 0})) {
                m_stateType = 0;
                m_statePicker = ObjectPicker(trNOOP("States"), Database::instance()->states.states(), m_actorState);
                m_statePicker->setOpen(true);
              }
              ImGui::PopID();
              ImGui::EndDisabled();
            }
            ImGui::EndVertical();
          }
          ImGui::EndHorizontal();
        }
        ImGui::EndDisabled();
      }
      ImGui::EndVertical();
    }
    ImGui::EndHorizontal();
    ImGui::EndTabItem();
  }
  if (ImGui::IsItemClicked()) {
    m_selectedTab = 1;
  }
}

void Dialog_ConditionalBranch::drawEntityTab() {
  if (ImGui::BeginTabItem(trNOOP("Entity"), nullptr, m_selectedTab == 2 ? ImGuiTabItemFlags_SetSelected : 0)) {
    ImGui::BeginHorizontal("##conditional_branch_entity_tab_main_layout", {-1, -1}, 0);
    {
      ImGui::BeginVertical("##conditional_branch_entity_tab_main_left_layout", {-1, 0}, 0);
      {
        ImGui::RadioButton(trNOOP("Enemy"), &m_conditionType, 5);
        ImGui::Dummy({-1, ImGui::GetFrameHeight()});
        ImGui::Dummy({-1, ImGui::GetFrameHeight()});
        ImGui::RadioButton(trNOOP("Character"), &m_conditionType, 6);
        ImGui::RadioButton(trNOOP("Vehicle"), &m_conditionType, 13);
      }
      ImGui::EndVertical();
      ImGui::BeginVertical("##conditional_branch_entity_tab_main_right_layout", {-1, 0}, 0);
      {
        ImGui::BeginVertical("##conditional_branch_entity_tab_main_right_enemy_layout", {-1, 0}, 0);
        {
          ImGui::BeginDisabled(m_conditionType != 5);
          {
            ImGui::SetNextItemWidth(-1);
            if (ImGui::BeginCombo("##conditional_branch_entity_tab_main_right_enemy_enemy_list",
                                  (m_conditionType != 5 ? "" : "#" + std::to_string(m_enemySelection + 1) + " " + Database::instance()->troopMemberName(m_troopId, m_enemySelection)).c_str())) {
              for (int i = 0; i < 9; ++i) {
                if (ImGui::Selectable(std::format("#{} {}", i + 1, Database::instance()->troopMemberName(m_troopId, i)).c_str(), i == m_enemySelection)) {
                  m_enemySelection = i;
                }
              }
              ImGui::EndCombo();
            }
            ImGui::BeginHorizontal("##conditional_branch_entity_tab_main_right_enemy_layout_inner", {-1, 0}, 0);
            {
              ImGui::BeginVertical("##conditional_branch_entity_tab_main_right_enemy_radios", {-1, 0}, 0);
              {
                ImGui::RadioButton("Appeared", &m_enemySubSelection, 0);
                ImGui::RadioButton("State", &m_enemySubSelection, 1);
              }
              ImGui::EndVertical();
              ImGui::BeginVertical("##conditional_branch_entity_tab_main_right_enemy_values", {-1, 0}, 0);
              {
                ImGui::Dummy({-1, ImGui::GetFrameHeight()});
                ImGui::BeginDisabled(m_enemySubSelection != 1);
                ImGui::PushID("##change_state_selection");
                if (ImGui::EllipsesButton(m_enemySubSelection != 1 ? "" : Database::instance()->stateNameAndId(m_actorState).c_str(), {-1, 0})) {
                  m_stateType = 1;
                  m_statePicker = ObjectPicker(trNOOP("States"), Database::instance()->states.states(), m_actorState);
                  m_statePicker->setOpen(true);
                }
                ImGui::PopID();
                ImGui::EndDisabled();
              }
              ImGui::EndVertical();
            }
            ImGui::EndHorizontal();
          }
          ImGui::EndDisabled();
        }
        ImGui::EndVertical();
        ImGui::BeginHorizontal("##conditional_branch_entity_tab_main_right_character_layout", {-1, 0}, 0);
        {
          ImGui::BeginDisabled(m_conditionType != 6 || !Database::instance()->mapInfos.currentMap() || !Database::instance()->mapInfos.currentMap()->map());
          {
            const auto label = trNOOP("is facing");
            ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * .5f);
            if (ImGui::BeginCombo("##conditional_branch_entity_tab_main_right_character_list", m_conditionType != 6 ? "" : Database::instance()->eventNameOrId(m_characterSelection).c_str())) {
              const auto map = Database::instance()->mapInfos.currentMap()->map();
              for (int i = -1; i < static_cast<int>(map->events().size()); ++i) {
                if (i > 0 && !map->event(i)) {
                  continue;
                }
                const bool selected = m_characterSelection == i;
                if (ImGui::Selectable(Database::instance()->eventNameOrId(i).c_str(), selected)) {
                  m_characterSelection = i;
                }
                if (selected) {
                  ImGui::SetItemDefaultFocus();
                }
              }
              ImGui::EndCombo();
            }
            ImGui::TextUnformatted(label);
            ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - (ImGui::CalcTextSize(label).x + ImGui::GetStyle().FramePadding.x));
            if (ImGui::BeginCombo("##conditional_branch_entity_tab_main_right_direction_selection",
                                  m_conditionType != 6 ? "" : DecodeEnumName(magic_enum::enum_value<Direction>(m_characterDirection)).c_str())) {
              for (auto& dir : magic_enum::enum_values<Direction>()) {
                if (dir == Direction::Retain) {
                  continue;
                }

                if (bool is_selected = m_characterDirection == static_cast<int>(dir); ImGui::Selectable(DecodeEnumName(dir).c_str(), is_selected)) {
                  m_characterDirection = magic_enum::enum_index(dir).value();
                  if (is_selected)
                    ImGui::SetItemDefaultFocus();
                }
              }
              ImGui::EndCombo();
            }
          }
          ImGui::EndDisabled();
        }
        ImGui::EndHorizontal();
        ImGui::BeginHorizontal("##conditional_branch_entity_tab_main_right_vehicle_layout", {-1, 0}, 0);
        {
          ImGui::BeginDisabled(m_conditionType != 13);
          {
            const auto label = trNOOP("is driven");
            ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * .5f);
            if (ImGui::BeginCombo("##conditional_branch_entity_tab_main_right_vehicle_location_selection",
                                  m_conditionType != 13 ? "" : DecodeEnumName(magic_enum::enum_value<VehicleType>(m_vehicleSelection)).c_str())) {
              for (auto& vehicle : magic_enum::enum_values<VehicleType>()) {
                const bool isSelected = m_vehicleSelection == magic_enum::enum_index(vehicle).value();
                if (ImGui::Selectable(DecodeEnumName(magic_enum::enum_name(vehicle)).c_str(), isSelected)) {
                  m_vehicleSelection = magic_enum::enum_index(vehicle).value();
                }
                if (isSelected) {
                  ImGui::SetItemDefaultFocus();
                }
              }
              ImGui::EndCombo();
            }
            ImGui::TextUnformatted(label);
          }
          ImGui::EndDisabled();
        }
        ImGui::EndHorizontal();
      }
      ImGui::EndVertical();
    }
    ImGui::EndHorizontal();
    ImGui::EndTabItem();
  }
  if (ImGui::IsItemClicked()) {
    m_selectedTab = 2;
  }
}

void Dialog_ConditionalBranch::drawMiscTab() {
  if (ImGui::BeginTabItem(trNOOP("Misc"), nullptr, m_selectedTab == 3 ? ImGuiTabItemFlags_SetSelected : 0)) {
    ImGui::BeginVertical("##conditional_branch_misc_tab_main_layout", {-1, -1}, 0);
    {
      ImGui::BeginHorizontal("##conditional_branch_misc_tab_main_layout_inner", {-1, -1}, 0);
      {
        ImGui::BeginVertical("##conditional_branch_misc_tab_main_left_layout", {-1, 0}, 0);
        {
          ImGui::RadioButton(trNOOP("Gold"), &m_conditionType, 7);
          ImGui::RadioButton(trNOOP("Item"), &m_conditionType, 8);
          ImGui::RadioButton(trNOOP("Weapon"), &m_conditionType, 9);
          ImGui::Dummy(ImVec2{0, ImGui::GetFrameHeight()});
          ImGui::RadioButton(trNOOP("Armor"), &m_conditionType, 10);
          ImGui::Dummy(ImVec2{0, ImGui::GetFrameHeight()});
          ImGui::RadioButton(trNOOP("Button"), &m_conditionType, 11);
          ImGui::RadioButton(trNOOP("Script:"), &m_conditionType, 12);
        }
        ImGui::EndVertical();
        ImGui::BeginVertical("##conditional_branch_misc_tab_main_right_layout", {-1, 0}, 0);
        {
          ImGui::BeginHorizontal("##conditional_branch_misc_tab_main_left_gold", {-1, 0}, 0);
          {
            ImGui::BeginDisabled(m_conditionType != 7);
            {
              ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * .33f);
              if (ImGui::BeginCombo("##conditional_gold_operation", m_conditionType != 7 ? "" : DecodeEnumName(magic_enum::enum_value<GoldComparisonType>(m_goldOperation)).c_str())) {
                for (auto& operation : magic_enum::enum_values<GoldComparisonType>()) {
                  bool isSelected = m_goldOperation == magic_enum::enum_index(operation).value();
                  if (ImGui::Selectable(DecodeEnumName(magic_enum::enum_name(operation)).c_str(), isSelected)) {
                    m_goldOperation = magic_enum::enum_index(operation).value();
                  }
                  if (isSelected) {
                    ImGui::SetItemDefaultFocus();
                  }
                }
                ImGui::EndCombo();
              }
              ImGui::BeginChild("##conditional_gold_value", {-1, 0}, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_NavFlattened,
                                ImGuiWindowFlags_NoBackground);
              {
                ImGui::SetNextItemWidth(-1);
                if (ImGui::SpinInt("##conditional_gold_selection", &m_goldSelection, 1, 100, std::format("%d {}", Database::instance()->instance()->system.currencyUnit()).c_str())) {
                  m_goldSelection = std::clamp(m_goldSelection, 0, 9999999);
                }
              }
              ImGui::EndChild();
            }
            ImGui::EndDisabled();
          }
          ImGui::EndHorizontal();
          ImGui::BeginVertical("##conditional_branch_misc_tab_main_left_item", {-1, 0}, 0);
          {
            ImGui::BeginDisabled(m_conditionType != 8);
            {
              ImGui::PushID("##conditional_item_selection");
              if (ImGui::EllipsesButton(m_conditionType != 8 ? "" : Database::instance()->itemNameOrId(m_itemSelection).c_str(), {-1, 0})) {
                m_itemPicker = ObjectPicker<Item>("Items"sv, Database::instance()->items.items(), m_itemSelection);
                m_itemPicker->setOpen(true);
              }
              ImGui::PopID();
            }
            ImGui::EndDisabled();
          }
          ImGui::EndVertical();
          ImGui::BeginVertical("##conditional_branch_misc_tab_main_left_weapon", {-1, 0}, 0);
          {
            // Weapon
            ImGui::BeginDisabled(m_conditionType != 9);
            {
              ImGui::PushID("##conditional_weapon_selection");
              if (ImGui::EllipsesButton(m_conditionType != 9 ? "" : Database::instance()->weaponNameOrId(m_weaponSelection).c_str(), {-1, 0})) {
                m_weaponType = 1;
                m_weaponPicker = ObjectPicker(trNOOP("Weapons"), Database::instance()->weapons.weapons(), m_weaponSelection);
                m_weaponPicker->setOpen(true);
              }
              ImGui::PopID();
              ImGui::Checkbox(std::format("{}##conditional_branch_misc_tab_weapon_checkbox", trNOOP("Include Equipment")).c_str(), &m_weaponInclude);
            }
            ImGui::EndDisabled();
          }
          ImGui::EndVertical();
          ImGui::BeginVertical("##conditional_branch_misc_tab_main_left_armor", {-1, 0}, 0);
          {
            // Armor
            ImGui::BeginDisabled(m_conditionType != 10);
            {
              ImGui::PushID("##conditional_armor_selection");
              if (ImGui::EllipsesButton(m_conditionType != 10 ? "" : Database::instance()->armorNameOrId(m_armorSelection).c_str(), {-1, 0})) {
                m_armorType = 1;
                m_armorPicker = ObjectPicker(trNOOP("Armors"), Database::instance()->armors.armors(), m_armorSelection);
                m_armorPicker->setOpen(true);
              }
              ImGui::PopID();
              ImGui::Checkbox(std::format("{}##conditional_branch_misc_tab_armor_checkbox", trNOOP("Include Equipment")).c_str(), &m_armorInclude);
            }
            ImGui::EndDisabled();
          }
          ImGui::EndVertical();
          ImGui::BeginHorizontal("##conditional_branch_misc_tab_main_left_button", {-1, 0}, 0);
          {
            // Button
            ImGui::BeginDisabled(m_conditionType != 11);
            {
              ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * .33f);
              if (ImGui::BeginCombo("##conditional_branch_misc_tab_main_left_button_selection",
                                    m_conditionType != 11 ? "" : DecodeEnumName(magic_enum::enum_value<Button>(m_buttonSelection)).c_str())) {
                for (auto& button : magic_enum::enum_values<Button>()) {
                  const bool isSelected = m_buttonSelection == static_cast<int>(button);
                  if (ImGui::Selectable(DecodeEnumName(button).c_str(), isSelected)) {
                    m_buttonSelection = static_cast<int>(button);
                  }
                  if (isSelected)
                    ImGui::SetItemDefaultFocus();
                }
                ImGui::EndCombo();
              }
              ImGui::TextUnformatted(trNOOP("is pressed down"));
            }
            ImGui::EndDisabled();
          }
          ImGui::EndHorizontal();
        }
        ImGui::EndVertical();
      }
      ImGui::EndHorizontal();
      ImGui::BeginDisabled(m_conditionType != 12);
      {
        if (ImGui::BeginChild("##source_text_child", {-1, ImGui::GetContentRegionAvail().y - ImGui::GetFrameHeightWithSpacing()},
                              ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NoMove)) {
          m_script.SetImGuiChildIgnored(true);
          m_script.SetHandleKeyboardInputs(m_conditionType == 12);
          m_script.SetHandleMouseInputs(m_conditionType == 12);
          m_script.Render("##source_text", {-1, -1});
        }
        ImGui::EndChild();
      }
      ImGui::EndDisabled();
    }
    ImGui::EndVertical();
    ImGui::EndTabItem();
  }
  if (ImGui::IsItemClicked()) {
    m_selectedTab = 3;
  }
}

void Dialog_ConditionalBranch::drawPickers() {
  if (m_variablePicker) {
    if (const auto [closed, confirmed] = m_variablePicker->draw(); closed) {
      if (confirmed) {
        if (m_pickerType == 0) {
          m_switchId = m_variablePicker->selection();
        } else if (m_pickerType == 2) {
          m_subVariableId = m_variablePicker->selection();
        } else {
          m_variableId = m_variablePicker->selection();
        }
      }
      m_variablePicker.reset();
    }
  }

  if (m_actorPicker) {
    if (const auto [closed, confirmed] = m_actorPicker->draw(); closed) {
      if (confirmed) {
        m_actorSelection = m_actorPicker->selection();
      }
      m_actorPicker.reset();
    }
  }
  if (m_classPicker) {
    if (const auto [closed, confirmed] = m_classPicker->draw(); closed) {
      if (confirmed) {
        m_actorClass = m_classPicker->selection();
      }
      m_classPicker.reset();
    }
  }
  if (m_skillPicker) {
    if (const auto [closed, confirmed] = m_skillPicker->draw(); closed) {
      if (confirmed) {
        m_actorSkill = m_skillPicker->selection();
      }
      m_skillPicker.reset();
    }
  }
  if (m_weaponPicker) {
    if (const auto [closed, confirmed] = m_weaponPicker->draw(); closed) {
      if (confirmed) {
        if (m_weaponType == 0) {
          m_actorWeapon = m_weaponPicker->selection();
        } else {
          m_weaponSelection = m_weaponPicker->selection();
        }
      }
      m_weaponPicker.reset();
    }
  }
  if (m_armorPicker) {
    if (const auto [closed, confirmed] = m_armorPicker->draw(); closed) {
      if (confirmed) {
        if (m_armorType == 0) {
          m_actorArmor = m_armorPicker->selection();
        } else {
          m_armorSelection = m_armorPicker->selection();
        }
      }
      m_armorPicker.reset();
    }
  }
  if (m_statePicker) {
    if (const auto [closed, confirmed] = m_statePicker->draw(); closed) {
      if (confirmed) {
        if (m_stateType == 0) {
          m_actorState = m_statePicker->selection();
        } else {
          m_enemySubState = m_statePicker->selection();
        }
      }
      m_statePicker.reset();
    }
  }

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

void Dialog_ConditionalBranch::drawDialogButtons() {
  ImGui::Spring();
  ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
  ImGui::BeginHorizontal("##conditional_branch_dialog_buttons_layout");
  {
    ImGui::Checkbox(trNOOP("Create Else Branch"), &m_elseBranch);
    ImGui::Spring();
    if (const auto ret = ImGui::ButtonGroup("##conditional_branch_dialog_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
      m_confirmed = true;
      m_command->type = static_cast<ConditionType>(m_conditionType);
      if (m_command->type == ConditionType::Switch) {
        m_command->globalSwitch.switchIdx = m_switchId;
        m_command->globalSwitch.checkIfOn = static_cast<ValueControl>(m_switchValue);
      } else if (m_command->type == ConditionType::Variable) {
        m_command->variable.id = m_variableId;
        m_command->variable.source = static_cast<VariableComparisonSource>(m_variableSubSource);
        m_command->variable.comparison = static_cast<VariableComparisonType>(m_variableValue);
        if (m_command->variable.source == VariableComparisonSource::Constant) {
          m_command->variable.constant = m_subConstant;
        } else {
          m_command->variable.otherId = m_subVariableId;
        }
      } else if (m_command->type == ConditionType::Self_Switch) {
        m_command->selfSw = m_selfSw;
        m_command->selfSwitch.checkIfOn = static_cast<ValueControl>(m_selfSwValue);
      } else if (m_command->type == ConditionType::Timer) {
        m_command->timer.sec = m_timerSec + (m_timerMin * 60);
        m_command->timer.comparison = static_cast<TimerComparisonType>(m_timerOperation);
      } else if (m_command->type == ConditionType::Actor) {
        m_command->actor.id = m_actorSelection;
        m_command->actor.type = static_cast<ActorConditionType>(m_actorSubSelection);
        if (m_command->actor.type == ActorConditionType::In_The_Party) {
          m_command->actor.checkId = 0;
        }
        if (m_command->actor.type == ActorConditionType::Name) {
          m_command->name = m_actorSelectionNameInput;
        }
        if (m_command->actor.type == ActorConditionType::Class) {
          m_command->actor.checkId = m_actorClass;
        }
        if (m_command->actor.type == ActorConditionType::Skill) {
          m_command->actor.checkId = m_actorSkill;
        }
        if (m_command->actor.type == ActorConditionType::Weapon) {
          m_command->actor.checkId = m_actorWeapon;
        }
        if (m_command->actor.type == ActorConditionType::Armor) {
          m_command->actor.checkId = m_actorArmor;
        }
        if (m_command->actor.type == ActorConditionType::State) {
          m_command->actor.checkId = m_actorState;
        }
      } else if (m_command->type == ConditionType::Enemy) {
        m_command->enemy.id = m_enemySelection;
        m_command->enemy.type = static_cast<EnemyConditionType>(m_enemySubSelection);
        if (m_command->enemy.type == EnemyConditionType::State) {
          m_command->enemy.stateId = m_enemySubState;
        } else {
          m_command->enemy.stateId = 0;
        }
      } else if (m_command->type == ConditionType::Character) {
        m_command->character.id = m_characterSelection;
        m_command->character.facing = static_cast<Direction>((m_characterDirection * 2));
      } else if (m_command->type == ConditionType::Vehicle) {
        m_command->vehicle.id = static_cast<VehicleType>(m_vehicleSelection);
      } else if (m_command->type == ConditionType::Gold) {
        m_command->gold.type = static_cast<GoldComparisonType>(m_goldOperation);
        m_command->gold.value = m_goldSelection;
      } else if (m_command->type == ConditionType::Item) {
        m_command->item.id = m_itemSelection;
      } else if (m_command->type == ConditionType::Weapon) {
        m_command->equip.equipId = m_weaponSelection;
        m_command->equip.includeEquipment = m_weaponInclude;
      } else if (m_command->type == ConditionType::Armor) {
        m_command->equip.equipId = m_armorSelection;
        m_command->equip.includeEquipment = m_armorInclude;
      } else if (m_command->type == ConditionType::Button) {
        m_command->button = static_cast<Button>(m_buttonSelection);
      } else if (m_command->type == ConditionType::Script) {
        m_command->script = m_script.GetText();
      }
      ImGui::CloseCurrentPopup();
      setOpen(false);
    } else if (ret == 1) {
      ImGui::CloseCurrentPopup();
      setOpen(false);
    }
  }
  ImGui::EndHorizontal();
}


code:
#pragma once
#include "Core/CommonUI/ObjectPicker.hpp"
#include "Core/CommonUI/TextEditor.hpp"
#include "Core/CommonUI/VariableSwitchPicker.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Database/Actors.hpp"
#include "Database/Armors.hpp"
#include "Database/Classes.hpp"
#include "Database/EventCommands/ConditionalBranch.hpp"
#include "Database/EventCommands/End.hpp"
#include "Database/EventCommands/EventDummy.hpp"
#include "Database/Items.hpp"
#include "Database/Skills.hpp"
#include "Database/States.hpp"
#include "Database/Weapons.hpp"

struct Dialog_ConditionalBranch : IEventDialogController {
  Dialog_ConditionalBranch() = delete;
  explicit Dialog_ConditionalBranch(const std::string& name, const std::shared_ptr<ConditionalBranchCommand>& cmd = nullptr, const int troopId = 0)
  : IEventDialogController(name)
  , m_troopId(troopId)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ConditionalBranchCommand());
    }

    if (m_command->type == ConditionType::Switch) {
      m_switchId = m_command->globalSwitch.switchIdx;
      m_switchValue = static_cast<int>(m_command->globalSwitch.checkIfOn);
    } else if (m_command->type == ConditionType::Variable) {
      m_variableId = m_command->variable.id;
      m_variableSubSource = static_cast<int>(m_command->variable.source);
      m_variableValue = static_cast<int>(m_command->variable.comparison);
      if (m_command->variable.source == VariableComparisonSource::Constant) {
        m_subConstant = m_command->variable.constant;
      } else {
        m_subVariableId = m_command->variable.otherId;
      }
    } else if (m_command->type == ConditionType::Self_Switch) {
      m_selfSw = m_command->selfSw;
      m_selfSwValue = static_cast<int>(m_command->selfSwitch.checkIfOn);
    } else if (m_command->type == ConditionType::Timer) {
      m_timerMin = m_command->timer.sec / 60;
      m_timerSec = m_command->timer.sec % 60;
      m_timerOperation = static_cast<int>(m_command->timer.comparison);
    } else if (m_command->type == ConditionType::Actor) {
      m_actorSelection = m_command->actor.id;
      m_actorSubSelection = static_cast<int>(m_command->actor.type);
      if (m_command->actor.type == ActorConditionType::In_The_Party) {
        //
      }
      if (m_command->actor.type == ActorConditionType::Name) {
        m_actorSelectionNameInput = m_command->name;
      }
      if (m_command->actor.type == ActorConditionType::Class) {
        m_actorClass = m_command->actor.checkId;
      }
      if (m_command->actor.type == ActorConditionType::Skill) {
        m_actorSkill = m_command->actor.checkId;
      }
      if (m_command->actor.type == ActorConditionType::Weapon) {
        m_actorWeapon = m_command->actor.checkId;
      }
      if (m_command->actor.type == ActorConditionType::Armor) {
        m_actorArmor = m_command->actor.checkId;
      }
      if (m_command->actor.type == ActorConditionType::State) {
        m_actorState = m_command->actor.checkId;
      }
    } else if (m_command->type == ConditionType::Enemy) {
      m_enemySelection = m_command->enemy.id;
      m_enemySubSelection = static_cast<int>(m_command->enemy.type);
      if (m_command->enemy.type == EnemyConditionType::State) {
        m_enemySubState = m_command->enemy.stateId;
      } else {
        m_enemySubState = 0;
      }
    } else if (m_command->type == ConditionType::Character) {
      m_characterSelection = m_command->character.id;
      m_characterDirection = static_cast<int>(m_command->character.facing);
    } else if (m_command->type == ConditionType::Vehicle) {
      m_vehicleSelection = static_cast<int>(m_command->vehicle.id);
    } else if (m_command->type == ConditionType::Gold) {
      m_goldOperation = static_cast<int>(m_command->gold.type);
      m_goldSelection = m_command->gold.value;
    } else if (m_command->type == ConditionType::Item) {
      m_itemSelection = m_command->equip.equipId;
    } else if (m_command->type == ConditionType::Weapon) {
      m_weaponSelection = m_command->equip.equipId;
      m_weaponInclude = m_command->equip.includeEquipment;
    } else if (m_command->type == ConditionType::Armor) {
      m_armorSelection = m_command->equip.equipId;
      m_armorInclude = m_command->equip.includeEquipment;
    } else if (m_command->type == ConditionType::Button) {
      m_buttonSelection = static_cast<int>(m_command->button);
    } else if (m_command->type == ConditionType::Script) {
      m_script.SetTextLines(splitString(m_command->script, '\n'));
    }
    m_conditionType = static_cast<int>(m_command->type);

    if (m_conditionType == 4) {
      m_selectedTab = 1;
    }
    if (m_conditionType == 5 || m_conditionType == 6 || m_conditionType == 13) {
      m_selectedTab = 2;
    }
    if (m_conditionType < 13 && m_conditionType > 6) {
      m_selectedTab = 3;
    }

    // if (command->isPartner(EventCode::Else, command->indent())) {
    //   m_else = true;
    //   m_elseBranch = true;
    // }

    m_script.SetLanguageDefinition(TextEditor::LanguageDefinition::Javascript());
  }
  void drawPickers();
  void drawMiscTab();
  void drawEntityTab();
  void drawActorTab();
  void drawDataTab();
  void drawDialogButtons();
  std::tuple<bool, bool> draw() override;

  std::shared_ptr<IEventCommand> getCommand() override { return m_command; };
  std::vector<std::shared_ptr<IEventCommand>> getBatchCommands(std::vector<std::shared_ptr<IEventCommand>>& list) override {
    std::vector<std::shared_ptr<IEventCommand>> eventCommands;
    std::shared_ptr<IEventCommand> sharedCommand = getCommand();
    eventCommands.push_back(sharedCommand);

    eventCommands.back()->setIndent(getParentIndent().value());
    eventCommands.insert(eventCommands.end(), list.begin(), list.end());
    if (m_elseBranch) {
      eventCommands.push_back(std::make_shared<ElseCommand>());
      eventCommands.back()->setIndent(getParentIndent().value());
      eventCommands.push_back(std::make_shared<EventDummy>());
      eventCommands.back()->setIndent(getParentIndent().value() + 1);
    }
    eventCommands.push_back(std::make_shared<EndCommand>());
    eventCommands.back()->setIndent(getParentIndent().value());
    return eventCommands;
  };
  std::vector<std::shared_ptr<IEventCommand>> getBatchCommands() override {
    std::vector<std::shared_ptr<IEventCommand>> eventCommands;
    const std::shared_ptr<IEventCommand> sharedCommand = getCommand();
    eventCommands.push_back(sharedCommand);

    eventCommands.back()->setIndent(getParentIndent().value());
    eventCommands.push_back(std::make_shared<EventDummy>());
    eventCommands.back()->setIndent(getParentIndent().value() + 1);
    if (m_elseBranch) {
      eventCommands.push_back(std::make_shared<ElseCommand>());
      eventCommands.back()->setIndent(getParentIndent().value());
      eventCommands.push_back(std::make_shared<EventDummy>());
      eventCommands.back()->setIndent(getParentIndent().value() + 1);
    }
    eventCommands.push_back(std::make_shared<EndCommand>());
    eventCommands.back()->setIndent(getParentIndent().value());
    return eventCommands;
  };

private:
  int m_troopId = 0;
  int m_selectedTab{0};
  int m_conditionType{0};
  int m_switchId{1};
  int m_switchValue{0};
  int m_pickerType;
  int m_variableId{1};
  int m_variableValue{0};
  int m_variableSubSource{0};
  int m_subConstant{0};
  int m_subVariableId{1};
  std::string m_selfSw{"A"};
  int m_selfSwValue{0};
  int m_timerMin{0};
  int m_timerSec{0};
  int m_timerOperation{0};
  int m_actorSelection{0};
  int m_actorSubSelection{0};
  std::string m_actorSelectionNameInput;
  int m_actorClass{1};
  int m_actorSkill{1};
  int m_actorArmor{1};
  int m_actorWeapon{1};
  int m_actorState{1};
  int m_enemySelection{0};
  int m_enemySubSelection{0};
  int m_enemySubState{1};
  int m_stateType{0};
  int m_characterSelection{-1};
  int m_characterDirection{1};
  int m_vehicleSelection{0};
  int m_goldOperation{0};
  int m_goldSelection{0};
  int m_itemSelection{1};
  int m_weaponSelection{1};
  int m_weaponType{0};
  bool m_weaponInclude{false};
  int m_armorSelection{1};
  int m_armorType{0};
  bool m_armorInclude{false};
  int m_buttonSelection{0};
  TextEditor m_script;
  bool m_elseBranch{false}; // determines future else (the option)
  bool m_else{false};       // determines current else
  std::shared_ptr<ConditionalBranchCommand> m_command;
  std::optional<VariableSwitchPicker> m_variablePicker;
  std::optional<ObjectPicker<Actor>> m_actorPicker;
  std::optional<ObjectPicker<State>> m_statePicker;
  std::optional<ObjectPicker<Weapon>> m_weaponPicker;
  std::optional<ObjectPicker<Armor>> m_armorPicker;
  std::optional<ObjectPicker<Skill>> m_skillPicker;
  std::optional<ObjectPicker<Class>> m_classPicker;
  std::optional<ObjectPicker<Item>> m_itemPicker;
  bool m_confirmed{false};
};

repo_name: Antidote/openrpgeditor

license: mit


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

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

#include "Database/Database.hpp"

#include "Core/CommonUI/GroupBox.hpp"
#include "imgui.h"

#include <imgui_internal.h>

std::tuple<bool, bool> Dialog_ControlSelfSwitch::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ControlSelfSwitch");
  }
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 20) + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetTextLineHeightWithSpacing() * 10) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});
  if (ImGui::BeginPopupModal(std::format("{}###ControlSelfSwitch", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    ImGui::BeginVertical("##control_self_switch_main_layout", ImGui::GetContentRegionAvail(), 0.f);
    {
      GroupBox selfSwitchGroup(trNOOP("Self Switch"), "##control_self_switch_self_switch_group", {-1, 0});
      if (selfSwitchGroup.begin()) {
        ImGui::SetNextItemWidth(-1);
        if (ImGui::BeginCombo("###control_self_switch_self_switch_list", m_selfSw.c_str())) {
          for (const auto self : {"A", "B", "C", "D"}) {
            const bool selected = self == m_selfSw;
            if (ImGui::Selectable(self, self == m_selfSw)) {
              m_selfSw = self;
            }
            if (selected) {
              ImGui::SetItemDefaultFocus();
            }
          }
          ImGui::EndCombo();
        }
      }
      selfSwitchGroup.end();

      GroupBox operationGroup(trNOOP("Operation"), "##control_self_switch_self_operation_group", {-1, 0});
      if (operationGroup.begin()) {
        ImGui::BeginHorizontal("##control_self_switch_self_operation_group_layout", ImGui::GetContentRegionAvail(), 0.f);
        {
          ImGui::Spring(0.5f);
          ImGui::RadioButton(trNOOP("ON"), &m_turnOff, 0);
          ImGui::Spring(0.33f);
          ImGui::RadioButton(trNOOP("OFF"), &m_turnOff, 1);
          ImGui::Spring(0.5f);
        }
        ImGui::EndHorizontal();
      }
      operationGroup.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##control_self_switch_button_layout", {-1, -1}, 0.f);
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##control_self_switch_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->selfSw = m_selfSw;
          m_command->turnOff = static_cast<ValueControl>(m_turnOff);
          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/ControlSelfSwitch.hpp"
#include "Database/States.hpp"

struct Dialog_ControlSelfSwitch : IEventDialogController {
  Dialog_ControlSelfSwitch() = delete;
  explicit Dialog_ControlSelfSwitch(const std::string& name, const std::shared_ptr<ControlSelfSwitchCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ControlSelfSwitchCommand());
    }
    m_command.reset(new ControlSelfSwitchCommand());
    m_selfSw = m_command->selfSw;
    m_turnOff = static_cast<int>(m_command->turnOff);
  }
  std::tuple<bool, bool> draw() override;

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

private:
  std::string m_selfSw; // A, B, C, D
  int m_turnOff;

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


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

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

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

  if (ImGui::BeginPopupModal(std::format("{}###ControlSwitches", m_name).c_str(), &m_open, ImGuiWindowFlags_NoResize)) {
    drawPickers();
    ImGui::BeginVertical("##control_switches_main_layout", ImGui::GetContentRegionAvail());
    {
      GroupBox switchGroup(trNOOP("Switch"), "##control_switches_switch_group", {-1, 0});
      if (switchGroup.begin()) {
        ImGui::BeginHorizontal("##control_switches_switch_group_layout", {-1, 0}, 0);
        {
          ImGui::BeginVertical("##control_switches_switch_group_layout_left");
          {
            ImGui::RadioButton(trNOOP("Single"), &m_operation, 0);
            ImGui::RadioButton(trNOOP("Range"), &m_operation, 1);
          }
          ImGui::EndVertical();
          ImGui::BeginVertical("##control_switches_switch_group_layout_right");
          {
            ImGui::BeginDisabled(m_operation != 0);
            {
              if (ImGui::EllipsesButton(m_operation != 0 ? "##control_switches_switch_empty" : (m_start == 0 ? "" : Database::instance()->switchNameAndId(m_start)).c_str(), ImVec2{-1, 0})) {
                picker.emplace(trNOOP("Switches"), Database::instance()->system.switches(), m_start);
                picker->setOpen(true);
              }
            }
            ImGui::EndDisabled();
            ImGui::BeginChild("##control_switches_switch_range", {-1, 0}, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_NavFlattened,
                              ImGuiWindowFlags_NoBackground);
            {
              ImGui::BeginDisabled(m_operation != 1);
              {
                ImGui::SetNextItemWidth((ImGui::GetContentRegionAvail().x * .5f) - (ImGui::CalcTextSize("~").x / 2));
                if (ImGui::SpinInt("##control_switches_switch_range_min", &m_rangeMin, 1, 100, m_operation == 1 ? nullptr : "")) {
                  m_rangeMin = std::clamp(m_rangeMin, 1, INT_MAX);
                }
                ImGui::SameLine();
                ImGui::Text("~");
                ImGui::SameLine();
                ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
                if (ImGui::SpinInt("##control_switches_switch_range_max", &m_rangeMax, 1, 100, m_operation == 1 ? nullptr : "")) {
                  m_rangeMax = std::clamp(m_rangeMax, 1, INT_MAX);
                }
              }
              ImGui::EndDisabled();
            }
            ImGui::EndChild();
          }
          ImGui::EndVertical();
        }
        ImGui::EndHorizontal();
      }
      switchGroup.end();
      GroupBox operationGroup(trNOOP("Operation"), "##control_switches_operation_group", {-1, 0});
      if (operationGroup.begin()) {
        ImGui::BeginHorizontal("##control_switches_operation_group_layout", {ImGui::GetContentRegionAvail().x, -1}, 0);
        {
          ImGui::Spring(0.33);
          ImGui::RadioButton(trNOOP("ON"), &m_isDisabled, 0);
          ImGui::Spring(0.33);
          ImGui::RadioButton(trNOOP("OFF"), &m_isDisabled, 1);
          ImGui::Spring(0.33);
        }
        ImGui::EndHorizontal();
      }
      operationGroup.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##control_switches_buttons_layout", {-1, 0}, 0);
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##control_switches_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          if (m_operation == 0) {
            command->start = m_start;
            command->end = m_end;
          } else {
            command->start = m_rangeMin;
            command->end = m_rangeMax;
          }
          command->turnOff = static_cast<ValueControl>(m_isDisabled);
          ImGui::CloseCurrentPopup();
          setOpen(false);
        } else if (ret == 1) {
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }
  return std::make_tuple(!m_open, m_confirmed);
}

void Dialog_ControlSwitches::drawPickers() {
  if (picker) {
    if (const auto [closed, confirmed] = picker->draw(); closed) {
      if (confirmed) {
        m_start = picker->selection();
        m_end = picker->selection();
      }
      picker.reset();
    }
  }
}


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

struct Dialog_ControlSwitches : IEventDialogController {
  Dialog_ControlSwitches() = delete;
  explicit Dialog_ControlSwitches(const std::string& name, const std::shared_ptr<ControlSwitches>& cmd = nullptr)
  : IEventDialogController(name)
  , command(cmd) {
    if (cmd == nullptr) {
      command.reset(new ControlSwitches());
    }
    m_start = command->start;
    m_end = command->end;
    m_isDisabled = static_cast<int>(command->turnOff);
  }
  std::tuple<bool, bool> draw() override;

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

private:
  void drawPickers();

  int m_start;
  int m_end;
  int m_rangeMin{1};
  int m_rangeMax{1};
  int m_isDisabled;
  int m_operation{0};

  std::shared_ptr<ControlSwitches> command;
  std::optional<VariableSwitchPicker> picker;
};


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

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

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

std::tuple<bool, bool> Dialog_ControlTimer::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###ControlTimer");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 24) + (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("{}###ControlTimer", m_name).c_str(), &m_open, ImGuiWindowFlags_NoResize)) {
    ImGui::BeginVertical("##control_timer_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      GroupBox operationGroup(trNOOP("Operation"), "##control_timer_operation_group", {-1, 0});
      if (operationGroup.begin()) {
        ImGui::BeginHorizontal("##control_timer_operation_group_layout", {ImGui::GetContentRegionAvail().x, 0});
        {
          ImGui::Spring(0.5);
          ImGui::RadioButton(trNOOP("Start"), &m_operation, 0);
          ImGui::Spring(0.33f);
          ImGui::RadioButton(trNOOP("Stop"), &m_operation, 1);
          ImGui::Spring(0.5);
        }
        ImGui::EndHorizontal();
      }
      operationGroup.end();
      ImGui::Spring();
      GroupBox timeGroup(trNOOP("Time"), "##control_timer_time_group", {-1, 0});
      if (timeGroup.begin()) {
        ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * .5f);
        if (ImGui::SpinInt("##control_timer_time_group_minutes", &m_minute, 1, 5, trNOOP("%2d min"))) {
          m_minute = std::clamp(m_minute, 0, 99);
        }
        ImGui::SameLine();
        ImGui::SetNextItemWidth(-1);
        if (ImGui::SpinInt("##control_timer_time_group_seconds", &m_second, 1, 5, trNOOP("%2d sec"))) {
          m_second = std::clamp(m_second, 0, 59);
        }
      }
      timeGroup.end();

      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##control_timer_button_layout");
      {
        ImGui::Spring();

        if (const auto ret = ImGui::ButtonGroup("##control_timer_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->control = static_cast<TimerControl>(m_operation);
          m_command->seconds = (m_minute * 60) + m_second;
          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/Class.hpp"
#include "Database/EventCommands/ChangeNickname.hpp"
#include "Database/EventCommands/ControlTimer.hpp"

struct Dialog_ControlTimer : IEventDialogController {
  Dialog_ControlTimer() = delete;
  explicit Dialog_ControlTimer(const std::string& name, const std::shared_ptr<ControlTimerCommand>& cmd = nullptr)
  : IEventDialogController(name)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new ControlTimerCommand());
    }
    m_operation = static_cast<int>(m_command->control);
    m_minute = m_command->seconds / 60;
    m_second = m_command->seconds % 60;
  }
  std::tuple<bool, bool> draw() override;

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

private:
  int m_operation;
  int m_minute = 0;
  int m_second;

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


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

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

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

  if (ImGui::BeginPopupModal(std::format("{}###ControlVariables", m_name).c_str(), &m_open)) {
    drawPickers();
    ImGui::BeginVertical("##control_variables_main_layout", ImGui::GetContentRegionAvail(), 0);
    {
      GroupBox variableGroupBox(trNOOP("Variable"), "##control_variables_variable_groupbox", {-1, 0});
      if (variableGroupBox.begin()) {
        ImGui::BeginHorizontal("##control_variables_variable_group_layout", {-1, -1}, 0);
        {
          ImGui::BeginVertical("##control_variables_variable_group_radios", {-1, 0}, 0);
          {
            ImGui::RadioButton(trNOOP("Single"), &m_isRange, 0); // Specific Switch
            ImGui::RadioButton(trNOOP("Range"), &m_isRange, 1);  // Range of Switches
          }
          ImGui::EndVertical();
          ImGui::BeginVertical("##control_variables_variable_group_variables", {-1, 0}, 0);
          {
            ImGui::BeginDisabled(m_isRange != 0);
            {
              ImGui::PushID("##control_variables_variable_group_variable_button");
              if (ImGui::EllipsesButton(m_isRange != 0 ? "" : Database::instance()->variableNameAndId(m_variableVar).c_str(), {-1, 0})) {
                m_singleRequest = true;
                m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_variableVar);
                m_variablePicker->setOpen(true);
              }
              ImGui::PopID();
            }
            ImGui::EndDisabled();
            ImGui::BeginChild("##control_variables_variable_range", {-1, 0},
                              ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_NoBackground);
            {
              ImGui::BeginDisabled(m_isRange != 1);
              {
                ImGui::SetNextItemWidth((ImGui::GetContentRegionAvail().x * .5f) - (ImGui::CalcTextSize("~").x / 2));
                if (ImGui::SpinInt("##control_variables_variable_range_min", &m_start, 1, 100, m_isRange == 1 ? nullptr : "")) {
                  m_start = std::clamp(m_start, 1, INT_MAX);
                }
                ImGui::SameLine();
                ImGui::Text("~");
                ImGui::SameLine();
                ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
                if (ImGui::SpinInt("##control_variables_variable_range_max", &m_end, 1, 100, m_isRange == 1 ? nullptr : "")) {
                  m_end = std::clamp(m_end, 1, INT_MAX);
                }
              }
              ImGui::EndDisabled();
            }
            ImGui::EndChild();
          }
          ImGui::EndVertical();
        }
        ImGui::EndHorizontal();
      }
      variableGroupBox.end();
      GroupBox operationGroupBox(trNOOP("Operation"), "##control_variables_operation_groupbox", {-1, 0});
      if (operationGroupBox.begin()) {
        ImGui::BeginHorizontal("##control_variables_operation_group_layout", {ImGui::GetContentRegionAvail().x, -1}, 0);
        {
          const auto weight = 1.f / (magic_enum::enum_count<VariableControlOperation>());
          ImGui::Spring(0.5);
          for (int i = 0; const auto& op : magic_enum::enum_values<VariableControlOperation>()) {
            ImGui::RadioButton(UndectorateEnumName(op).c_str(), &m_operation, static_cast<int>(op));
            if (i < magic_enum::enum_count<VariableControlOperation>()) {
              ImGui::Spring(weight);
            }
            ++i;
          }
          ImGui::Spring(0.5);
        }
        ImGui::EndHorizontal();
      }
      operationGroupBox.end();
      GroupBox operandGroupBox(trNOOP("Operand"), "##control_variables_operand_groupbox", {-1, ImGui::GetContentRegionAvail().y - (ImGui::GetFrameHeightWithSpacing() * 1.5f)});
      if (operandGroupBox.begin()) {
        ImGui::BeginVertical("##control_variables_operand_group_layout", ImGui::GetContentRegionAvail(), 0);
        {
          ImGui::BeginHorizontal("##control_variables_operand_group_layout_inner", {-1, -1}, 0);
          {
            ImGui::BeginVertical("control_variables_operand_group_radios", {-1, -1}, 0);
            {
              ImGui::RadioButton(trNOOP("Constant"), &m_operandType, 0);
              ImGui::RadioButton(trNOOP("Variable"), &m_operandType, 1);
              ImGui::RadioButton(trNOOP("Random"), &m_operandType, 2);
              ImGui::RadioButton(trNOOP("Game Data"), &m_operandType, 3);
              ImGui::RadioButton(trNOOP("Script:"), &m_operandType, 4);
            }
            ImGui::EndVertical();
            ImGui::BeginVertical("control_variables_operand_group_values", {-1, -1}, 0);
            {
              // Constant
              ImGui::BeginDisabled(m_operandType != 0);
              {
                ImGui::SetNextItemWidth(-1);
                if (ImGui::SpinInt("##control_variables_operand_constant", &m_constant, 1, 100, m_operandType == 0 ? nullptr : "")) {
                  m_constant = std::clamp(m_constant, -99999999, 99999999);
                }
              }
              ImGui::EndDisabled();
              // Variable
              ImGui::BeginDisabled(m_operandType != 1);
              {
                ImGui::PushID("####control_variables_operand_variable");
                if (ImGui::Button(m_operandType != 1 ? "" : Database::instance()->variableNameAndId(m_variableOperand).c_str(), ImVec2{-1, 0})) {
                  m_singleRequest = false;
                  m_variablePicker.emplace(trNOOP("Variables"), Database::instance()->system.variables(), m_variableOperand);
                  m_variablePicker->setOpen(true);
                }
                ImGui::PopID();
              }
              ImGui::EndDisabled();
              // Random
              ImGui::BeginChild("##control_variables_operand_rand", {-1, 0},
                                ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_NoBackground);
              {
                ImGui::BeginDisabled(m_operandType != 2);
                {
                  ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * .5f - (ImGui::CalcTextSize("~").x / 2));
                  if (ImGui::SpinInt("##control_variables_operand_rand_min", &m_randMin, 1, 100, m_operandType == 2 ? nullptr : "")) {
                    m_randMin = std::clamp(m_randMin, -99999999, 99999999);
                  }
                  ImGui::SameLine();
                  ImGui::TextUnformatted("~");
                  ImGui::SameLine();
                  ImGui::SetNextItemWidth(-1);
                  if (ImGui::SpinInt("##control_variables_operand_rand_max", &m_randMax, 1, 100, m_operandType == 2 ? nullptr : "")) {
                    m_randMax = std::clamp(m_randMax, -99999999, 99999999);
                  }
                }
                ImGui::EndDisabled();
              }
              ImGui::EndChild();
              // Game Data
              ImGui::BeginDisabled(m_operandType != 3);
              ImGui::SetNextItemWidth(-1);
              ImGui::PushID("##control_variable_game_data");
              if (ImGui::EllipsesButton(m_operandType != 3 ? "" : getGameDataString().c_str(), ImVec2{-1, 0})) {
                if (!m_gameDataDialog) {
                  m_gameDataDialog.emplace(trNOOP("Game Data"), m_gameDataType, m_gameDataRawSource, m_gameDataValue, m_troopId);
                }
                m_gameDataDialog->setOpen(true);
              }
              ImGui::PopID();
              ImGui::EndDisabled();
            }
            ImGui::EndVertical();
          }
          ImGui::EndHorizontal();
          ImGui::BeginDisabled(m_operandType != 4);
          {
            if (ImGui::BeginChild("##source_text_child", ImGui::GetContentRegionAvail(), ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize,
                                  ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NoMove)) {
              m_script.SetImGuiChildIgnored(true);
              m_script.SetHandleKeyboardInputs(m_operandType == 4);
              m_script.SetHandleMouseInputs(m_operandType == 4);
              m_script.Render("##source_text", {-1, -1});
            }
            ImGui::EndChild();
          }
          ImGui::EndDisabled();
        }
        ImGui::EndVertical();
      }
      operandGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##control_variables_buttons_layout", {-1, 0}, 0);
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##control_variables_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          if (m_isRange) {
            m_command->start = m_start;
            m_command->end = m_end;
          } else {
            m_command->start = m_variableVar;
            m_command->end = m_variableVar;
          }
          m_command->operation = static_cast<VariableControlOperation>(m_operation);
          m_command->operand = static_cast<VariableControlOperand>(m_operandType);
          if (m_command->operand == VariableControlOperand::Constant) {
            m_command->constant = m_constant;
          } else if (m_command->operand == VariableControlOperand::Variable) {
            m_command->variable = m_variableOperand;
          } else if (m_command->operand == VariableControlOperand::Random) {
            m_command->random.min = m_randMin;
            m_command->random.max = m_randMax;
          } else if (m_command->operand == VariableControlOperand::Script) {
            m_command->script = m_script.GetText();
          } else if (m_command->operand == VariableControlOperand::Game_Data) {
            m_command->gameData.type = static_cast<GameDataType>(m_gameDataType);
            m_command->gameData.rawSource = m_gameDataRawSource;
            m_command->gameData.value = m_gameDataValue;
          }
          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_ControlVariables::drawPickers() {
  if (m_variablePicker) {
    if (const auto [closed, confirmed] = m_variablePicker->draw(); closed) {
      if (confirmed) {
        if (m_singleRequest) {
          m_variableVar = m_variablePicker->selection();
        } else {
          m_variableOperand = m_variablePicker->selection();
        }
      }
      m_variablePicker.reset();
    }
  }

  if (m_gameDataDialog) {
    if (const auto [closed, confirmed] = m_gameDataDialog->draw(); confirmed) {
      m_gameDataType = static_cast<int>(m_gameDataDialog->getData().gameData.type);
      m_gameDataRawSource = m_gameDataDialog->getData().gameData.rawSource;
      m_gameDataValue = m_gameDataDialog->getData().gameData.value;
    }
  }
}

std::string Dialog_ControlVariables::getGameDataString() {
  switch (static_cast<GameDataType>(m_gameDataType)) {
  case GameDataType::Item:
    return Database::theNumberOf(Database::instance()->itemNameOrId(m_gameDataValue));
  case GameDataType::Weapon:
    return Database::theNumberOf(Database::instance()->weaponNameOrId(m_gameDataValue));
  case GameDataType::Armor:
    return Database::theNumberOf(Database::instance()->armorNameOrId(m_gameDataValue));
  case GameDataType::Actor:
    return Database::AOfB(DecodeEnumName(static_cast<ActorDataSource>(m_gameDataRawSource)), Database::instance()->actorNameOrId(m_gameDataValue));
  case GameDataType::Enemy: {
    std::string enemyName;
    if (m_troopId == 0) {
      enemyName = std::format("#{}", m_gameDataValue + 1);
    } else {
      enemyName = Database::instance()->troopMemberName(m_troopId, m_gameDataValue);
    }
    return Database::AOfB(DecodeEnumName(static_cast<EnemyDataSource>(m_gameDataRawSource)), enemyName);
  }
  case GameDataType::Character:
    return Database::AOfB(DecodeEnumName(static_cast<CharacterDataSource>(m_gameDataRawSource)), Database::instance()->eventNameOrId(m_gameDataValue));
  case GameDataType::Party:
    return trFormat("Actor ID of the party member #{0}", m_gameDataValue + 1);
  case GameDataType::Other:
    return DecodeEnumName(static_cast<OtherDataSource>(m_gameDataValue));
  }

  return "???";
}


code:
#pragma once
#include "Core/CommonUI/TextEditor.hpp"
#include "Core/CommonUI/VariableSwitchPicker.hpp"
#include "Core/EventCommands/Dialog_GameData.hpp"
#include "Core/EventCommands/IEventDialogController.hpp"
#include "Core/Log.hpp"
#include "Database/CommandParser.hpp"
#include "Database/Database.hpp"

struct Dialog_ControlVariables : IEventDialogController {
  Dialog_ControlVariables() = delete;
  explicit Dialog_ControlVariables(const std::string& name, const std::shared_ptr<ControlVariables>& cmd = nullptr, const int troopId = 0)
  : IEventDialogController(name)
  , m_troopId(troopId)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command = std::make_shared<ControlVariables>();
    }
    m_operation = static_cast<int>(m_command->operation);
    m_operandType = static_cast<int>(m_command->operand);

    if (m_command->start == m_command->end) {
      m_isRange = 0;
      m_start = m_command->start;
      m_end = m_command->end;
      m_variableVar = m_start;
    } else {
      m_isRange = 1;
      m_start = m_command->start;
      m_end = m_command->end;
    }
    if (m_command->operand == VariableControlOperand::Constant) {
      m_constant = m_command->constant;
    } else if (m_command->operand == VariableControlOperand::Variable) {
      m_variableOperand = m_command->variable;
    } else if (m_command->operand == VariableControlOperand::Random) {
      m_randMin = m_command->random.min;
      m_randMax = m_command->random.max;
    } else if (m_command->operand == VariableControlOperand::Script) {
      m_script.SetTextLines(splitString(m_command->script, '\n'));
    } else if (m_command->operand == VariableControlOperand::Game_Data) {
      m_gameDataType = static_cast<int>(m_command->gameData.type);
      m_gameDataRawSource = m_command->gameData.rawSource;
      m_gameDataValue = m_command->gameData.value;
    }
  }
  std::tuple<bool, bool> draw() override;

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

private:
  void drawPickers();
  // Command scope
  int m_troopId{0};
  int m_start{1};
  int m_end{1};
  int m_constant{0};
  int m_variableOperand{1};
  int m_operation{};
  int m_operandType{0};
  int m_gameDataType{7};
  int m_gameDataRawSource{0};
  int m_gameDataValue{0};
  TextEditor m_script;

  // Outside of command scope
  int m_randMin{0};
  int m_randMax{0};
  int m_variableVar{1};
  int m_isRange{0}; // Radio button (Single / Range)

  // Other
  std::shared_ptr<ControlVariables> m_command;
  std::optional<VariableSwitchPicker> m_variablePicker;
  bool m_singleRequest = false;
  bool m_confirmed{false};
  std::optional<Dialog_GameData> m_gameDataDialog;

  std::string getGameDataString();
};


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

#include "Database/Database.hpp"

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

std::tuple<bool, bool> Dialog_EnemyAppear::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###EnemyAppear");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 32) + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetFrameHeightWithSpacing() * 4) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});
  if (ImGui::BeginPopupModal(std::format("{}###EnemyAppear", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    ImGui::BeginVertical("##enemy_appear_main_layout");
    {
      GroupBox enemyGroupBox(trNOOP("Enemy"), "##enemy_appear_enemy_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (enemyGroupBox.begin()) {
        ImGui::SetNextItemWidth(-1);

        auto preview = Database::instance()->troopMemberName(m_troopId, m_troopMemberSelection);
        if (m_troopMemberSelection >= 0) {
          preview = std::format("#{} {}", m_troopMemberSelection + 1, preview);
        }

        if (ImGui::BeginCombo("##enemy_appear_change_list", preview.c_str())) {
          for (int i = 0; i < 8; ++i) {
            auto name = Database::instance()->troopMemberName(m_troopId, i);
            if (i >= 0) {
              name = std::format("#{} {}", i + 1, name);
            }

            if (ImGui::Selectable(name.c_str(), i == m_troopMemberSelection)) {
              m_troopMemberSelection = i;
            }
          }
          ImGui::EndCombo();
        }
      }
      enemyGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##enemy_appear_buttons_layout");
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##enemy_appear_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->troopMember = m_troopMemberSelection;
          ImGui::CloseCurrentPopup();
          setOpen(false);
        } else if (ret == 1) {
          ImGui::CloseCurrentPopup();
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }

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


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

struct Dialog_EnemyAppear : IEventDialogController {
  Dialog_EnemyAppear() = delete;
  explicit Dialog_EnemyAppear(const std::string& name, const std::shared_ptr<EnemyAppearCommand>& cmd = nullptr, const int troopId = 0)
  : IEventDialogController(name)
  , m_troopId(troopId)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new EnemyAppearCommand());
    }
    m_troopMemberSelection = m_command->troopMember;
    m_command->m_troopId = m_troopId;
  }
  std::tuple<bool, bool> draw() override;

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

private:
  int m_troopId = 0;
  int m_troopMemberSelection;

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


code:
#include "Core/EventCommands/Dialog_EnemyRecoverAll.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_EnemyRecoverAll::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###EnemyRecoverAll");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 32) + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetFrameHeightWithSpacing() * 4) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});
  if (ImGui::BeginPopupModal(std::format("{}###EnemyRecoverAll", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    ImGui::BeginVertical("##enemy_recover_all_main_layout");
    {
      GroupBox enemyGroupBox(trNOOP("Enemy"), "##enemy_recover_all_enemy_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (enemyGroupBox.begin()) {
        ImGui::SetNextItemWidth(-1);

        auto preview = Database::instance()->troopMemberName(m_troopId, m_troopMemberSelection);
        if (m_troopMemberSelection >= 0) {
          preview = std::format("#{} {}", m_troopMemberSelection + 1, preview);
        }

        if (ImGui::BeginCombo("##enemy_recover_all_change_list", preview.c_str())) {
          for (int i = -1; i < 8; ++i) {
            auto name = Database::instance()->troopMemberName(m_troopId, i);
            if (i >= 0) {
              name = std::format("#{} {}", i + 1, name);
            }

            if (ImGui::Selectable(name.c_str(), i == m_troopMemberSelection)) {
              m_troopMemberSelection = i;
            }
          }
          ImGui::EndCombo();
        }
      }
      enemyGroupBox.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##enemy_recover_all_buttons_layout");
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##enemy_recover_all_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->troopMember = m_troopMemberSelection;
          ImGui::CloseCurrentPopup();
          setOpen(false);
        } else if (ret == 1) {
          ImGui::CloseCurrentPopup();
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }

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


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

struct Dialog_EnemyRecoverAll : IEventDialogController {
  Dialog_EnemyRecoverAll() = delete;
  explicit Dialog_EnemyRecoverAll(const std::string& name, const std::shared_ptr<EnemyRecoverAllCommand>& cmd = nullptr, int troopId = 0)
  : IEventDialogController(name)
  , m_troopId(troopId)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new EnemyRecoverAllCommand());
    }
    m_troopMemberSelection = m_command->troopMember;
    m_command->m_troopId = m_troopId;
  }

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

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

  void setTroopId(const int troopId) { m_troopId = troopId; }

private:
  int m_troopId = 0;
  int m_troopMemberSelection = 0;

  bool m_confirmed{false};
  std::shared_ptr<EnemyRecoverAllCommand> m_command;
  std::tuple<bool, bool> result;
};


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

#include "Database/Database.hpp"

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

void Dialog_EnemyTransform::drawPickers() {
  if (m_enemyPicker) {
    if (const auto [closed, confirmed] = m_enemyPicker->draw(); closed) {
      if (confirmed) {
        m_enemy = m_enemyPicker->selection();
        m_enemyPicker.reset();
      }
    }
  }
}
std::tuple<bool, bool> Dialog_EnemyTransform::draw() {
  if (isOpen()) {
    ImGui::OpenPopup("###EnemyAppear");
  }
  ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
  const auto maxSize = ImVec2{(ImGui::CalcTextSize("#").x * 32) + (ImGui::GetStyle().FramePadding.x * 2), (ImGui::GetFrameHeightWithSpacing() * 4) + (ImGui::GetStyle().FramePadding.y * 2)};
  ImGui::SetNextWindowSize(maxSize, ImGuiCond_Appearing);
  ImGui::SetNextWindowSizeConstraints(maxSize, {FLT_MAX, FLT_MAX});
  if (ImGui::BeginPopupModal(std::format("{}###EnemyAppear", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    drawPickers();
    ImGui::BeginVertical("##enemy_transform_main_layout");
    {
      GroupBox memberGroupBox(trNOOP("Enemy"), "##enemy_transform_member_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (memberGroupBox.begin()) {
        ImGui::SetNextItemWidth(-1);

        auto preview = Database::instance()->troopMemberName(m_troopId, m_troopMemberSelection);
        if (m_troopMemberSelection >= 0) {
          preview = std::format("#{} {}", m_troopMemberSelection + 1, preview);
        }

        if (ImGui::BeginCombo("##enemy_transform_change_list", preview.c_str())) {
          for (int i = 0; i < 8; ++i) {
            auto name = Database::instance()->troopMemberName(m_troopId, i);
            if (i >= 0) {
              name = std::format("#{} {}", i + 1, name);
            }

            if (ImGui::Selectable(name.c_str(), i == m_troopMemberSelection)) {
              m_troopMemberSelection = i;
            }
          }
          ImGui::EndCombo();
        }
      }
      memberGroupBox.end();

      GroupBox enemyGroupBox(trNOOP("Transform to"), "##enemy_transform_enemy_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (enemyGroupBox.begin()) {
        ImGui::PushID("##enemy_transform_selection");
        if (ImGui::Button(Database::instance()->enemyNameAndId(m_enemy).c_str(), ImVec2{-1, 0})) {
          m_enemyPicker = ObjectPicker(trNOOP("Enemy"), Database::instance()->enemies.enemies(), m_enemy);
          m_enemyPicker->setOpen(true);
        }
        ImGui::PopID();
      }
      enemyGroupBox.end();

      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##enemy_transform_buttons_layout", {-1, -1});
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##enemy_transform_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->troopMember = m_troopMemberSelection;
          m_command->enemy = m_enemy;
          ImGui::CloseCurrentPopup();
          setOpen(false);
        } else if (ret == 1) {
          ImGui::CloseCurrentPopup();
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }

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


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

struct Dialog_EnemyTransform : IEventDialogController {
  Dialog_EnemyTransform() = delete;
  explicit Dialog_EnemyTransform(const std::string& name, const std::shared_ptr<EnemyTransformCommand>& cmd = nullptr, const int troopId = 0)
  : IEventDialogController(name)
  , m_troopId(troopId)
  , m_command(cmd) {
    if (cmd == nullptr) {
      m_command.reset(new EnemyTransformCommand());
    }
    m_enemy = m_command->enemy;
    m_troopMemberSelection = m_command->troopMember;
  }
  void drawPickers();
  std::tuple<bool, bool> draw() override;

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

private:
  int m_troopMemberSelection = 0;
  int m_enemy = 1;
  int m_troopId = 0;

  bool m_confirmed{false};
  std::shared_ptr<EnemyTransformCommand> m_command;
  std::optional<ObjectPicker<Enemy>> m_enemyPicker;
  std::tuple<bool, bool> result;
};


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

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


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

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

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

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


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

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

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

    ImGui::SeparatorText("Picture Number");
    ImGui::SetNextItemWidth(110);
    if (ImGui::InputInt("##erasepicture_id", &m_picture)) {
      if (m_picture > 999) {
        m_picture = 999;
      } else if (m_picture < 1)
        m_picture = 1;
    }

    if (ImGui::Button("OK")) {
      m_confirmed = true;
      command->picture = m_picture;
      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/ErasePicture.hpp"

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

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

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


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

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


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

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

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

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


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

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


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

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

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

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


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

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

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

#include <tuple>

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

  if (ImGui::BeginPopupModal(std::format("{}###FadeoutBGM", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    ImGui::BeginVertical("##fadeout_bgm_main_layout", ImGui::GetContentRegionAvail());
    {
      GroupBox durationGroup(trNOOP("Duration"), "##fadeout_bgm_duration_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (durationGroup.begin()) {
        const std::string durationText = trNOOP("seconds");
        ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - (ImGui::CalcItemSize(ImGui::CalcTextSize(durationText.c_str()), 0, 0).x + ImGui::GetStyle().FramePadding.x * 2));
        if (ImGui::SpinInt("##fadeout_bgm_input", &m_duration)) {
          m_duration = std::clamp(m_duration, 1, 999);
        }
        ImGui::SameLine();
        ImGui::TextUnformatted(durationText.c_str());
      }
      durationGroup.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##fadeout_bgm_button_group", {-1, -1});
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##fadeout_bgm_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->duration = m_duration;
          ImGui::CloseCurrentPopup();
          setOpen(false);
        } else if (ret == 1) {
          ImGui::CloseCurrentPopup();
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }

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


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

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

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

private:
  int m_duration;
  bool m_confirmed{false};
  std::shared_ptr<FadeoutBGM> m_command;
};


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

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

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

#include <tuple>

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

  if (ImGui::BeginPopupModal(std::format("{}###FadeoutBGS", m_name).c_str(), &m_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize)) {
    ImGui::BeginVertical("##fadeout_bgm_main_layout", ImGui::GetContentRegionAvail());
    {
      GroupBox durationGroup(trNOOP("Duration"), "##fadeout_bgm_duration_group", {-1, 0}, nullptr, ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize);
      if (durationGroup.begin()) {
        const std::string durationText = trNOOP("seconds");
        ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - (ImGui::CalcItemSize(ImGui::CalcTextSize(durationText.c_str()), 0, 0).x + ImGui::GetStyle().FramePadding.x * 2));
        if (ImGui::SpinInt("##fadeout_bgm_input", &m_duration)) {
          m_duration = std::clamp(m_duration, 1, 999);
        }
        ImGui::SameLine();
        ImGui::TextUnformatted(durationText.c_str());
      }
      durationGroup.end();
      ImGui::Spring();
      ImGui::SeparatorEx(ImGuiSeparatorFlags_Horizontal, ImGui::GetDPIScaledValue(1.5f));
      ImGui::BeginHorizontal("##fadeout_bgm_button_group", {-1, -1});
      {
        ImGui::Spring();
        if (const auto ret = ImGui::ButtonGroup("##fadeout_bgm_buttons", {trNOOP("OK"), trNOOP("Cancel")}); ret == 0) {
          m_confirmed = true;
          m_command->duration = m_duration;
          ImGui::CloseCurrentPopup();
          setOpen(false);
        } else if (ret == 1) {
          ImGui::CloseCurrentPopup();
          setOpen(false);
        }
      }
      ImGui::EndHorizontal();
    }
    ImGui::EndVertical();
    ImGui::EndPopup();
  }

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


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

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

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

private:
  int m_duration;
  bool m_confirmed{false};
  std::shared_ptr<FadeoutBGS> m_command;
};


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

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