code:
#include "Core/TroopsEventEditor/TroopsEVPage.hpp"

#include "Core/ImGuiExt/ImGuiUtils.hpp"
#include "Core/MainWindow.hpp"
#include "Database/Globals.hpp"

#include <format>
#include <string>

#include "imgui.h"

TroopsEVPage::TroopsEVPage(TroopsEVEditor* parent, Troop::Page* page, const int troopId)
: m_parent(parent)
, m_page(page)
, m_pageNameBuf{}
, m_page_id(0) {
  m_commandEditor.setCommands(&m_page->list());
  m_commandEditor.setTroopId(troopId);
}

std::tuple<bool, bool> TroopsEVPage::draw(bool canDelete, int index) {

  // return std::make_tuple(false, true);
  bool open = true;
  m_page_id = index + 1;

  if (m_actorPicker) {
    if (const auto [closed, confirmed] = m_actorPicker->draw(); closed) {
      if (closed) {
        if (confirmed) {
          m_page->conditions().setActorId(m_actorPicker->selection());
        }
        m_actorPicker.reset();
      }
    }
  }
  if (picker) {
    auto [closed, confirmed] = picker->draw();
    if (closed) {
      if (confirmed) {
        m_page->conditions().setSwitchId(m_actorPicker->selection());
      }
      picker.reset();
    }
  }

  ImGui::BeginChild("##orpg_troops_panel_bottom_commands", ImVec2{0, ImGui::GetContentRegionMax().y - 250});
  {
    m_commandEditor.draw();
    ImGui::EndChild();
  }
  ImGui::BeginGroup();
  {
    bool tmp = m_page->conditions().turnValid();
    if (ImGui::Checkbox("Turn", &tmp)) {
      m_page->conditions().setTurnValid(tmp);
    }
    ImGui::EndGroup();
  }
  ImGui::BeginGroup();
  {
    bool tmp = m_page->conditions().turnEnding();
    if (ImGui::Checkbox("Turn End", &tmp)) {
      m_page->conditions().setTurnEnding(tmp);
    }
    tmp = m_page->conditions().enemyValid();
    if (ImGui::Checkbox("Enemy HP", &tmp)) {
      m_page->conditions().setEnemyValid(tmp);
    }
    tmp = m_page->conditions().actorValid();
    if (ImGui::Checkbox("Actor HP", &tmp)) {
      m_page->conditions().setActorValid(tmp);
    }
    tmp = m_page->conditions().switchValid();
    if (ImGui::Checkbox("Switch", &tmp)) {
      m_page->conditions().setSwitchValid(tmp);
    }
    ImGui::EndGroup();
  }
  ImGui::SameLine();
  // ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 100);
  ImGui::BeginGroup();
  {
    ImGui::BeginDisabled(!m_page->conditions().turnEnding());
    {
      ImGui::SetNextItemWidth(150);
      int tmp = m_page->conditions().turnA();
      if (ImGui::InputInt("##orpg_troops_panel_conditions_turnA", &tmp)) {
        m_page->conditions().setTurnA(std::clamp(tmp, 0, 9999));
      }
      ImGui::SameLine();
      ImGui::SetNextItemWidth(150);
      tmp = m_page->conditions().turnB();
      if (ImGui::InputInt("##orpg_troops_panel_conditions_turnB", &tmp)) {
        m_page->conditions().setTurnB(std::clamp(tmp, 0, 9999));
      }
    }
    ImGui::EndDisabled();
    // Enemy condition
    ImGui::BeginDisabled(!m_page->conditions().enemyValid());
    {
      ImGui::SetNextItemWidth(150);
      std::string title = "#" + std::to_string(m_page->conditions().enemyIndex() + 1) + " " +
                          std::string((m_parent->event()->members().size() <= m_page->conditions().enemyIndex())
                                          ? "?"
                                          : Database::instance()->enemyNameOrId(m_parent->event()->members().at(m_page->conditions().enemyIndex()).enemyId()));

      if (ImGui::BeginCombo("##orpg_troops_panel_conditions_enemylist", m_page->conditions().enemyValid() ? title.c_str() : "")) {
        for (int i = 0; i < 8; ++i) {
          std::string text =
              "#" + std::to_string(i + 1) + " " + std::string((m_parent->event()->members().size() <= i) ? "?" : Database::instance()->enemyNameOrId(m_parent->event()->members().at(i).enemyId()));
          if (ImGui::Selectable(text.c_str(), i == m_page->conditions().enemyIndex())) {
            m_page->conditions().setEnemyIndex(i);
          }
        }
        ImGui::EndCombo();
      }
      ImGui::SameLine();
      ImGui::SetNextItemWidth(150);
      int tmp = m_page->conditions().enemyHp();
      if (ImGui::SliderInt("##orpg_troops_panel_conditions_enemyhp", &tmp, 0, 100, m_page->conditions().enemyValid() ? " %d%%" : "")) {
        m_page->conditions().setEnemyHp(tmp);
      }
      ImGui::SameLine();
      ImGui::Text("or below");
    }
    ImGui::EndDisabled();
    // Actor condition
    ImGui::BeginDisabled(!m_page->conditions().actorValid());
    {
      if (ImGui::Button(std::string(std::format("{}##orpg_troops_conditions_actor_page_{}",
                                                m_page->conditions().actorValid() ? Database::instance()->actorNameOrId(m_page->conditions().actorId()) : "", m_page_id))
                            .c_str(),
                        {(150), 0})) {
        m_actorPicker = ObjectPicker<Actor>("Actor"sv, Database::instance()->actors.actorList(), m_page->conditions().actorId());
        m_actorPicker->setOpen(true);
      }
      ImGui::SameLine();
      ImGui::SetNextItemWidth(150);
      int tmp = m_page->conditions().actorHp();
      if (ImGui::SliderInt("##orpg_troops_panel_conditions_actorhp", &tmp, 0, 100, m_page->conditions().actorId() > 0 ? " %d%%" : "")) {
        m_page->conditions().setActorHp(tmp);
      }
      ImGui::SameLine();
      ImGui::Text("or below");
    }
    ImGui::EndDisabled();
    // Switch condition
    ImGui::BeginDisabled(!m_page->conditions().switchValid());
    {
      if (ImGui::Button(std::string(std::format("{}##orpg_troops_conditions_switch_page_{}",
                                                m_page->conditions().switchValid() ? Database::instance()->switchNameOrId(m_page->conditions().switchId()) : "", m_page_id))
                            .c_str(),
                        ImVec2{(150), 0})) {
        picker.emplace("Switches", Database::instance()->system.switches(), m_page->conditions().switchId());
        picker->setOpen(true);
      }
    }
    ImGui::EndDisabled();
  }
  ImGui::EndGroup();

  ImGui::BeginGroup();
  {
    const auto preview = DecodeEnumName(static_cast<Span>(m_page->span()));
    ImGui::SetNextItemWidth(300);
    if (ImGui::BeginCombo("##trait_editor_party_ability_combo", preview.c_str())) {
      for (const auto& type : magic_enum::enum_values<Span>()) {
        if (ImGui::Selectable(DecodeEnumName(type).c_str(), m_page->span() == static_cast<int>(type))) {
          m_page->setSpan(static_cast<int>(type));
        }
      }
      ImGui::EndCombo();
    }
    ImGui::EndGroup();
  }

  open ^= 1;
  return std::make_tuple(open, true);
}

void TroopsEVPage::clearPage() {
  m_page->list().clear();
  m_page->list().emplace_back(new EventDummy())->setIndent(0);
}


code:
#pragma once
#include "Core/CommonUI/CharacterPicker.hpp"
#include "Core/CommonUI/EventCommandEditor.hpp"
#include "Core/CommonUI/ObjectPicker.hpp"
#include "Core/CommonUI/VariableSwitchPicker.hpp"
#include "Core/Graphics/CharacterSheet.hpp"

struct TroopsEVEditor;
struct TroopsEVPage {
  TroopsEVPage(TroopsEVEditor* parent, Troop::Page* page, int m_troopId);

  /* Returns true when closed, closing is the equivelant of deleting */
  std::tuple<bool, bool> draw(bool canDelete, int index);

  void clearPage();

  void setPage(Troop::Page* page, int pageIndex) {
    m_page = page;
    m_commandEditor.setCommands(&m_page->list());
  }
  void setParent(TroopsEVEditor* parent) { m_parent = parent; }

private:
  TroopsEVEditor* m_parent;
  Troop::Page* m_page;
  char m_pageNameBuf[4096];
  EventCommandEditor m_commandEditor;
  std::optional<ObjectPicker<Actor>> m_actorPicker;
  std::optional<VariableSwitchPicker> picker;
  int m_page_id;
};

repo_name: Antidote/openrpgeditor

license: mit


code:
//
// Created by antidote on 6/11/24.
//

#include "UndoStack.hpp"


code:
#pragma once

#include "Core/IUndoCommand.hpp"

#include <memory>
#include <stack>

struct UndoStack {

  void push(const std::weak_ptr<IUndoCommand>& undo) { m_undoStack.push(undo.lock()); }

  std::shared_ptr<IUndoCommand> pop() {
    auto ret = m_undoStack.top();
    m_undoStack.pop();
    return ret;
  }

  bool hasCommands() const { return !m_undoStack.empty(); }

  void clear() {
    while (!m_undoStack.empty()) {
      m_undoStack.pop();
    }
  }

  std::shared_ptr<IUndoCommand> top() { return m_undoStack.top(); }

private:
  std::stack<std::shared_ptr<IUndoCommand>> m_undoStack;
};


code:
#pragma once

#include <algorithm>
#include <cctype>
#include <locale>
#include <random>

namespace Utils {
// trim from start (in place)
inline void ltrim(std::string& s) {
  s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); }));
}

// trim from end (in place)
inline void rtrim(std::string& s) {
  s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end());
}

// trim from both ends (in place)
inline void trim(std::string& s) {
  rtrim(s);
  ltrim(s);
}

// trim from start (copying)
inline std::string ltrim_copy(std::string s) {
  ltrim(s);
  return s;
}

// trim from end (copying)
inline std::string rtrim_copy(std::string s) {
  rtrim(s);
  return s;
}

// trim from both ends (copying)
inline std::string trim_copy(std::string s) {
  trim(s);
  return s;
}

} // namespace Utils


code:
#include "Window.hpp"

#include "Core/Debug/Instrumentor.hpp"
#include "Core/Log.hpp"
#include <SDL3/SDL.h>
#include <SDL3/SDL_render.h>

namespace App {

Window::Window(const Settings& settings) {
  /* Create the window as hidden so we can secretly configure it */
  m_window = SDL_CreateWindow(settings.title.c_str(), settings.width, settings.height, SDL_WINDOW_TRANSPARENT | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_RESIZABLE);

  /* Set the size from the settings scaled to the user's DPI settings */
  setWindowPosition(settings.x, settings.y);

  if (settings.maximized) {
    setMaximized();
  }

  m_title = settings.title;

  m_renderer = SDL_CreateRenderer(m_window, "direct3d,d3d11,metal,vulkan,opengl");

  if (m_renderer == nullptr) {
    APP_ERROR("Error creating SDL_Renderer!");
    return;
  }
  // We want all textures to wrap
#ifdef SDL_SetRenderTextureAddressMode
  SDL_SetRenderTextureAddressMode(m_renderer, SDL_TEXTURE_ADDRESS_WRAP, SDL_TEXTURE_ADDRESS_WRAP);
#endif

  APP_INFO("Current SDL_Renderer: {}", SDL_GetRendererName(m_renderer));
}

Window::~Window() {

  SDL_DestroyRenderer(m_renderer);
  SDL_DestroyWindow(m_window);
}

SDL_Window* Window::getNativeWindow() const { return m_window; }

SDL_Renderer* Window::getNativeRenderer() const { return m_renderer; }

int Window::getWidth() const {
  int width{};
  SDL_GetWindowSize(m_window, &width, nullptr);
  return width;
}

int Window::getHeight() const {
  int height{};
  SDL_GetWindowSize(m_window, nullptr, &height);
  return height;
}

void Window::setMaximized() { SDL_MaximizeWindow(m_window); }

void Window::setWindowSize(int width, int height) { SDL_SetWindowSize(m_window, width, height); }

int Window::getPositionX() const {
  int x{};
  SDL_GetWindowPosition(m_window, &x, nullptr);
  return x;
}
int Window::getPositionY() const {
  int y{};
  SDL_GetWindowPosition(m_window, nullptr, &y);
  return y;
}

void Window::setWindowPosition(int x, int y) { SDL_SetWindowPosition(m_window, x, y); }

} // namespace App


code:
#pragma once

#include <SDL3/SDL.h>

#include <string>

namespace App {

class Window {
public:
  struct Settings {
    std::string title;
    int width{1920};
    int height{1080};
    int x{-1};
    int y{-1};
    int maximized{false};
  };

  explicit Window(const Settings& settings);
  ~Window();

  Window(const Window&) = delete;
  Window(Window&&) = delete;
  Window& operator=(Window other) = delete;
  Window& operator=(Window&& other) = delete;

  [[nodiscard]] SDL_Window* getNativeWindow() const;
  [[nodiscard]] SDL_Renderer* getNativeRenderer() const;

  void setTitle(std::string_view title) {
    m_title = title;
    SDL_SetWindowTitle(m_window, title.data());
  }

  std::string_view getTitle() const { return m_title; }

  [[nodiscard]] int getWidth() const;
  [[nodiscard]] int getHeight() const;
  void setWindowSize(int width, int height);
  [[nodiscard]] int getPositionX() const;
  [[nodiscard]] int getPositionY() const;
  void setWindowPosition(int x, int y);
  void setMaximized();

private:
  SDL_Window* m_window{nullptr};
  SDL_Renderer* m_renderer{nullptr};
  // Cache this so we don't have to query into SDL every time
  std::string m_title;
};

} // namespace App