code:
#include "Core/DatabaseEditor/DBMappingsTab.hpp"
#include "Core/Application.hpp"
#include "Core/ImGuiExt/ImGuiUtils.hpp"
#include "Database/Skills.hpp"

#include "imgui.h"
DBMappingsTab::DBMappingsTab(System& system, DatabaseEditor* parent)
: IDBEditorTab(parent)
, m_system(system) {
  m_switch_string = m_system.switche(m_selectedSwitch);
  m_variable_string = m_system.variable(m_selectedVariable);
  m_unicodes = getUnicodeFormatters();
}

void DBMappingsTab::draw() {

  const auto calc = ImGui::CalcTextSize("ABCDEFGHIJKLMNOPQRSTUV");
  ImGui::BeginChild("##orpg_mappings_editor_tab");
  {
    if (ImGui::BeginTabBar("##orpg_mappings_editor_tabs")) {

      if (ImGui::BeginTabItem("Variable")) {
        if (m_selectedTab != 0) {
          if (!m_reference_left.empty()) {
            m_reference_left.clear();
            m_reference_right.clear();
          }
          m_selectedTab = 0;
        }

        drawVariables();
        ImGui::EndTabItem();
      }
      if (ImGui::BeginTabItem("Switches")) {
        if (m_selectedTab != 1) {
          if (!m_reference_left.empty()) {
            m_reference_left.clear();
            m_reference_right.clear();
          }
          m_selectedTab = 1;
        }
        drawSwitches();
        ImGui::EndTabItem();
      }
      if (ImGui::BeginTabItem("Common Events")) {
        if (m_selectedTab != 2) {
          if (!m_reference_left.empty()) {
            m_reference_left.clear();
            m_reference_right.clear();
          }
          m_selectedTab = 2;
        }
        drawCommons();
        ImGui::EndTabItem();
      }
      // if (ImGui::TabItemButton("E", ImGuiTabItemFlags_NoReorder)) {}
      ImGui::EndTabBar();
    }
    ImGui::EndChild();
  }
}
void DBMappingsTab::drawCommons() {
  const auto calc = ImGui::CalcTextSize("ABCDEFGHIJKLMNOPQRSTUV");
  ImGui::BeginChild("##orpg_mapping_header_commons", ImVec2{ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y - ImGui::GetStyle().FramePadding.y});
  {
    ImGui::BeginChild("##orpg_mapping2_header_panel_left_commons", ImVec2{ImGui::GetContentRegionAvail().x, calc.y * 2 - (ImGui::GetStyle().ItemSpacing.y * 2)},
                      ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
    {
      ImGui::SetNextItemAllowOverlap();
      ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x);
      ImGui::BeginDisabled(m_selectedCommon == 0);
      float pos = ImGui::GetCursorPosY();
      if (ImGui::InputText("##orpg_mapping_commonevent_name", &m_common_string)) {
        Database::instance()->commonEvents.event(m_selectedCommon)->setName(m_common_string);
      }
      ImGui::SetCursorPos(ImVec2{ImGui::GetContentRegionAvail().x - (ImGui::GetStyle().FramePadding.x * 8) + 4, pos + 4.f});
      ImGui::TextDisabled("(?)");
      if (ImGui::BeginItemTooltip()) {
        ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
        ImGui::TextUnformatted(GetFormattingHelpText().data());
        ImGui::PopTextWrapPos();
        ImGui::EndTooltip();
      }
      ImGui::SameLine();
      ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 4.f);
      if (ImGui::Button(std::format("{}##{}", m_unicodes.at(m_selectedUnicode), "_commonevent").c_str(), ImVec2(30, 30))) {
        m_switch_string += m_unicodes.at(m_selectedUnicode);
        Database::instance()->commonEvents.event(m_selectedCommon)->setName(m_common_string);
      }
      if (ImGui::IsItemHovered()) {
        if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
          ImGui::OpenPopup("unicodePopup");
        }
      }
      if (ImGui::BeginPopup("unicodePopup")) {
        ImGui::SeparatorText("Unicodes");
        for (int i = 0; i < m_unicodes.size(); i++) {
          if (ImGui::Selectable(m_unicodes.at(i).data())) {
            m_selectedUnicode = i;
          }
        }
        ImGui::EndPopup();
      }
      ImGui::EndDisabled();
      ImGui::PopItemWidth();
    }
    ImGui::EndChild();
    ImGui::BeginChild("##orpg_mapping_panel_left_commons", ImVec2{ImGui::GetContentRegionMax().x / 2, ImGui::GetContentRegionAvail().y});
    {

      int index{0};
      for (auto& common : Database::instance()->commonEvents.events()) {
        if (index > 0) {
          bool isStyle{false};
          if (std::find(m_reference_left.begin(), m_reference_left.end(), index) != m_reference_left.end()) {
            ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(1.0f, 0.0f, 0.0f, 0.43f));
            ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(1.0f, 0.0f, 0.0f, 0.43f));
            ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(1.0f, 0.0f, 0.0f, 0.43f));
            isStyle = true;
          }
          bool isFormatted{false};
          if (isUnicodeFormatting(common.value().name())) {
            ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            isFormatted = true;
          }

          if (ImGui::Selectable(std::format("{}##orpg_mappings_{}_commons", std::format("#{:04} {}", common->id(), common.value().name()), index).c_str(),
                                m_selectedCommon == index || isStyle || isFormatted)) {
            m_selectedCommon = index;
            m_common_string = common.value().name();
          }
          if (isStyle || isFormatted) {
            ImGui::PopStyleColor(3);
          }
        }

        ImGuiDragDropFlags src_flags = 0;
        src_flags |= ImGuiDragDropFlags_SourceNoDisableHover;     // Keep the source displayed as hovered
        src_flags |= ImGuiDragDropFlags_SourceNoHoldToOpenOthers; // Because our dragging is local, we disable the feature of opening foreign treenodes/tabs while dragging
        // src_flags |= ImGuiDragDropFlags_SourceNoPreviewTooltip; // Hide the tooltip
        if (ImGui::BeginDragDropSource(src_flags)) {
          if (!(src_flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
            ImGui::Text("Moving");
          ImGui::SetDragDropPayload("CommonList", &index, sizeof(int));
          ImGui::EndDragDropSource();
        }
        index++;
      }
    }
    ImGui::EndChild();
    ImGui::SameLine();
    ImGui::BeginChild("##orpg_mapping_switch_panel_right_commons", ImVec2{ImGui::GetContentRegionMax().x / 2 - ImGui::GetStyle().FramePadding.x, ImGui::GetContentRegionAvail().y});
    {

      int index{0};
      for (auto& common : Database::instance()->commonEvents.events()) {
        if (index > 0) {

          bool isStyle{false};
          if (std::find(m_reference_right.begin(), m_reference_right.end(), index) != m_reference_right.end()) {
            ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.0f, 1.0f, 0.0f, 0.43f));
            ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.0f, 1.0f, 0.0f, 0.43f));
            ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.0f, 1.0f, 0.0f, 0.43f));
            isStyle = true;
          }
          bool isFormatted{false};
          if (isUnicodeFormatting(common.value().name())) {
            ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            isFormatted = true;
          }
          if (ImGui::Selectable(std::format("{}##orpg_mappings_{}_commons", std::format("#{:04} {}", common->id(), common.value().name()), index).c_str(),
                                m_selectedCommon == index || isStyle || isFormatted)) {
            m_selectedCommon = index;
            m_common_string = common.value().name();
          }
          if (isStyle || isFormatted) {
            ImGui::PopStyleColor(3);
          }
        }
        if (ImGui::BeginDragDropTarget()) {
          ImGuiDragDropFlags target_flags = 0;
          // target_flags |= ImGuiDragDropFlags_AcceptBeforeDelivery; // Don't wait until the delivery (release mouse button on a target) to do something
          //  target_flags |= ImGuiDragDropFlags_AcceptNoDrawDefaultRect; // Don't display the yellow rectangle
          if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("CommonList", target_flags)) {
            int move_from = *static_cast<const int*>(payload->Data);
            int move_to = index;
            reference_from.findAllReferences(move_from, SearchType::CommonEvent);
            reference_to.findAllReferences(move_to, SearchType::CommonEvent);

            m_reference_left.push_back(move_from);
            m_reference_right.push_back(move_to);
            for (auto& cmd : reference_from.getCommands()) {
              cmd.getCommand()->setReference(move_from, -1, SearchType::CommonEvent);
            }
            for (auto& cmd : reference_from.getCommons()) {
              cmd.getCommand()->setReference(move_from, -1, SearchType::CommonEvent);
            }

            for (auto& cmd : reference_to.getCommands()) {
              cmd.getCommand()->setReference(move_to, move_from, SearchType::CommonEvent);
            }
            for (auto& cmd : reference_to.getCommons()) {
              cmd.getCommand()->setReference(move_to, move_from, SearchType::CommonEvent);
            }

            for (auto& cmd : reference_from.getCommands()) {
              cmd.getCommand()->setReference(-1, move_to, SearchType::CommonEvent);
            }
            for (auto& cmd : reference_from.getCommons()) {
              cmd.getCommand()->setReference(-1, move_to, SearchType::CommonEvent);
            }
            Database::instance()->commonEvents.swapReference(move_from, move_to);
            Database::instance()->gameConstants.swap(move_from, move_to, Database::instance()->gameConstants.commonEvents);
          }
          ImGui::EndDragDropTarget();
        }
        index++;
      }
    }
    ImGui::EndChild();
  }
  ImGui::EndChild();
}
void DBMappingsTab::drawSwitches() {

  const auto calc = ImGui::CalcTextSize("ABCDEFGHIJKLMNOPQRSTUV");
  ImGui::BeginChild("##orpg_mapping2_header_switches", ImVec2{ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y - ImGui::GetStyle().FramePadding.y * 11});
  {
    ImGui::BeginChild("##orpg_mapping2_header_panel_left_switches", ImVec2{ImGui::GetContentRegionAvail().x, calc.y * 2 - (ImGui::GetStyle().ItemSpacing.y * 2)},
                      ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);

    {
      ImGui::SetNextItemAllowOverlap();
      ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x);
      float pos = ImGui::GetCursorPosY();
      ImGui::BeginDisabled(m_selectedSwitch == 0);
      if (ImGui::InputText("##orpg_mapping_switch_name", &m_switch_string)) {
        Database::instance()->system.setSwitch(m_selectedSwitch, m_switch_string);
      }
      ImGui::SetCursorPos(ImVec2{ImGui::GetContentRegionAvail().x - (ImGui::GetStyle().FramePadding.x * 8) + 4, pos + 4.f});
      ImGui::TextDisabled("(?)");
      if (ImGui::BeginItemTooltip()) {
        ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
        ImGui::TextUnformatted(GetFormattingHelpText().data());
        ImGui::PopTextWrapPos();
        ImGui::EndTooltip();
      }
      ImGui::SameLine();
      ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 4.f);
      if (ImGui::Button(std::format("{}##{}", m_unicodes.at(m_selectedUnicode), "_switch").c_str(), ImVec2(30, 30))) {
        m_switch_string += m_unicodes.at(m_selectedUnicode);
        Database::instance()->system.setSwitch(m_selectedSwitch, m_switch_string);
      }
      if (ImGui::IsItemHovered()) {
        if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
          ImGui::OpenPopup("unicodePopup");
        }
      }
      ImGui::EndDisabled();
      ImGui::PopItemWidth();

      if (ImGui::BeginPopup("unicodePopup")) {
        ImGui::SeparatorText("Unicodes");
        for (int i = 0; i < m_unicodes.size(); i++) {
          if (ImGui::Selectable(m_unicodes.at(i).data())) {
            m_selectedUnicode = i;
          }
        }
        ImGui::EndPopup();
      }
    }
    ImGui::EndChild();
    ImGui::BeginChild("##orpg_mapping2_switches_panel_left_switches", ImVec2{ImGui::GetContentRegionMax().x / 2, ImGui::GetContentRegionAvail().y});
    {

      int index{0};
      for (auto& sw : m_system.switches()) {
        if (index > 0) {

          bool isStyle{false};
          if (std::find(m_reference_left.begin(), m_reference_left.end(), index) != m_reference_left.end()) {
            ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(1.0f, 0.0f, 0.0f, 0.43f));
            ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(1.0f, 0.0f, 0.0f, 0.43f));
            ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(1.0f, 0.0f, 0.0f, 0.43f));
            isStyle = true;
          }
          bool isFormatted{false};
          if (isUnicodeFormatting(sw)) {
            ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            isFormatted = true;
          }

          if (ImGui::Selectable(std::format("{}##orpg_mappings2_{}_switches", std::format("#{:04} {}", index, sw), index).c_str(), m_selectedSwitch == index || isStyle || isFormatted)) {
            m_selectedSwitch = index;
            m_switch_string = sw;
          }
          if (isStyle || isFormatted) {
            ImGui::PopStyleColor(3);
          }
        }

        ImGuiDragDropFlags src_flags = 0;
        src_flags |= ImGuiDragDropFlags_SourceNoDisableHover;     // Keep the source displayed as hovered
        src_flags |= ImGuiDragDropFlags_SourceNoHoldToOpenOthers; // Because our dragging is local, we disable the feature of opening foreign treenodes/tabs while dragging
        if (ImGui::BeginDragDropSource(src_flags)) {
          if (!(src_flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
            ImGui::Text("Moving");
          ImGui::SetDragDropPayload("SwitchList", &index, sizeof(int));
          ImGui::EndDragDropSource();
        }
        index++;
      }
    }
    ImGui::EndChild();
    ImGui::SameLine();
    ImGui::BeginChild("##orpg_mapping2_switch_panel_right_switches", ImVec2{ImGui::GetContentRegionMax().x / 2 - ImGui::GetStyle().FramePadding.x, ImGui::GetContentRegionAvail().y});
    {

      int index{0};
      for (auto& sw : m_system.switches()) {
        if (index > 0) {
          bool isStyle{false};
          if (std::find(m_reference_right.begin(), m_reference_right.end(), index) != m_reference_right.end()) {
            ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.0f, 1.0f, 0.0f, 0.43f));
            ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.0f, 1.0f, 0.0f, 0.43f));
            ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.0f, 1.0f, 0.0f, 0.43f));
            isStyle = true;
          }
          bool isFormatted{false};
          if (isUnicodeFormatting(sw)) {
            ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            isFormatted = true;
          }
          if (ImGui::Selectable(std::format("{}##orpg_mappings2_switch_{}_switches", std::format("#{:04} {}", index, sw), index).c_str(), m_selectedSwitch == index || isStyle || isFormatted)) {
            m_selectedSwitch = index;
            m_switch_string = sw;
          }
          if (isStyle || isFormatted) {
            ImGui::PopStyleColor(3);
          }
        }
        if (ImGui::BeginDragDropTarget()) {
          ImGuiDragDropFlags target_flags = 0;
          if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("SwitchList", target_flags)) {
            int move_from = *static_cast<const int*>(payload->Data);
            int move_to = index;

            reference_from.findAllReferences(move_from, SearchType::Switch);
            reference_to.findAllReferences(move_to, SearchType::Switch);

            m_reference_left.push_back(move_from);
            m_reference_right.push_back(move_to);

            // Reference 1 => Temp Id
            for (auto& ev : reference_from.getEvents()) {
              ev.getEvent().setEventReference(ev.getPage(), move_from, -1, SearchType::Switch);
            }
            for (auto& cmd : reference_from.getCommands()) {
              cmd.getCommand()->setReference(move_from, -1, SearchType::Switch);
            }
            for (auto& cmd : reference_from.getCommons()) {
              if (cmd.getStep() == -2) {
                Database::instance()->commonEvents.event(cmd.getCommonEventId())->setReference(move_from, -1, SearchType::Switch);
              } else {
                cmd.getCommand()->setReference(move_from, -1, SearchType::Switch);
              }
            }

            // Reference 2 => Reference 1
            for (auto& ev : reference_from.getEvents()) {
              ev.getEvent().setEventReference(ev.getPage(), move_to, move_from, SearchType::Switch);
            }

            for (auto& cmd : reference_to.getCommands()) {
              cmd.getCommand()->setReference(move_to, move_from, SearchType::Switch);
            }
            for (auto& cmd : reference_to.getCommons()) {
              if (cmd.getStep() == -2) {
                Database::instance()->commonEvents.event(cmd.getCommonEventId())->setReference(move_to, move_from, SearchType::Switch);
              } else {
                cmd.getCommand()->setReference(move_to, move_from, SearchType::Switch);
              }
            }

            // Reference 1 => Reference 2
            for (auto& ev : reference_from.getEvents()) {
              ev.getEvent().setEventReference(ev.getPage(), -1, move_to, SearchType::Switch);
            }

            for (auto& cmd : reference_from.getCommands()) {
              cmd.getCommand()->setReference(-1, move_to, SearchType::Switch);
            }
            for (auto& cmd : reference_from.getCommons()) {
              if (cmd.getStep() == -2) {
                Database::instance()->commonEvents.event(cmd.getCommonEventId())->setReference(-1, move_to, SearchType::Switch);
              } else {
                cmd.getCommand()->setReference(-1, move_to, SearchType::Switch);
              }
            }

            Database::instance()->system.swapSwitchReference(move_from, move_to);
            Database::instance()->gameConstants.swap(move_from, move_to, Database::instance()->gameConstants.switches);
          }
          ImGui::EndDragDropTarget();
        }
        index++;
      }
    }
    ImGui::EndChild();
  }
  ImGui::EndChild();

  ImGui::BeginChild("##orpg_mappings2_footer_switches");
  {
    ImGui::BeginChild("##orpg_mapping2_footer_panel_left_switches", ImVec2{ImGui::GetContentRegionMax().x / 2, 0});
    {
      ImGui::SeparatorText(trFormat("Max Switches {}", m_system.switches().size() - 1).c_str());
      if (ImGui::Button("Change Max", ImVec2{ImGui::GetContentRegionMax().x - 8, 0})) {
        m_changeIntDialogOpen = true;
        m_editMaxSwitches = m_system.switches().size() - 1;
      }
    }
    ImGui::EndChild();
    ImGui::SameLine();
    ImGui::BeginChild("##orpg_mapping2_footer_panel_right_switches", ImVec2{ImGui::GetContentRegionMax().x / 2 - 10, 0});
    {

      ImGui::SeparatorText(trFormat("Max Switches {}", m_system.switches().size() - 1).c_str());
      if (ImGui::Button("Change Max", ImVec2{ImGui::GetContentRegionMax().x - 8, 0})) {
        m_changeIntDialogOpen = true;
        m_editMaxVariables = m_system.variables().size() - 1;
      }
    }
    ImGui::EndChild();
  }
  ImGui::EndChild();
}
void DBMappingsTab::drawVariables() {
  const auto calc = ImGui::CalcTextSize("ABCDEFGHIJKLMNOPQRSTUV");
  ImGui::BeginChild("##orpg_mapping2_header_variables", ImVec2{ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y - ImGui::GetStyle().FramePadding.y * 11});
  {
    ImGui::BeginChild("##orpg_mapping2_header_panel_left_variables", ImVec2{ImGui::GetContentRegionAvail().x, calc.y * 2 - (ImGui::GetStyle().ItemSpacing.y * 2)},
                      ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
    {

      ImGui::SetNextItemAllowOverlap();
      ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x);
      float pos = ImGui::GetCursorPosX();
      ImGui::BeginDisabled(m_selectedVariable == 0);
      if (ImGui::InputText("##orpg_mapping_variable_name", &m_variable_string)) {
        Database::instance()->system.setVariable(m_selectedVariable, m_variable_string);
      }
      ImGui::SetCursorPos(ImVec2{ImGui::GetContentRegionAvail().x - (ImGui::GetStyle().FramePadding.x * 8) + 4, pos + 4.f});
      ImGui::TextDisabled("(?)");
      if (ImGui::BeginItemTooltip()) {
        ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
        ImGui::TextUnformatted(GetFormattingHelpText().data());
        ImGui::PopTextWrapPos();
        ImGui::EndTooltip();
      }
      ImGui::SameLine();
      ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 4.f);
      if (ImGui::Button(std::format("{}##{}", m_unicodes.at(m_selectedUnicode), "_variable").c_str(), ImVec2(30, 30))) {
        m_variable_string += m_unicodes.at(m_selectedUnicode);
        Database::instance()->system.setSwitch(m_selectedVariable, m_variable_string);
      }
      if (ImGui::IsItemHovered()) {
        if (ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
          ImGui::OpenPopup("unicodePopup");
        }
      }
      ImGui::EndDisabled();
      ImGui::PopItemWidth();

      if (ImGui::BeginPopup("unicodePopup")) {
        ImGui::SeparatorText("Unicodes");
        for (int i = 0; i < m_unicodes.size(); i++) {
          if (ImGui::Selectable(m_unicodes.at(i).data())) {
            m_selectedUnicode = i;
          }
        }
        ImGui::EndPopup();
      }
    }
    ImGui::EndChild();
    ImGui::BeginChild("##orpg_mapping2_panel_left_variables", ImVec2{ImGui::GetContentRegionMax().x / 2, ImGui::GetContentRegionAvail().y});
    {

      int index{0};
      for (auto& variable : m_system.variables()) {
        if (index > 0) {
          bool isStyle{false};
          if (std::find(m_reference_left.begin(), m_reference_left.end(), index) != m_reference_left.end()) {
            ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(1.0f, 0.0f, 0.0f, 0.43f));
            ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(1.0f, 0.0f, 0.0f, 0.43f));
            ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(1.0f, 0.0f, 0.0f, 0.43f));
            isStyle = true;
          }
          bool isFormatted{false};
          if (isUnicodeFormatting(variable)) {
            ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            isFormatted = true;
          }
          if (ImGui::Selectable(std::format("{}##orpg_mappings2_variable_{}_variables", std::format("#{:04} {}", index, variable), index).c_str(),
                                m_selectedVariable == index || isStyle || isFormatted)) {
            m_selectedVariable = index;
            m_variable_string = variable;
          }
          if (isStyle || isFormatted) {
            ImGui::PopStyleColor(3);
          }
        }

        ImGuiDragDropFlags src_flags = 0;
        src_flags |= ImGuiDragDropFlags_SourceNoDisableHover;     // Keep the source displayed as hovered
        src_flags |= ImGuiDragDropFlags_SourceNoHoldToOpenOthers; // Because our dragging is local, we disable the feature of opening foreign treenodes/tabs while dragging
        // src_flags |= ImGuiDragDropFlags_SourceNoPreviewTooltip; // Hide the tooltip
        if (ImGui::BeginDragDropSource(src_flags)) {
          if (!(src_flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
            ImGui::Text("Moving");
          ImGui::SetDragDropPayload("VariableList", &index, sizeof(int));
          ImGui::EndDragDropSource();
        }
        index++;
      }
    }
    ImGui::EndChild();
    ImGui::SameLine();
    ImGui::BeginChild("##orpg_mapping2_panel_right_variables", ImVec2{ImGui::GetContentRegionMax().x / 2 - ImGui::GetStyle().FramePadding.x, ImGui::GetContentRegionAvail().y});
    {

      int index{0};
      for (auto& variable : m_system.variables()) {
        if (index > 0) {
          bool isStyle{false};
          if (std::find(m_reference_right.begin(), m_reference_right.end(), index) != m_reference_right.end()) {
            ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.0f, 1.0f, 0.0f, 0.43f));
            ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.0f, 1.0f, 0.0f, 0.43f));
            ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.0f, 1.0f, 0.0f, 0.43f));
            isStyle = true;
          }
          bool isFormatted{false};
          if (isUnicodeFormatting(variable)) {
            ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.110f, 0.153f, 0.173f, 1.0f));
            isFormatted = true;
          }
          if (ImGui::Selectable(std::format("{}##orpg_mappings2_{}_variables", std::format("#{:04} {}", index, variable), index).c_str(), m_selectedVariable == index || isStyle || isFormatted)) {
            m_selectedVariable = index;
            m_variable_string = variable;
          }
          if (isStyle || isFormatted) {
            ImGui::PopStyleColor(3);
          }
        }
        if (ImGui::BeginDragDropTarget()) {
          ImGuiDragDropFlags target_flags = 0;
          if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("VariableList", target_flags)) {
            int move_from = *static_cast<const int*>(payload->Data);
            int move_to = index;
            reference_from.findAllReferences(move_from, SearchType::Variable);
            reference_to.findAllReferences(move_to, SearchType::Variable);

            m_reference_left.push_back(move_from);
            m_reference_right.push_back(move_to);

            for (auto& cmd : reference_from.getCommands()) {
              cmd.getCommand()->setReference(move_from, -1, SearchType::Variable);
            }
            for (auto& cmd : reference_from.getCommons()) {
              cmd.getCommand()->setReference(move_from, -1, SearchType::Variable);
            }

            for (auto& cmd : reference_to.getCommands()) {
              cmd.getCommand()->setReference(move_to, move_from, SearchType::Variable);
            }
            for (auto& cmd : reference_to.getCommons()) {
              cmd.getCommand()->setReference(move_to, move_from, SearchType::Variable);
            }

            for (auto& cmd : reference_from.getCommands()) {
              cmd.getCommand()->setReference(-1, move_to, SearchType::Variable);
            }
            for (auto& cmd : reference_from.getCommons()) {
              cmd.getCommand()->setReference(-1, move_to, SearchType::Variable);
            }

            Database::instance()->system.swapVariableReference(move_from, move_to);
            Database::instance()->gameConstants.swap(move_from, move_to, Database::instance()->gameConstants.variables);
          }
          ImGui::EndDragDropTarget();
        }
        index++;
      }
    }
    ImGui::EndChild();
  }
  ImGui::EndChild();

  ImGui::BeginChild("##orpg_mappings2_footer_variables");
  {
    ImGui::BeginChild("##orpg_mapping2_footer_panel_left_variables", ImVec2{ImGui::GetContentRegionMax().x / 2, 0});
    {
      ImGui::SeparatorText(trFormat("Max Variables {}", m_system.variables().size() - 1).c_str());
      if (ImGui::Button("Change Max", ImVec2{ImGui::GetContentRegionMax().x - 8, 0})) {
        m_changeIntDialogOpen = true;
        m_editMaxVariables = m_system.variables().size() - 1;
      }
    }
    ImGui::EndChild();
    ImGui::SameLine();
    ImGui::BeginChild("##orpg_mapping2_footer_panel_right_variables", ImVec2{ImGui::GetContentRegionMax().x / 2 - 10, 0});
    {

      ImGui::SeparatorText(trFormat("Max Variables {}", m_system.variables().size() - 1).c_str());
      if (ImGui::Button("Change Max", ImVec2{ImGui::GetContentRegionMax().x - 8, 0})) {
        m_changeIntDialogOpen = true;
        m_editMaxVariables = m_system.variables().size() - 1;
      }
    }
    ImGui::EndChild();
  }
  ImGui::EndChild();
}
bool DBMappingsTab::isUnicodeFormatting(const std::string& text) {
  if (text.contains("\u25bc")) {
    return true;
  }
  return false;
}


code:
#pragma once
#include "Core/DatabaseEditor/IDBEditorTab.hpp"
#include "Core/ReferenceSearch.hpp"
#include "DBCommonEventsTab.hpp"
#include "Database/System.hpp"

class DBMappingsTab final : public IDBEditorTab {
public:
  DBMappingsTab() = delete;
  explicit DBMappingsTab(System& system, DatabaseEditor* parent);

  bool isUnicodeFormatting(const std::string& text);
  void draw() override;
  void drawVariables();
  void drawSwitches();
  void drawCommons();
  std::vector<int>& getHeaders() override { return m_headers; }
  int getHeader(int index) override { return m_headers.at(index); }
  bool hasHeader() override { return !m_headers.empty(); }
  void setHeaderRange(int start, int end) override {
    m_categoryStart = start;
    m_categoryEnd = end;
  }
  std::string_view GetFormattingHelpText() { return trNOOP("Reference updating does not support:\n- Ranges\n- Data without game constants\nThese must be updated manually."); }
  std::string getName(int index) override { return ""; }
  int getCount() override { return 0; }

private:
  int m_categoryStart;
  int m_categoryEnd;
  std::vector<int> m_headers;
  System& m_system;
  int m_selectedVariable{0};
  int m_selectedSwitch{0};
  int m_selectedCommon{0};
  int m_selectedTab{0};

  std::string m_switch_string;
  std::string m_variable_string;
  std::string m_common_string;

  ReferenceSearch reference_from;
  ReferenceSearch reference_to;

  std::vector<int> m_reference_left{};
  std::vector<int> m_reference_right{};

  float m_splitterWidth = 300.f;
  bool m_changeIntDialogOpen = false;
  bool m_changeConfirmDialogOpen = false;
  int m_editMaxVariables{};
  int m_editMaxSwitches{};
  int m_selectedUnicode{0};
  std::vector<std::string_view> m_unicodes;
};

repo_name: Antidote/openrpgeditor

license: mit


code:
#include "Core/DatabaseEditor/DBSkillsTab.hpp"
#include "Core/Application.hpp"
#include "Core/ImGuiExt/ImGuiUtils.hpp"
#include "Database/Skills.hpp"

#include "imgui.h"
#include "imgui_internal.h"
DBSkillsTab::DBSkillsTab(Skills& skills, DatabaseEditor* parent)
: IDBEditorTab(parent)
, m_skills(skills) {
  m_selectedSkill = m_skills.skill(1);
  if (m_selectedSkill) {
    m_effectsEditor.setEffects(&m_selectedSkill->effects());
  }
  m_maxSkills = m_skills.count();
}

void DBSkillsTab::draw() {
  if (m_animationPicker) {
    if (const auto [closed, confirmed] = m_animationPicker->draw(); closed) {
      if (confirmed) {
        m_selectedSkill->setAnimationId(m_animationPicker->selection());
      }
      m_animationPicker.reset();
    }
  }
  if (!m_iconButtonTexture) {
    m_iconButtonTexture.emplace();
    m_iconButtonTexture->setSize(56, 56);
  }
  if (m_selectedSkill && !m_iconButtonTexture->hasCompositeTextures()) {
    const auto* iconSheet = m_parent->getIconSheet();
    const auto& [uv0, uv1] = iconSheet->rectForId(m_selectedSkill->iconIndex());
    const Point offset{static_cast<int>(uv0.x() * iconSheet->texture().width()), static_cast<int>(uv0.y() * iconSheet->texture().height())};
    m_iconButtonTexture->setTexturesToComposite({{iconSheet->texture(), {iconSheet->iconWidth(), iconSheet->iconHeight()}, offset}});
  }
  ImGui::BeginChild("#orpg_skills_editor");
  {
    const auto calc = ImGui::CalcTextSize("ABCDEFGHIJKLMNOPQRSTUV");
    ImGui::BeginChild("##orpg_skills_editor_skills", ImVec2{calc.x + (ImGui::GetStyle().ItemSpacing.x * 2), 0}, ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX, ImGuiWindowFlags_NoScrollbar);
    {
      ImGui::BeginGroup();
      {
        ImGui::SeparatorText("Skills");
        ImGui::BeginChild("##orpg_skills_editor_skills_list", ImVec2{0, ImGui::GetContentRegionMax().y - ((calc.y + ImGui::GetStyle().ItemSpacing.y) * 4)}, ImGuiChildFlags_Borders);
        {
          ImGui::BeginGroup();
          {
            for (auto& skill_ : m_skills.skills()) {
              if (skill_.id() == 0) {
                continue;
              }

              char name[4096];
              snprintf(name, 4096, "%04i %s", skill_.id(), skill_.name().c_str());
              if (ImGui::Selectable(name, &skill_ == m_selectedSkill) || (ImGui::IsItemFocused() && m_selectedSkill != &skill_)) {
                m_selectedSkill = &skill_;
                m_effectsEditor.setEffects(&m_selectedSkill->effects());
              }
            }
          }
          ImGui::EndGroup();
        }
        ImGui::EndChild();
        char str[4096];
        snprintf(str, 4096, "Max Skills %i", m_maxSkills);
        ImGui::SeparatorText(str);
        if (ImGui::Button("Change Max", ImVec2{ImGui::GetContentRegionMax().x - 8, 0})) {
          m_changeIntDialogOpen = true;
          m_editMaxSkills = m_maxSkills;
        }
      }
      ImGui::EndGroup();
    }
    ImGui::EndChild();
    ImGui::SameLine();
    ImGui::BeginChild("##orpg_skills_editor_skills_skill_properties", {}, ImGuiChildFlags_Borders);
    {
      if (m_selectedSkill) {
        ImGui::BeginChild("##orpg_skills_skill_panel_left", ImVec2{ImGui::GetContentRegionMax().x / 2, 0.f}, ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX);
        {
          ImGui::BeginGroup();
          {
            ImGui::SeparatorText("General Settings");
            // Name
            ImGui::BeginGroup();
            {
              char name[4096];
              strncpy(name, m_selectedSkill->name().c_str(), 4096);
              if (ImGui::LabelOverLineEdit(std::format("##orpg_skills_editor_skills_skill_name_{}", m_selectedSkill->id()).c_str(), "Name:", name, 4096, ImGui::GetContentRegionMax().x / 2 - 16,
                                           nullptr, 0)) {
                m_selectedSkill->setName(name);
              }
            }
            ImGui::EndGroup();
            ImGui::SameLine();
            // Icon
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetStyle().ItemSpacing.y);
            ImGui::BeginGroup();
            {
              ImGui::BeginGroup();
              {
                ImGui::TextUnformatted("Icon:");
                ImGui::Text("%s", std::to_string(m_selectedSkill->iconIndex()).c_str());
              }
              ImGui::EndGroup();
              ImGui::SameLine();
              // ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetStyle().ItemSpacing.y);
              if (ImGui::ImageButtonEx(ImGui::GetID("##orpg_database_items_image"), m_iconButtonTexture->get(), ImVec2(m_iconButtonTexture->size()), {0.f, 0.f}, {1.f, 1.f}, {}, {1.f, 1.f, 1.f, 1.f},
                                       ImGuiButtonFlags_PressedOnDoubleClick)) {}
            }
            ImGui::EndGroup();
            // Description
            ImGui::BeginGroup();
            {
              char description[4096];
              strncpy(description, m_selectedSkill->description().c_str(), 4096);
              ImGui::TextUnformatted("Description:");
              if (ImGui::InputTextMultiline(std::format("##orpg_database_skills_description_{}", m_selectedSkill->id()).c_str(), description, 4096,
                                            ImVec2{ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x, ImGui::CalcTextSize("A").y * 2 + ImGui::GetStyle().FramePadding.y * 2})) {
                m_selectedSkill->setDescription(description);
              }
            }
            ImGui::EndGroup();
            // Skill Type, MP/TP Cost
            ImGui::BeginGroup();
            {
              ImGui::BeginGroup();
              {
                ImGui::Text("Skill Type:");
                ImGui::SetNextItemWidth((ImGui::GetContentRegionAvail().x / 2) - ImGui::GetStyle().FramePadding.x);
                if (ImGui::BeginCombo(std::format("##orpg_database_skills_skilltype_{}", m_selectedSkill->id()).c_str(),
                                      m_selectedSkill->stypeId() == 0 ? "None" : Database::instance()->system.skillType(m_selectedSkill->stypeId()).c_str())) {
                  int index{0};
                  for (auto& dataSource : Database::instance()->system.skillTypes()) {
                    const bool is_selected = m_selectedSkill->stypeId() == index;
                    if (index == 0) {
                      if (ImGui::Selectable("None", is_selected)) {
                        m_selectedSkill->setStypeId(index);
                        if (is_selected)
                          ImGui::SetItemDefaultFocus();
                      }
                    } else {
                      if (ImGui::Selectable(dataSource.c_str(), is_selected)) {
                        m_selectedSkill->setStypeId(index);
                        if (is_selected)
                          ImGui::SetItemDefaultFocus();
                      }
                    }

                    index++;
                  }
                  ImGui::EndCombo();
                }
              }
              ImGui::EndGroup();
              ImGui::SameLine();
              ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetStyle().ItemSpacing.y);
              ImGui::BeginGroup();
              {
                ImGui::Text("MP Cost:");
                ImGui::SetNextItemWidth((ImGui::GetContentRegionAvail().x / 2) - ImGui::GetStyle().FramePadding.x);
                int mpCost = m_selectedSkill->mpCost();
                if (ImGui::InputInt(std::format("##orpg_database_skills_manacost_{}", m_selectedSkill->id()).c_str(), &mpCost, 1, 100)) {
                  m_selectedSkill->setMpCost(std::clamp(mpCost, 0, 9999));
                }
              }
              ImGui::EndGroup();
              ImGui::SameLine();
              ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetStyle().ItemSpacing.y);
              ImGui::BeginGroup();
              {
                ImGui::Text("TP Cost:");
                ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x);
                int tpCost = m_selectedSkill->tpCost();
                if (ImGui::InputInt(std::format("##orpg_database_skills_tcost_{}", m_selectedSkill->id()).c_str(), &tpCost, 1, 100)) {
                  m_selectedSkill->setTpCost(std::clamp(tpCost, 0, 999));
                }
              }
              ImGui::EndGroup();
            }
            ImGui::EndGroup();
            // Scope, Occasion
            ImGui::BeginGroup();
            {
              ImGui::BeginGroup();
              {
                ImGui::Text("Scope:");
                ImGui::SetNextItemWidth((ImGui::GetContentRegionAvail().x / 2) - ImGui::GetStyle().FramePadding.x);
                if (ImGui::BeginCombo(std::format("##orpg_database_skills_scopelist_{}", m_selectedSkill->id()).c_str(), DecodeEnumName(magic_enum::enum_name(m_selectedSkill->scope())).c_str())) {
                  int index{0};
                  for (auto& dir : magic_enum::enum_values<Scope>()) {
                    if (const bool is_selected = m_selectedSkill->scope() == static_cast<Scope>(magic_enum::enum_index(dir).value());
                        ImGui::Selectable(DecodeEnumName(magic_enum::enum_name(dir)).c_str(), is_selected)) {
                      m_selectedSkill->setScope(static_cast<Scope>(magic_enum::enum_index(dir).value()));
                      if (is_selected)
                        ImGui::SetItemDefaultFocus();
                    }
                    index++;
                  }
                  ImGui::EndCombo();
                }
              }
              ImGui::EndGroup();
              ImGui::SameLine();
              ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetStyle().ItemSpacing.y);
              ImGui::BeginGroup();
              {
                ImGui::Text("Occasion:");
                ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x);
                if (ImGui::BeginCombo(std::format("##orpg_database_skills_occasionlist_{}", m_selectedSkill->id()).c_str(),
                                      DecodeEnumName(magic_enum::enum_name(m_selectedSkill->occasion())).c_str())) {
                  int index{0};
                  for (auto& dir : magic_enum::enum_values<Occasion>()) {
                    if (const bool is_selected = m_selectedSkill->occasion() == static_cast<Occasion>(magic_enum::enum_index(dir).value());
                        ImGui::Selectable(DecodeEnumName(magic_enum::enum_name(dir)).c_str(), is_selected)) {
                      m_selectedSkill->setOccasion(dir);
                      if (is_selected)
                        ImGui::SetItemDefaultFocus();
                    }
                    index++;
                  }
                  ImGui::EndCombo();
                }
              }
              ImGui::EndGroup();
            }
            ImGui::EndGroup();
          }
          ImGui::EndGroup();
          // Invocation

          ImGui::SeparatorText("Invocation");
          ImGui::BeginGroup();
          {
            ImGui::BeginGroup();
            {
              ImGui::Text("Speed:");
              ImGui::SetNextItemWidth((ImGui::GetContentRegionAvail().x / 4) - ImGui::GetStyle().FramePadding.x);
              int speed = m_selectedSkill->speed();
              if (ImGui::InputInt(std::format("##orpg_database_skills_speed_{}", m_selectedSkill->id()).c_str(), &speed, 1, 100)) {
                m_selectedSkill->setSpeed(std::clamp(speed, -2000, 2000));
              }
            }
            ImGui::EndGroup();
            ImGui::SameLine();
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetStyle().ItemSpacing.y);
            ImGui::BeginGroup();
            {
              ImGui::Text("Success:");
              ImGui::SetNextItemWidth((ImGui::GetContentRegionAvail().x / 3) - ImGui::GetStyle().FramePadding.x);
              int successRate = m_selectedSkill->successRate();
              if (ImGui::InputInt(std::format("##orpg_database_skills_successRate_{}", m_selectedSkill->id()).c_str(), &successRate, 1, 100)) {
                m_selectedSkill->setSuccessRate(std::clamp(successRate, 0, 100));
              }
            }
            ImGui::EndGroup();
            ImGui::SameLine();
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetStyle().ItemSpacing.y);
            ImGui::BeginGroup();
            {
              ImGui::Text("Repeat:");
              ImGui::SetNextItemWidth((ImGui::GetContentRegionAvail().x / 2) - ImGui::GetStyle().FramePadding.x);
              int repeats = m_selectedSkill->repeats();
              if (ImGui::InputInt("##orpg_database_skills_repeats", &repeats, 1, 100)) {
                m_selectedSkill->setRepeats(std::clamp(repeats, 1, 9));
              }
            }
            ImGui::EndGroup();
            ImGui::SameLine();
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetStyle().ItemSpacing.y);
            ImGui::BeginGroup();
            {
              ImGui::Text("TP Gain:");
              ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x);
              int tpGain = m_selectedSkill->tpGain();
              if (ImGui::InputInt(std::format("##orpg_database_skills_tpGain_{}", m_selectedSkill->id()).c_str(), &tpGain, 1, 100)) {
                m_selectedSkill->setTpGain(std::clamp(tpGain, 0, 100));
              }
            }
            ImGui::EndGroup();
            ImGui::BeginGroup();
            {
              ImGui::Text("Hit Type:");
              ImGui::SetNextItemWidth((ImGui::GetContentRegionAvail().x / 2) - ImGui::GetStyle().FramePadding.x);
              if (ImGui::BeginCombo(std::format("##orpg_database_skills_hitType_{}", m_selectedSkill->id()).c_str(), DecodeEnumName(magic_enum::enum_name(m_selectedSkill->hitType())).c_str())) {
                for (auto& dir : magic_enum::enum_values<HitType>()) {
                  if (const bool is_selected = m_selectedSkill->hitType() == static_cast<HitType>(magic_enum::enum_index(dir).value());
                      ImGui::Selectable(DecodeEnumName(magic_enum::enum_name(dir)).c_str(), is_selected)) {
                    m_selectedSkill->setHitType(dir);
                    if (is_selected)
                      ImGui::SetItemDefaultFocus();
                  }
                }
                ImGui::EndCombo();
              }
            }
            ImGui::EndGroup();
            ImGui::SameLine();
            // Animation
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetStyle().ItemSpacing.y);
            ImGui::BeginGroup();
            {
              ImGui::Text("Animation:");
              // Animation Button
              ImGui::PushID(std::format("##orpg_database_skills_animation_{}", m_selectedSkill->id()).c_str());
              if (ImGui::Button(m_selectedSkill->animationId() == -1  ? "Normal Attack"
                                : m_selectedSkill->animationId() == 0 ? "None"
                                                                      : Database::instance()->animationName(m_selectedSkill->animationId()).c_str(),
                                ImVec2{ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x, 0})) {
                m_animationPicker = ObjectPicker("Animation"sv, Database::instance()->animations.animations(), m_selectedSkill->animationId());
                m_animationPicker->setOpen(true);
              }
              ImGui::PopID();
            }
            ImGui::EndGroup();
          }
          ImGui::EndGroup();
          ImGui::SeparatorText("Message");
          ImGui::BeginGroup();
          {
            char message1[4096];
            strncpy(message1, m_selectedSkill->message1().c_str(), 4096);
            char message2[4096];
            strncpy(message2, m_selectedSkill->message2().c_str(), 4096);

            auto textColor = ImGui::GetStyleColorVec4(ImGuiCol_Text);
            textColor.w = 0.5f;
            ImGui::PushStyleColor(ImGuiCol_Text, textColor);
            ImGui::Text("(User Name)");
            ImGui::PopStyleColor();
            ImGui::SameLine();
            ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - (ImGui::GetContentRegionAvail().x / 4) - ImGui::GetStyle().FramePadding.x);
            if (ImGui::InputText(std::format("##orpg_database_message_message1_{}", m_selectedSkill->id()).c_str(), message1, 4096)) {
              m_selectedSkill->setMessage1(message1);
            }
            ImGui::SameLine();
            ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x);
            if (ImGui::BeginCombo(std::format("##orpg_database_message_templateList_{}", m_selectedSkill->id()).c_str(), m_message_templateList.at(m_message_template).c_str())) {
              for (int index{0}; auto& msg : m_message_templateList) {
                if (msg == m_selectedSkill->message1() && m_message_template != index) {
                  m_message_template = index;
                }
                if (const bool is_selected = m_message_template == index; ImGui::Selectable(m_message_templateList.at(index).c_str(), is_selected)) {
                  m_message_template = index;
                  m_selectedSkill->setMessage1(msg);
                  if (is_selected)
                    ImGui::SetItemDefaultFocus();
                }
                index++;
              }
              ImGui::EndCombo();
            }
            ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x);
            if (ImGui::InputText(std::format("##orpg_database_message_message2_{}", m_selectedSkill->id()).c_str(), message2, 4096)) {
              m_selectedSkill->setMessage2(message2);
            }
          }
          ImGui::EndGroup();
          ImGui::SeparatorText("Required Weapon");
          ImGui::BeginGroup();
          {
            ImGui::BeginGroup();
            {
              ImGui::Text("Weapon Type 1");
              ImGui::SetNextItemWidth((ImGui::GetContentRegionAvail().x / 2) - ImGui::GetStyle().FramePadding.x);
              if (ImGui::BeginCombo(std::format("##orpg_database_reqweapon_1_{}", m_selectedSkill->id()).c_str(),
                                    m_selectedSkill->requiredWtypeId1() == 0 ? "None" : Database::instance()->system.weaponType(m_selectedSkill->requiredWtypeId1()).c_str())) {
                for (int index{0}; auto& _ : Database::instance()->system.weaponTypes()) {
                  const bool is_selected = m_selectedSkill->requiredWtypeId1() == index;
                  if (index == 0) {
                    if (ImGui::Selectable("None", is_selected)) {
                      m_selectedSkill->setRequiredWtypeId1(index);
                      if (is_selected)
                        ImGui::SetItemDefaultFocus();
                    }
                  } else {
                    if (ImGui::Selectable(Database::instance()->system.weaponType(index).c_str(), is_selected)) {
                      m_selectedSkill->setRequiredWtypeId1(index);
                      if (is_selected)
                        ImGui::SetItemDefaultFocus();
                    }
                  }

                  index++;
                }
                ImGui::EndCombo();
              }
            }
            ImGui::EndGroup();
            ImGui::SameLine();
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetStyle().ItemSpacing.y);
            ImGui::BeginGroup();
            {
              ImGui::Text("Weapon Type 2");
              ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x);
              if (ImGui::BeginCombo(std::format("##orpg_database_reqweapon_2_{}", m_selectedSkill->id()).c_str(),
                                    m_selectedSkill->requiredWtypeId2() == 0 ? "None" : Database::instance()->system.weaponType(m_selectedSkill->requiredWtypeId2()).c_str())) {
                int index{0};
                for (auto& _ : Database::instance()->system.weaponTypes()) {
                  const bool is_selected = m_selectedSkill->requiredWtypeId2() == index;
                  if (index == 0) {
                    if (ImGui::Selectable("None", is_selected)) {
                      m_selectedSkill->setRequiredWtypeId2(index);
                      if (is_selected)
                        ImGui::SetItemDefaultFocus();
                    }
                  } else {
                    if (ImGui::Selectable(Database::instance()->system.weaponType(index).c_str(), is_selected)) {
                      m_selectedSkill->setRequiredWtypeId2(index);
                      if (is_selected)
                        ImGui::SetItemDefaultFocus();
                    }
                  }
                  index++;
                }
                ImGui::EndCombo();
              }
            }
            ImGui::EndGroup();
          }
          ImGui::EndGroup();
        }
        ImGui::EndChild();
        ImGui::SameLine();
        ImGui::BeginChild("##orpg_skills_skill_panel_right", {}, ImGuiChildFlags_Borders);
        {
          ImGui::BeginChild("##damage", {}, ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_Borders);
          {
            ImGui::SeparatorText("Damage");
            ImGui::BeginGroup();
            {
              ImGui::BeginGroup();
              {
                ImGui::Text("Type:");
                ImGui::SetNextItemWidth((ImGui::GetContentRegionAvail().x / 2) - ImGui::GetStyle().FramePadding.x);
                if (ImGui::BeginCombo(std::format("##orpg_database_skills_damage_type_{}", m_selectedSkill->id()).c_str(),
                                      DecodeEnumName(magic_enum::enum_name(m_selectedSkill->damage().type())).c_str())) {
                  int index{0};
                  for (auto& dir : magic_enum::enum_values<DamageType>()) {
                    if (const bool isSelected = m_selectedSkill->damage().type() == dir; ImGui::Selectable(DecodeEnumName(magic_enum::enum_name(dir)).c_str(), isSelected)) {
                      m_selectedSkill->damage().setType(dir);
                      if (isSelected)
                        ImGui::SetItemDefaultFocus();
                    }
                    index++;
                  }
                  ImGui::EndCombo();
                }
              }
              ImGui::EndGroup();
              ImGui::SameLine();
              ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetStyle().ItemSpacing.y);
              ImGui::BeginGroup();
              {
                ImGui::TextUnformatted(trNOOP("Element:"));
                ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x);
                if (ImGui::BeginCombo(std::format("##orpg_database_skills_damage_element_{}", m_selectedSkill->id()).c_str(),
                                      m_selectedSkill->damage().elementId() == -1 ? trNOOP("Normal Attack")
                                      : m_selectedSkill->damage().elementId() == 0
                                          ? trNOOP("None")
                                          : (Database::instance()->elementNameOrId(m_selectedSkill->damage().elementId()) + "##" + std::to_string(m_selectedSkill->damage().elementId())).c_str())) {
                  int index{-1};
                  for (auto& elem : Database::instance()->system.elements()) {
                    const bool isSelected = m_selectedSkill->damage().elementId() == index;
                    if (index == -1) {
                      if (ImGui::Selectable(trNOOP("Normal Attack"), isSelected)) {
                        m_selectedSkill->damage().setElementId(index);
                      }
                    } else if (index == 0) {
                      if (ImGui::Selectable(trNOOP("None"), isSelected)) {
                        m_selectedSkill->damage().setElementId(index);
                      }
                    } else {
                      if (ImGui::Selectable(std::format("{}##{}", elem, index).c_str(), isSelected)) {
                        m_selectedSkill->damage().setElementId(index);
                      }
                    }
                    if (isSelected) {
                      ImGui::SetItemDefaultFocus();
                    }
                    index++;
                  }
                  ImGui::EndCombo();
                }
              }
              ImGui::EndGroup();
              char formula[4096];
              strncpy(formula, m_selectedSkill->damage().formula().c_str(), 4096);
              ImGui::LabelOverLineEdit("##orpg_database_skills_formula", trNOOP("Formula"), formula, 4096, ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x, nullptr,
                                       ImGuiInputTextFlags_None);
              ImGui::BeginGroup();
              {
                ImGui::TextUnformatted("Variance:");
                int variance = m_selectedSkill->damage().variance();
                if (ImGui::InputInt(std::format("##orpg_database_skills_variance_{}", m_selectedSkill->id()).c_str(), &variance)) {
                  m_selectedSkill->damage().setVariance(std::clamp(variance, 0, 100));
                }
              }
              ImGui::EndGroup();
              ImGui::SameLine();
              ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ImGui::GetStyle().ItemSpacing.y);
              ImGui::BeginGroup();
              {
                ImGui::Text("Critical Hits:");
                bool critical = m_selectedSkill->damage().critical();
                if (ImGui::Checkbox("##orpg_database_skills_crits", &critical)) {
                  m_selectedSkill->damage().setCritical(critical);
                }
              }
              ImGui::EndGroup();
            }
            ImGui::EndGroup();
          }
          ImGui::EndChild();
          // Begin effects drawing
          ImGui::BeginChild("##effects", {}, ImGuiChildFlags_ResizeY | ImGuiChildFlags_Borders);
          { m_effectsEditor.draw(m_parent); }
          ImGui::EndChild();

          ImGui::BeginChild("##note", {}, ImGuiChildFlags_Borders);
          {
            ImGui::SeparatorText("Note:");
            char note[8192];
            strncpy(note, m_selectedSkill->note().c_str(), IM_ARRAYSIZE(note));
            if (ImGui::InputTextMultiline(std::format("##orpg_database_skills_note_{}", m_selectedSkill->id()).c_str(), note, IM_ARRAYSIZE(note),
                                          ImGui::GetContentRegionAvail() - ImGui::GetStyle().FramePadding)) {
              m_selectedSkill->setNote(note);
            }
          }
          ImGui::EndChild();
        }
        ImGui::EndChild();
      }
    }
    ImGui::EndChild();
  }
  ImGui::EndChild();
  if (m_changeIntDialogOpen) {
    if (ImGui::Begin("Change Max Classes", &m_changeIntDialogOpen,
                     ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_Modal | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking)) {
      ImGui::Text(
          "Specify an amount to resize the skill list to\n"
          "This cannot be undone!");
      ImGui::InputInt("##value_input", &m_editMaxSkills);
      ImGui::SameLine();
      if (ImGui::Button("Accept")) {
        m_changeConfirmDialogOpen = true;
      }
      ImGui::SameLine();
      if (ImGui::Button("Cancel")) {
        m_changeIntDialogOpen = false;
      }
    }
    ImGui::End();

    if (m_changeConfirmDialogOpen) {
      if (ImGui::Begin("Confirm Change", &m_changeConfirmDialogOpen,
                       ImGuiWindowFlags_NoResize | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking)) {
        ImGui::Text("Are you sure?");
        if (ImGui::Button("Yes")) {
          const int tmpId = m_selectedSkill->id();
          m_maxSkills = m_editMaxSkills;
          m_skills.resize(m_maxSkills);
          m_selectedSkill = m_skills.skill(tmpId);
          m_changeIntDialogOpen = false;
          m_changeConfirmDialogOpen = false;
        }
        ImGui::SameLine();
        if (ImGui::Button("Cancel")) {
          m_editMaxSkills = m_maxSkills;
          m_changeIntDialogOpen = false;
          m_changeConfirmDialogOpen = false;
        }
      }
      ImGui::End();
    }
  }
}


code:
#pragma once
#include "Core/CommonUI/EffectsEditor.hpp"
#include "Core/CommonUI/ObjectPicker.hpp"
#include "Core/DatabaseEditor/DBCommonEventsTab.hpp"
#include "Core/DatabaseEditor/IDBEditorTab.hpp"
#include "Core/Graphics/CheckeredCompositeTexture.hpp"

#include "Database/Animation.hpp"
#include "Database/Skills.hpp"

class DBSkillsTab final : public IDBEditorTab {
public:
  DBSkillsTab() = delete;
  explicit DBSkillsTab(Skills& skills, DatabaseEditor* parent);
  void draw() override;

  [[nodiscard]] std::vector<Skill>& skills() { return m_skills.skills(); }
  [[nodiscard]] const std::vector<Skill>& skills() const { return m_skills.skills(); }
  [[nodiscard]] Skill* skill(const int id) { return m_skills.skill(id); }
  [[nodiscard]] const Skill* skill(const int id) const { return m_skills.skill(id); }
  std::vector<int>& getHeaders() override { return m_headers; }
  int getHeader(int index) override { return m_headers.at(index); }
  bool hasHeader() override { return !m_headers.empty(); }
  void setHeaderRange(int start, int end) override {
    m_categoryStart = start;
    m_categoryEnd = end;
  }

  std::string getName(int index) override { return m_skills.skill(index)->name(); }
  int getCount() override { return m_skills.count(); }

private:
  int m_categoryStart;
  int m_categoryEnd;
  std::vector<int> m_headers;
  Skills& m_skills;
  Skill* m_selectedSkill{};
  int m_maxSkills{};
  int m_editMaxSkills{};
  float m_splitterWidth = 300.f;
  bool m_changeIntDialogOpen = false;
  bool m_changeConfirmDialogOpen = false;
  std::vector<Effect> m_effects;
  EffectsEditor m_effectsEditor;
  int m_message_template{0};
  std::vector<std::string> m_message_templateList{"casts %1!", "does %1!", "uses %1"};
  std::optional<ObjectPicker<Animation>> m_animationPicker;
  std::optional<CheckeredCompositeTexture> m_iconButtonTexture;
};


code:
#include "Core/DatabaseEditor/DBStatesTab.hpp"
#include "Core/Application.hpp"
#include "Database/States.hpp"

#include "Core/ImGuiExt/ImGuiUtils.hpp"
#include "imgui.h"
#include "imgui_internal.h"

DBStatesTab::DBStatesTab(States& States, DatabaseEditor* parent)
: IDBEditorTab(parent)
, m_states(States) {
  m_selectedState = m_states.state(1);
  if (m_selectedState) {
    m_traitsEditor.setTraits(&m_selectedState->traits());
  }
}

void DBStatesTab::draw() {
  ImGui::BeginChild("#orpg_states_editor");
  {
    const auto calc = ImGui::CalcTextSize("ABCDEFGHIJKLMNOPQRSTUV");
    ImGui::BeginChild("##orpg_states_editor_states", ImVec2{calc.x + (ImGui::GetStyle().ItemSpacing.x * 2), 0}, ImGuiChildFlags_Border | ImGuiChildFlags_ResizeX, ImGuiWindowFlags_NoScrollbar);
    {
      ImGui::BeginGroup();
      {
        ImGui::SeparatorText("States");
        ImGui::BeginChild("##orpg_states_editor_States_list", ImVec2{0, ImGui::GetContentRegionMax().y - ((calc.y + ImGui::GetStyle().ItemSpacing.y) * 4)});
        {
          ImGui::BeginGroup();
          {
            for (auto& state : m_states.states()) {
              if (state.id() == 0) {
                continue;
              }

              if (ImGui::Selectable(Database::instance()->stateNameAndId(state.id()).c_str(), &state == m_selectedState) || (ImGui::IsItemFocused() && m_selectedState != &state)) {
                m_selectedState = &state;
                m_traitsEditor.setTraits(&m_selectedState->traits());
              }
            }
          }
          ImGui::EndGroup();
        }
        ImGui::EndChild();
        char str[4096];
        snprintf(str, 4096, "Max States %i", m_states.count());
        ImGui::SeparatorText(str);
        if (ImGui::Button("Change Max", ImVec2{ImGui::GetContentRegionMax().x - (8), 0})) {
          m_changeIntDialogOpen = true;
          m_editMaxStates = m_states.count();
        }
      }
      ImGui::EndGroup();
    }
    ImGui::EndChild();
    ImGui::SameLine();
    ImGui::BeginChild("##orpg_states_editor_states_state_properties");
    {
      if (m_selectedState) {
        ImGui::BeginChild("##orpg_states_state_panel_left", ImVec2{ImGui::GetContentRegionMax().x / 2, 0.f});
        {
          ImGui::BeginGroup();
          {
            ImGui::SeparatorText("General Settings");
            // Name
            ImGui::BeginGroup();
            {
              char name[4096];
              strncpy(name, m_selectedState->name().c_str(), 4096);
              if (ImGui::LabelOverLineEdit("##orpg_states_editor_name", "Name:", name, 4096, ImGui::GetContentRegionMax().x / 2, nullptr, ImGuiInputTextFlags_None)) {
                m_selectedState->setName(name);
              }
            }
            ImGui::EndGroup();
            ImGui::SameLine();
            // Image
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 6.f);
            ImGui::BeginGroup();
            {
              ImGui::Text("Icon:");
              ImGui::Text("%s", std::to_string(m_selectedState->iconIndex()).c_str());
            }
            ImGui::EndGroup();
            ImGui::SameLine();
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 20.f);
            ImGui::BeginGroup();
            {
              const auto* iconSheet = m_parent->getIconSheet();
              auto [min, max] = iconSheet->rectForId(m_selectedState->iconIndex());
              ImGui::Image(iconSheet->texture(), ImVec2{static_cast<float>(iconSheet->iconWidth()), static_cast<float>(iconSheet->iconHeight())}, min,
                           max); // Show icon image
              ImGui::EndGroup();
            }
            ImGui::BeginGroup();
            {
              ImGui::Text("Restriction:");
              ImGui::SetNextItemWidth(170);
              if (ImGui::BeginCombo("##database_state_restriction_combo", DecodeEnumName(m_selectedState->restriction()).c_str())) {
                for (const auto& type : magic_enum::enum_values<StateRestriction>()) {
                  if (ImGui::Selectable(DecodeEnumName(type).c_str(), m_selectedState->restriction() == type)) {
                    m_selectedState->setRestriction(type);
                  }
                }
                ImGui::EndCombo();
              }
              ImGui::EndGroup();
            }
            ImGui::SameLine();
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 6.f);
            ImGui::BeginGroup();
            {
              ImGui::Text("Priority:");

              int tempInt = m_selectedState->priority();
              ImGui::SetNextItemWidth(170);
              if (ImGui::InputInt("##database_state_priority", &tempInt)) {
                m_selectedState->setPriority(std::clamp(tempInt, 0, 100));
              }
              ImGui::EndGroup();
            }
            ImGui::BeginGroup();
            {
              ImGui::Text("[SV] Motion:");
              ImGui::SetNextItemWidth(170);
              if (ImGui::BeginCombo("##database_state_sv_motion_combo", DecodeEnumName(m_selectedState->motion()).c_str())) {
                for (const auto& type : magic_enum::enum_values<StateMotion>()) {
                  if (ImGui::Selectable(DecodeEnumName(type).c_str(), m_selectedState->motion() == type)) {
                    m_selectedState->setMotion(type);
                  }
                }
                ImGui::EndCombo();
              }
              ImGui::EndGroup();
            }
            ImGui::SameLine();
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 6.f);
            ImGui::BeginGroup();
            {
              ImGui::Text("[SV] Overlay:");
              ImGui::SetNextItemWidth(170);
              if (ImGui::BeginCombo("##database_state_sv_overlay_combo", DecodeEnumName(m_selectedState->overlay()).c_str())) {
                for (const auto& type : magic_enum::enum_values<StateOverlay>()) {
                  if (ImGui::Selectable(DecodeEnumName(type).c_str(), m_selectedState->overlay() == type)) {
                    m_selectedState->setOverlay(type);
                  }
                }
                ImGui::EndCombo();
              }
              ImGui::EndGroup();
            }
          }
          ImGui::EndGroup();

          ImGui::BeginGroup();
          {
            ImGui::SeparatorText("Removal Conditions");
            ImGui::BeginGroup();
            {
              bool isRemoveAtBattleEnd = m_selectedState->removeAtBattleEnd();
              if (ImGui::Checkbox("##database_states_remove_battleend_checkbox", &isRemoveAtBattleEnd)) {
                m_selectedState->setRemoveAtBattleEnd(isRemoveAtBattleEnd);
              }
              ImGui::SameLine();
              ImGui::Text("Remove at Battle End");
            }
            ImGui::EndGroup();
            ImGui::SameLine();
            ImGui::BeginGroup();
            {
              bool isRemoveByRestriction = m_selectedState->removeByRestriction();
              if (ImGui::Checkbox("##database_states_remove_removerestr_checkbox", &isRemoveByRestriction)) {
                m_selectedState->setRemoveByRestriction(isRemoveByRestriction);
              }
              ImGui::SameLine();
              ImGui::Text("Remove by Restriction");
            }
            ImGui::EndGroup();
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 6.f);
            ImGui::BeginGroup();
            {
              ImGui::Text("Auto-removal Timing:");
              ImGui::EndGroup();
            }
            ImGui::SameLine();
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 6.f);
            ImGui::BeginGroup();
            {
              ImGui::SetNextItemWidth(170);
              if (ImGui::BeginCombo("##database_state_removal_timing_combo", DecodeEnumName(m_selectedState->autoRemovalTiming()).c_str())) {
                for (const auto& type : magic_enum::enum_values<AutoRemovalTiming>()) {
                  if (ImGui::Selectable(DecodeEnumName(type).c_str(), m_selectedState->autoRemovalTiming() == type)) {
                    m_selectedState->setAutoRemovalTiming(type);
                  }
                }
                ImGui::EndCombo();
              }
              ImGui::EndGroup();
            }
            ImGui::BeginGroup();
            {
              ImGui::BeginDisabled(m_selectedState->autoRemovalTiming() == AutoRemovalTiming::None);
              {
                // Duration in turns
                ImGui::Text("Duration in Turns:");
                int tempInt = m_selectedState->minTurns();
                ImGui::SetNextItemWidth(150);
                if (ImGui::InputInt("##database_state_duration_turns_1", &tempInt)) {
                  m_selectedState->setMinTurns(std::clamp(tempInt, 1, 9999));
                }
                ImGui::SameLine();
                ImGui::Text("~");
                ImGui::SameLine();
                int tempInt2 = m_selectedState->maxTurns();
                ImGui::SetNextItemWidth(150);
                if (ImGui::InputInt("##database_state_duration_turns_2", &tempInt2)) {
                  m_selectedState->setMaxTurns(std::clamp(tempInt2, 1, 9999));
                }
              }
              ImGui::EndDisabled();
              ImGui::EndGroup();
            }
            ImGui::BeginGroup();
            {
              // Remove by Damage
              bool isRemoveByDamage = m_selectedState->removeByDamage();
              if (ImGui::Checkbox("##database_states_removedamage_checkbox", &isRemoveByDamage)) {
                m_selectedState->setRemoveByDamage(isRemoveByDamage);
              }
              ImGui::SameLine();
              ImGui::Text("Remove by Damage");
              ImGui::SameLine();
              ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 2.f);
              ImGui::BeginDisabled(!isRemoveByDamage);
              {
                int tempInt = m_selectedState->chanceByDamage();
                ImGui::SetNextItemWidth(150);
                if (ImGui::SliderInt("##database_states_removebydamage_chance", &tempInt, 0, 100, isRemoveByDamage ? " %d%%" : "")) {
                  m_selectedState->setChanceByDamage(tempInt);
                }
                ImGui::EndDisabled();
              }
              ImGui::EndGroup();
            }
            ImGui::BeginGroup();
            {
              // Remove by Walking
              bool isRemoveByWalking = m_selectedState->stepsToRemove();
              if (ImGui::Checkbox("##database_states_removebywalking_checkbox", &isRemoveByWalking)) {
                m_selectedState->setRemoveByWalking(isRemoveByWalking);
              }
              ImGui::SameLine();
              ImGui::Text("Remove by Walking");
              ImGui::SameLine();
              ImGui::BeginDisabled(!isRemoveByWalking);
              {
                int tempInt = m_selectedState->stepsToRemove();
                ImGui::SetNextItemWidth(150);
                if (ImGui::InputInt("##database_states_stepstoremove", &tempInt)) {
                  m_selectedState->setStepsToRemove(std::clamp(tempInt, 1, 9999));
                }
                ImGui::SameLine();
                ImGui::Text("(steps)");
                ImGui::EndDisabled();
              }
              ImGui::EndGroup();
            }
            ImGui::EndGroup();
          }
          ImGui::BeginGroup();
          {
            ImGui::SeparatorText("Messages");
            ImGui::Text("If an actor is inflicted with the state:");
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 6.f);
            auto textColor = ImGui::GetStyleColorVec4(ImGuiCol_Text);
            textColor.w = 0.5f;
            ImGui::TextColored(textColor, "(Target Name)");
            ImGui::SameLine();
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 6.f);
            std::string text1 = m_selectedState->message1();
            if (ImGui::InputText("##orpg_states_messages_input1", &text1)) {
              m_selectedState->setMessage1(text1);
            }
            ImGui::Text("If an enemy is inflicted with the state:");
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 6.f);
            ImGui::TextColored(textColor, "(Target Name)");
            ImGui::SameLine();
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 6.f);
            std::string text2 = m_selectedState->message2();
            if (ImGui::InputText("##orpg_states_messages_input2", &text2)) {
              m_selectedState->setMessage2(text2);
            }
            ImGui::Text("If the state persists:");
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 6.f);
            ImGui::TextColored(textColor, "(Target Name)");
            ImGui::SameLine();
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 6.f);
            std::string text3 = m_selectedState->message3();
            if (ImGui::InputText("##orpg_states_messages_input3", &text3)) {
              m_selectedState->setMessage1(text3);
            }
            ImGui::Text("If the state is removed:");
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 6.f);
            ImGui::TextColored(textColor, "(Target Name)");
            ImGui::SameLine();
            ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 6.f);
            std::string text4 = m_selectedState->message4();
            if (ImGui::InputText("##orpg_states_messages_input4", &text4)) {
              m_selectedState->setMessage1(text4);
            }
            ImGui::EndGroup();
          }
        }
        ImGui::EndChild();
        ImGui::SameLine();
        ImGui::BeginChild("##orpg_states_state_panel_right");
        {
          ImGui::BeginChild("##traits_editor", {0, ImGui::GetContentRegionAvail().y / 2}, ImGuiChildFlags_ResizeY);
          m_traitsEditor.draw(m_parent);
          ImGui::EndChild();
          ImGui::BeginChild("##notes");
          {
            ImGui::SeparatorText("Note:");
            char note[8192];
            strncpy(note, m_selectedState->note().c_str(), IM_ARRAYSIZE(note));
            if (ImGui::InputTextMultiline("##orpg_database_states_note", note, IM_ARRAYSIZE(note), ImVec2{ImGui::GetContentRegionMax().x - 16, ImGui::GetContentRegionAvail().y - 16})) {
              m_selectedState->setNote(note);
            }
          }
          ImGui::EndChild();
        }
        ImGui::EndChild();
      }

      ImGui::EndChild();
    }
    ImGui::EndChild();

    if (m_changeIntDialogOpen) {
      if (ImGui::Begin("Change Max States", &m_changeIntDialogOpen,
                       ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_Modal | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking)) {
        ImGui::Text(
            "Specify an amount to resize the state list to\n"
            "This cannot be undone!");
        ImGui::InputInt("##value_input", &m_editMaxStates);
        ImGui::SameLine();
        if (ImGui::Button("Accept")) {
          m_changeConfirmDialogOpen = true;
        }
        ImGui::SameLine();
        if (ImGui::Button("Cancel")) {
          m_changeIntDialogOpen = false;
        }
      }
      ImGui::End();

      if (m_changeConfirmDialogOpen) {
        if (ImGui::Begin("Confirm Change", &m_changeConfirmDialogOpen,
                         ImGuiWindowFlags_NoResize | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking)) {
          ImGui::Text("Are you sure?");
          if (ImGui::Button("Yes")) {
            const int tmpId = m_selectedState->id();
            m_states.resize(m_editMaxStates);
            m_selectedState = m_states.state(tmpId);
            m_changeIntDialogOpen = false;
            m_changeConfirmDialogOpen = false;
          }
          ImGui::SameLine();
          if (ImGui::Button("Cancel")) {
            m_editMaxStates = m_states.count();
            m_changeIntDialogOpen = false;
            m_changeConfirmDialogOpen = false;
          }
        }
        ImGui::End();
      }
    }
  }
}


code:
#pragma once
#include "Core/CommonUI/TraitsEditor.hpp"
#include "Core/DatabaseEditor/IDBEditorTab.hpp"
#include "DBCommonEventsTab.hpp"
#include "Database/States.hpp"

struct DBStatesTab : IDBEditorTab {
  DBStatesTab() = delete;
  explicit DBStatesTab(States& system, DatabaseEditor* parent);
  void draw() override;

  [[nodiscard]] State* state(int id) { return m_states.state(id); }
  [[nodiscard]] const State* state(int id) const { return m_states.state(id); }

  [[nodiscard]] States& states() { return m_states; }
  [[nodiscard]] const States& states() const { return m_states; }
  std::vector<int>& getHeaders() override { return m_headers; }
  int getHeader(int index) override { return m_headers.at(index); }
  bool hasHeader() override { return !m_headers.empty(); }
  void setHeaderRange(int start, int end) override {
    m_categoryStart = start;
    m_categoryEnd = end;
  }

  std::string getName(int index) override { return m_states.state(index)->name(); }
  int getCount() override { return m_states.count(); }

private:
  int m_categoryStart;
  int m_categoryEnd;
  std::vector<int> m_headers;
  States& m_states;
  State* m_selectedState{};
  int m_editMaxStates;
  float m_splitterWidth = 300.f;
  bool m_changeIntDialogOpen = false;
  bool m_changeConfirmDialogOpen = false;
  TraitsEditor m_traitsEditor;
};