WIP Script Inspector
This commit is contained in:
parent
4effe016e4
commit
a57c4d0d73
|
@ -0,0 +1,421 @@
|
|||
/************************************************************************************//*!
|
||||
\file EditorUI.cpp
|
||||
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||
\par email: kahwei.tng\@digipen.edu
|
||||
\date Nov 7, 2021
|
||||
\brief Contains the implementation of the EditorUI class.
|
||||
|
||||
Copyright (C) 2021 DigiPen Institute of Technology.
|
||||
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||
of DigiPen Institute of Technology is prohibited.
|
||||
*//*************************************************************************************/
|
||||
// Precompiled Header
|
||||
#include <pch.h>
|
||||
// Primary Header
|
||||
#include "Editor/EditorUI.h"
|
||||
// External Dependencies
|
||||
#include <imgui.h>
|
||||
// Project Headers
|
||||
#include "Core/Resource/ResourceManager.h"
|
||||
#include "Editor/ImGuiExtensions.h"
|
||||
#include "Editor/Editor.h"
|
||||
|
||||
namespace Pls
|
||||
{
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* ImGui Wrapper Functions - ID Stack */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
void EditorUI::PushID(const std::string& id)
|
||||
{
|
||||
ImGui::PushID(id.c_str());
|
||||
}
|
||||
|
||||
void EditorUI::PushID(int id)
|
||||
{
|
||||
ImGui::PushID(id);
|
||||
}
|
||||
|
||||
void EditorUI::PopID()
|
||||
{
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* ImGui Wrapper Functions - Indent */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
void EditorUI::Indent()
|
||||
{
|
||||
ImGui::Indent();
|
||||
}
|
||||
void EditorUI::Unindent()
|
||||
{
|
||||
ImGui::Unindent();
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* ImGui Wrapper Functions - Organisers */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
bool EditorUI::CollapsingHeader(const std::string& title)
|
||||
{
|
||||
return ImGui::CollapsingHeader(title.c_str());
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* ImGui Wrapper Functions - Pop Ups */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
bool EditorUI::BeginPopup(const std::string& label)
|
||||
{
|
||||
return ImGui::BeginPopup(label.c_str());
|
||||
}
|
||||
void EditorUI::EndPopup()
|
||||
{
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
void EditorUI::OpenPopup(const std::string& label)
|
||||
{
|
||||
ImGui::OpenPopup(label.c_str());
|
||||
}
|
||||
|
||||
bool EditorUI::MenuItem(const std::string& label)
|
||||
{
|
||||
return ImGui::MenuItem(label.c_str());
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* ImGui Wrapper Functions - Widgets */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
void EditorUI::Text(const std::string& title)
|
||||
{
|
||||
ImGui::Text(title.c_str());
|
||||
}
|
||||
bool EditorUI::SmallButton(const std::string& title)
|
||||
{
|
||||
return ImGui::SmallButton(title.c_str());
|
||||
}
|
||||
bool EditorUI::Button(const std::string& title)
|
||||
{
|
||||
return ImGui::Button(title.c_str());
|
||||
}
|
||||
bool EditorUI::InputCheckbox(const std::string& label, bool& value)
|
||||
{
|
||||
return ImGui::Checkbox(label.c_str(), &value);
|
||||
}
|
||||
bool EditorUI::InputInt(const std::string& label, int& value)
|
||||
{
|
||||
return ImGui::InputInt(label.c_str(), &value,
|
||||
1, 10,
|
||||
ImGuiInputTextFlags_EnterReturnsTrue);
|
||||
}
|
||||
bool EditorUI::InputUnsignedInt(const std::string& label, unsigned int& value)
|
||||
{
|
||||
int signedVal = static_cast<int>(value);
|
||||
const bool CHANGED = InputInt(label, signedVal);
|
||||
if (CHANGED)
|
||||
{
|
||||
signedVal = std::clamp(signedVal, 0, std::numeric_limits<int>::max());
|
||||
value = static_cast<unsigned int>(signedVal);
|
||||
}
|
||||
return CHANGED;
|
||||
}
|
||||
bool EditorUI::InputFloat(const std::string& label, float& value)
|
||||
{
|
||||
return ImGui::InputFloat(label.c_str(), &value,
|
||||
0.1f, 1.0f, "%.3f",
|
||||
ImGuiInputTextFlags_EnterReturnsTrue);
|
||||
}
|
||||
bool EditorUI::InputDouble(const std::string& label, double& value)
|
||||
{
|
||||
return ImGui::InputDouble(label.c_str(), &value,
|
||||
0.1, 1.0, "%.3f",
|
||||
ImGuiInputTextFlags_EnterReturnsTrue);
|
||||
}
|
||||
bool EditorUI::InputAngle(const std::string& label, double& value)
|
||||
{
|
||||
return ImGui::InputDouble(label.c_str(), &value,
|
||||
1.0, 45.0, "%.3f",
|
||||
ImGuiInputTextFlags_EnterReturnsTrue);
|
||||
}
|
||||
|
||||
bool EditorUI::InputSlider(const std::string& label, double min, double max, double& value)
|
||||
{
|
||||
float val = static_cast<float>(value);
|
||||
const bool CHANGED = ImGui::SliderFloat(label.c_str(), &val,
|
||||
static_cast<float>(min), static_cast<float>(max), "%.3f",
|
||||
ImGuiInputTextFlags_EnterReturnsTrue);
|
||||
|
||||
if (CHANGED)
|
||||
{
|
||||
value = val;
|
||||
}
|
||||
|
||||
|
||||
return CHANGED;
|
||||
}
|
||||
|
||||
bool EditorUI::InputVec2(const std::string& label, vec2& value)
|
||||
{
|
||||
float vec[2] =
|
||||
{
|
||||
static_cast<float>(value.x),
|
||||
static_cast<float>(value.y)
|
||||
};
|
||||
const bool CHANGED = ImGui::InputFloat2(label.c_str(), vec, "%.3f",
|
||||
ImGuiInputTextFlags_EnterReturnsTrue);
|
||||
if (CHANGED)
|
||||
{
|
||||
value.x = vec[0];
|
||||
value.y = vec[1];
|
||||
}
|
||||
return CHANGED;
|
||||
}
|
||||
bool EditorUI::InputVec3(const std::string& label, vec3& value)
|
||||
{
|
||||
float vec[3] =
|
||||
{
|
||||
static_cast<float>(value.x),
|
||||
static_cast<float>(value.y),
|
||||
static_cast<float>(value.z)
|
||||
};
|
||||
const bool CHANGED = ImGui::InputFloat3(label.c_str(), vec, "%.3f",
|
||||
ImGuiInputTextFlags_EnterReturnsTrue);
|
||||
if (CHANGED)
|
||||
{
|
||||
value.x = vec[0];
|
||||
value.y = vec[1];
|
||||
value.z = vec[2];
|
||||
}
|
||||
return CHANGED;
|
||||
}
|
||||
|
||||
bool EditorUI::InputSliderVec3(const std::string& label, double min, double max, vec3& value)
|
||||
{
|
||||
float vec[3] =
|
||||
{
|
||||
static_cast<float>(value.x),
|
||||
static_cast<float>(value.y),
|
||||
static_cast<float>(value.z)
|
||||
};
|
||||
const bool CHANGED = ImGui::SliderFloat3(label.c_str(), vec,
|
||||
static_cast<float>(min), static_cast<float>(max), "%.3f",
|
||||
ImGuiInputTextFlags_EnterReturnsTrue);
|
||||
if (CHANGED)
|
||||
{
|
||||
value.x = vec[0];
|
||||
value.y = vec[1];
|
||||
value.z = vec[2];
|
||||
}
|
||||
return CHANGED;
|
||||
}
|
||||
|
||||
bool EditorUI::InputColor(const std::string& label, GFX::Color& value)
|
||||
{
|
||||
float color[4] =
|
||||
{
|
||||
value.R,
|
||||
value.G,
|
||||
value.B,
|
||||
value.A
|
||||
};
|
||||
const bool CHANGED = ImGui::ColorEdit4(label.c_str(), color,
|
||||
ImGuiColorEditFlags_AlphaBar |
|
||||
ImGuiColorEditFlags_AlphaPreview |
|
||||
ImGuiColorEditFlags_Float);
|
||||
if (CHANGED)
|
||||
{
|
||||
value.R = color[0];
|
||||
value.G = color[1];
|
||||
value.B = color[2];
|
||||
value.A = std::clamp(color[3], 0.f, 1.f);
|
||||
}
|
||||
return CHANGED;
|
||||
}
|
||||
bool EditorUI::InputTextField(const std::string& label, std::string& value)
|
||||
{
|
||||
std::array<char, TEXT_FIELD_MAX_LENGTH> buffer = { '\0' };
|
||||
strcpy_s(buffer.data(), TEXT_FIELD_MAX_LENGTH, value.c_str());
|
||||
const bool CHANGED = ImGui::InputText(label.c_str(), &buffer[0], TEXT_FIELD_MAX_LENGTH);
|
||||
if (CHANGED)
|
||||
{
|
||||
value = std::string(buffer.data(), buffer.data() + TEXT_FIELD_MAX_LENGTH);
|
||||
}
|
||||
return CHANGED;
|
||||
}
|
||||
|
||||
bool EditorUI::InputEnumCombo(const std::string& label, int& v, const std::vector<std::string>& enumNames)
|
||||
{
|
||||
|
||||
// Clamp input value
|
||||
const std::string& INITIAL_NAME = v >= static_cast<int>(enumNames.size()) ? "Unknown" : enumNames[v];
|
||||
bool b = false;
|
||||
if (ImGui::BeginCombo(label.c_str(), INITIAL_NAME.c_str(), ImGuiComboFlags_None))
|
||||
{
|
||||
for (int i = 0; i < enumNames.size(); ++i)
|
||||
{
|
||||
const bool IS_SELECTED = v == i;
|
||||
if (ImGui::Selectable(enumNames[i].c_str(), IS_SELECTED))
|
||||
{
|
||||
v = i;
|
||||
b = true;
|
||||
}
|
||||
if (IS_SELECTED)
|
||||
{
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
bool EditorUI::InputTextureDropDown(const std::string& label, Resource::Snowflake& v)
|
||||
{
|
||||
static std::vector<std::reference_wrapper<Resource>> resources;
|
||||
|
||||
// Register texture popup
|
||||
bool hasChanges = false;
|
||||
if (ImGui::BeginPopup("Texture Menu"))
|
||||
{
|
||||
if (ImGui::Button("None"))
|
||||
{
|
||||
v = Resource::INVALID_SNOWFLAKE;
|
||||
ImGui::CloseCurrentPopup();
|
||||
hasChanges = true;
|
||||
}
|
||||
for (auto& rscWrapper : resources)
|
||||
{
|
||||
Resource& rsc = rscWrapper.get();
|
||||
|
||||
ImGui::PushID(static_cast<int>(rsc.GetID()));
|
||||
|
||||
const GFX::Texture* TEX = rsc.LoadTexture();
|
||||
if (TEX == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const ImTextureID TEX_ID = reinterpret_cast<void*>(static_cast<intptr_t>(TEX->GetHandle()));
|
||||
const std::string NAME = rsc.GetPath().filename().string();
|
||||
const std::string FP = rsc.GetPath().string();
|
||||
if (ImGui::ImageButtonWithText(TEX_ID, NAME.c_str()))
|
||||
{
|
||||
v = rsc.GetID();
|
||||
ImGui::CloseCurrentPopup();
|
||||
hasChanges = true;
|
||||
}
|
||||
ImGui::TextDisabled(FP.c_str());
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// Get texture ID of resource
|
||||
ImTextureID texID = 0;
|
||||
std::string texName = "None";
|
||||
Resource* rsc = ResourceManager::Find(v);
|
||||
if (rsc)
|
||||
{
|
||||
// File
|
||||
if (rsc->IsType<GFX::Texture>())
|
||||
{
|
||||
GFX::Texture* tex = rsc->LoadTexture();
|
||||
if (tex)
|
||||
{
|
||||
texID = reinterpret_cast<void*>(static_cast<intptr_t>(tex->GetHandle()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO (Clarence): replace with missing texture image
|
||||
texID = Editor::Editor::GetInternalTexture("scene.png");
|
||||
}
|
||||
texName = rsc->GetPath().filename().string();
|
||||
}
|
||||
|
||||
// Show texture selection menu
|
||||
if (ImGui::ImageButtonWithText(texID, texName.c_str(), label.c_str()))
|
||||
{
|
||||
resources = ResourceManager::FindAllOfType<GFX::Texture>();
|
||||
ImGui::OpenPopup("Texture Menu");
|
||||
}
|
||||
|
||||
return hasChanges;
|
||||
}
|
||||
bool EditorUI::InputFontDropDown(const char* label, Resource::Snowflake& v)
|
||||
{
|
||||
static std::vector<std::reference_wrapper<Resource>> resources;
|
||||
|
||||
// Register texture popup
|
||||
bool hasChanges = false;
|
||||
if (ImGui::BeginPopup("Font Menu"))
|
||||
{
|
||||
if (ImGui::Button("None"))
|
||||
{
|
||||
v = Resource::INVALID_SNOWFLAKE;
|
||||
ImGui::CloseCurrentPopup();
|
||||
hasChanges = true;
|
||||
}
|
||||
for (auto& rscWrapper : resources)
|
||||
{
|
||||
Resource& rsc = rscWrapper.get();
|
||||
|
||||
ImGui::PushID(static_cast<int>(rsc.GetID()));
|
||||
|
||||
const GFX::Font* FONT = rsc.LoadFont();
|
||||
if (FONT == nullptr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const std::string NAME = rsc.GetPath().filename().string();
|
||||
const std::string FP = rsc.GetPath().string();
|
||||
if (ImGui::Button(NAME.c_str()))
|
||||
{
|
||||
v = rsc.GetID();
|
||||
ImGui::CloseCurrentPopup();
|
||||
hasChanges = true;
|
||||
}
|
||||
ImGui::TextDisabled(FP.c_str());
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// Get font ID of resource
|
||||
ImTextureID fontID = 0;
|
||||
std::string fontName = "None";
|
||||
Resource* rsc = ResourceManager::Find(v);
|
||||
|
||||
if (rsc)
|
||||
{
|
||||
// File
|
||||
if (rsc)
|
||||
{
|
||||
GFX::Font* font = rsc->LoadFont();
|
||||
if (font)
|
||||
{
|
||||
fontID = reinterpret_cast<void*>(static_cast<intptr_t>(font->GetID()));
|
||||
if (font->CreatedThisFrame())
|
||||
{
|
||||
font->OnCreate() = false;
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO (Clarence): replace with missing texture image
|
||||
fontID = Editor::Editor::GetInternalFont("selawk.tff");
|
||||
}
|
||||
fontName = rsc->GetPath().filename().string();
|
||||
}
|
||||
|
||||
// Show font selection menu
|
||||
if (ImGui::ButtonWithText(fontName.c_str(), label))
|
||||
{
|
||||
resources = ResourceManager::FindAllOfType<GFX::Font>();
|
||||
ImGui::OpenPopup("Font Menu");
|
||||
}
|
||||
|
||||
return hasChanges;
|
||||
}
|
||||
} // namespace PlushieEngine
|
|
@ -0,0 +1,312 @@
|
|||
/************************************************************************************//*!
|
||||
\file EditorUI.h
|
||||
\author Tng Kah Wei, kahwei.tng, 390009620 (50%)
|
||||
\par email: kahwei.tng\@digipen.edu
|
||||
\author Tay Yan Chong Clarence, t.yanchongclarence, 620008720 (50%)
|
||||
\par email: t.yanchongclarence\@digipen.edu
|
||||
\date Nov 7, 2021
|
||||
\brief Defines a class that encapsulates the running of a Plushie Engine
|
||||
application.
|
||||
|
||||
Copyright (C) 2021 DigiPen Institute of Technology.
|
||||
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||
of DigiPen Institute of Technology is prohibited.
|
||||
*//*************************************************************************************/
|
||||
#pragma once
|
||||
// Platform Defines
|
||||
#include "PlushieDefines.h"
|
||||
// Standard Library
|
||||
#include <functional> // std::function
|
||||
#include <string> // std::string
|
||||
|
||||
#include "Core/Resource/Resource.h"
|
||||
#include "Graphics/Color.h"
|
||||
#include "Math/Vector2.h"
|
||||
#include "Math/Vector3.h"
|
||||
|
||||
namespace Pls
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class that contains useful functions for Editor UI using ImGui.
|
||||
/// </summary>
|
||||
class PLS_API EditorUI final
|
||||
{
|
||||
public:
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Constants */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Maximum length of a string supported by InputTextField()
|
||||
/// </summary>
|
||||
static constexpr size_t TEXT_FIELD_MAX_LENGTH = 256;
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* ImGui Wrapper Functions - ID Stack */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Marks the start of a stack of ImGui widgets with the specified id.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::PushID().
|
||||
/// </summary>
|
||||
/// <param name="id">String-based ID.</param>
|
||||
static void PushID(const std::string& id);
|
||||
/// <summary>
|
||||
/// Marks the start of a stack of ImGui widgets with the specified id.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::PushID().
|
||||
/// </summary>
|
||||
/// <param name="id">Integer-based ID.</param>
|
||||
static void PushID(int id);
|
||||
/// <summary>
|
||||
/// Marks the end of a stack of ImGui widgets from the last PushID() call.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::PopID().
|
||||
/// </summary>
|
||||
static void PopID();
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* ImGui Wrapper Functions - Indent */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Indents the widgets rendered after this call.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::Indent().
|
||||
/// </summary>
|
||||
static void Indent();
|
||||
/// <summary>
|
||||
/// Unindents the widgets rendered after this call.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::Unindent().
|
||||
/// </summary>
|
||||
static void Unindent();
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* ImGui Wrapper Functions - Organisers */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Creates a collapsing title header.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::CollapsingHeader().
|
||||
/// </summary>
|
||||
/// <param name="title">Label for the header.</param>
|
||||
/// <returns>True if the header is open, false otherwise.</returns>
|
||||
static bool CollapsingHeader(const std::string& title);
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* ImGui Wrapper Functions - Pop Ups */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Marks the start of a definition of a mini pop up that can show options.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::BeginPopup().
|
||||
/// </summary>
|
||||
/// <param name="label">Label used to identify this widget.</param>
|
||||
/// <returns>Whether or not the pop up is open.</returns>
|
||||
static bool BeginPopup(const std::string& label);
|
||||
/// <summary>
|
||||
/// Marks the end of a definition of a mini pop up that can show options.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::EndPopup().
|
||||
/// </summary>
|
||||
static void EndPopup();
|
||||
/// <summary>
|
||||
/// Opens the popup that was defined with the specified label.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::OpenPopup().
|
||||
/// </summary>
|
||||
static void OpenPopup(const std::string& label);
|
||||
/// <summary>
|
||||
/// Creates a menu item in the list of items for a mini popup.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::MenuItem().
|
||||
/// </summary>
|
||||
/// <param name="label">Label used to identify this widget.</param>
|
||||
/// <returns>Whether or not the menu item was selected.</returns>
|
||||
static bool MenuItem(const std::string& label);
|
||||
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* ImGui Wrapper Functions - Widgets */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Creates a visual text widget.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::Text().
|
||||
/// </summary>
|
||||
/// <param name="title">Text to display.</param>
|
||||
static void Text(const std::string& title);
|
||||
/// <summary>
|
||||
/// Creates a small inline button widget.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::SmallButton().
|
||||
/// </summary>
|
||||
/// <param name="title">Text to display.</param>
|
||||
/// <returns>True if button was pressed.</returns>
|
||||
static bool SmallButton(const std::string& title);
|
||||
/// <summary>
|
||||
/// Creates a inline button widget.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::Button().
|
||||
/// </summary>
|
||||
/// <param name="title">Text to display.</param>
|
||||
/// <returns>True if button was pressed.</returns>
|
||||
static bool Button(const std::string& title);
|
||||
/// <summary>
|
||||
/// Creates a checkbox widget for boolean input.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::Checkbox().
|
||||
/// </summary>
|
||||
/// <param name="label">Label used to identify this widget.</param>
|
||||
/// <param name="value">Reference to the variable to store the result.</param>
|
||||
/// <returns>True if the value was changed.</returns>
|
||||
static bool InputCheckbox(const std::string& label, bool& value);
|
||||
/// <summary>
|
||||
/// Creates a integer field widget for integer input.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::InputInt().
|
||||
/// </summary>
|
||||
/// <param name="label">Label used to identify this widget.</param>
|
||||
/// <param name="value">Reference to the variable to store the result.</param>
|
||||
/// <returns>True if the value was changed.</returns>
|
||||
static bool InputInt(const std::string& label, int& value);
|
||||
/// <summary>
|
||||
/// Creates a integer field widget for unsigned integer input.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::InputInt() with an additional clamping of values.
|
||||
/// <br/>
|
||||
/// Note: As a result, the range of this function limits it to the maximum
|
||||
/// value of a 32-bit signed integer instead of a 32-bit unsigned integer.
|
||||
/// </summary>
|
||||
/// <param name="label">Label used to identify this widget.</param>
|
||||
/// <param name="value">Reference to the variable to store the result.</param>
|
||||
/// <returns>True if the value was changed.</returns>
|
||||
static bool InputUnsignedInt(const std::string& label, unsigned int& value);
|
||||
/// <summary>
|
||||
/// Creates a decimal field widget for single precision float input.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::InputFloat().
|
||||
/// </summary>
|
||||
/// <param name="label">Label used to identify this widget.</param>
|
||||
/// <param name="value">Reference to the variable to store the result.</param>
|
||||
/// <returns>True if the value was changed.</returns>
|
||||
static bool InputFloat(const std::string& label, float& value);
|
||||
/// <summary>
|
||||
/// Creates a decimal field widget for double precision float input.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::InputDouble().
|
||||
/// </summary>
|
||||
/// <param name="label">Label used to identify this widget.</param>
|
||||
/// <param name="value">Reference to the variable to store the result.</param>
|
||||
/// <returns>True if the value was changed.</returns>
|
||||
static bool InputDouble(const std::string& label, double& value);
|
||||
/// <summary>
|
||||
/// Creates a decimal field widget for double input with increments of higher
|
||||
/// steps meant for angle variables.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::InputDouble().
|
||||
/// </summary>
|
||||
/// <param name="label">Label used to identify this widget.</param>
|
||||
/// <param name="value">Reference to the variable to store the result.</param>
|
||||
/// <returns>True if the value was changed.</returns>
|
||||
static bool InputAngle(const std::string& label, double& value);
|
||||
/// <summary>
|
||||
/// Creates a double slider field widget for double input.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::InputSliderFloat().
|
||||
/// </summary>
|
||||
/// <param name="label">Label used to identify this widget.</param>
|
||||
/// <param name="min">Minimum value of the slider.</param>
|
||||
/// <param name="max">Maximum value of the slider.</param>
|
||||
/// <param name="value">Reference to the variable to store the result.</param>
|
||||
/// <returns>True if the value was changed.</returns>
|
||||
static bool InputSlider(const std::string& label, double min, double max, double& value);
|
||||
/// <summary>
|
||||
/// Creates a 2x double field widget for Vector2 input.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::InputFloat2().
|
||||
/// </summary>
|
||||
/// <param name="label">Label used to identify this widget.</param>
|
||||
/// <param name="value">Reference to the variable to store the result.</param>
|
||||
/// <returns>True if the value was changed.</returns>
|
||||
static bool InputVec2(const std::string& label, vec2& value);
|
||||
/// <summary>
|
||||
/// Creates a 3x double field widget for Vector3 input.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::InputFloat3().
|
||||
/// </summary>
|
||||
/// <param name="label">Label used to identify this widget.</param>
|
||||
/// <param name="value">Reference to the variable to store the result.</param>
|
||||
/// <returns>True if the value was changed.</returns>
|
||||
static bool InputVec3(const std::string& label, vec3& value);
|
||||
/// <summary>
|
||||
/// Creates a 3x double slider field widget for Vector3 input.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::InputSliderFloat3().
|
||||
/// </summary>
|
||||
/// <param name="label">Label used to identify this widget.</param>
|
||||
/// <param name="min">Minimum value of the slider.</param>
|
||||
/// <param name="max">Maximum value of the slider.</param>
|
||||
/// <param name="value">Reference to the variable to store the result.</param>
|
||||
/// <returns>True if the value was changed.</returns>
|
||||
static bool InputSliderVec3(const std::string& label, double min, double max, vec3& value);
|
||||
/// <summary>
|
||||
/// Creates a colour field widget for Color input.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::ColorEdit4().
|
||||
/// </summary>
|
||||
/// <param name="label">Label used to identify this widget.</param>
|
||||
/// <param name="value">Reference to the variable to store the result.</param>
|
||||
/// <returns>True if the value was changed.</returns>
|
||||
static bool InputColor(const std::string& label, GFX::Color& value);
|
||||
/// <summary>
|
||||
/// Creates a text field widget for string input.
|
||||
/// <br/>
|
||||
/// Wraps up ImGui::InputText().
|
||||
/// </summary>
|
||||
/// <param name="label">Label used to identify this widget.</param>
|
||||
/// <param name="value">Reference to the variable to store the result.</param>
|
||||
/// <returns>True if the value was changed.</returns>
|
||||
static bool InputTextField(const std::string& label, std::string& value);
|
||||
/// <summary>
|
||||
/// Creates a combo box for enumeration input.
|
||||
/// </summary>
|
||||
/// <typeparam name="Enum">The type of enum to input.</typeparam>
|
||||
/// <param name="label">The name of the input.</param>
|
||||
/// <param name="v">The reference to the value to modify.</param>
|
||||
/// <param name="maxVal">The maximum value of the enum.</param>
|
||||
/// <param name="toStrFn">
|
||||
/// Conversion function from the type of enum
|
||||
/// to C-style string.</param>
|
||||
/// <returns>Whether the value was modified.</returns>
|
||||
template<typename Enum>
|
||||
static bool InputEnumCombo(const std::string& label, Enum& v, int maxVal, std::function<const char*(Enum)> toStrFn);
|
||||
/// <summary>
|
||||
/// Creates a combo box for enumeration input using a specified list of names.
|
||||
/// </summary>
|
||||
/// <param name="label">The name of the input.</param>
|
||||
/// <param name="v">The reference to the value to modify.</param>
|
||||
/// <param name="enumNames">Vector of names for each enumeration value.</param>
|
||||
/// <returns>Whether the value was modified.</returns>
|
||||
static bool InputEnumCombo(const std::string& label, int& v, const std::vector<std::string>& enumNames);
|
||||
/// <summary>
|
||||
/// Creates a drop down widget for texture selection.
|
||||
/// </summary>
|
||||
/// <param name="label">The name of the input.</param>
|
||||
/// <param name="v">The reference to the value to modify.</param>
|
||||
/// <returns>Whether the value was modified.</returns>
|
||||
static bool InputTextureDropDown(const std::string& label, Resource::Snowflake& v);
|
||||
/// <summary>
|
||||
/// Creates a drop down widget for font selection.
|
||||
/// </summary>
|
||||
/// <param name="label">The name of the input.</param>
|
||||
/// <param name="v">The reference to the value to modify.</param>
|
||||
/// <returns>Whether the value was modified.</returns>
|
||||
static bool InputFontDropDown(const char* label, Resource::Snowflake& v);
|
||||
|
||||
|
||||
private:
|
||||
// Prevent instantiation of this static class
|
||||
EditorUI() = delete;
|
||||
};
|
||||
} // namespace PlushieEngine
|
||||
|
||||
#include "EditorUI.hpp"
|
|
@ -0,0 +1,49 @@
|
|||
/************************************************************************************//*!
|
||||
\file EditorUI.hpp
|
||||
\author Tay Yan Chong Clarence, t.yanchongclarence, 620008720
|
||||
\par email: t.yanchongclarence\@digipen.edu
|
||||
\date Nov 8, 2021
|
||||
\brief Contains the implementation of editor inspector template functions.
|
||||
|
||||
Copyright (C) 2021 DigiPen Institute of Technology.
|
||||
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||
of DigiPen Institute of Technology is prohibited.
|
||||
*//*************************************************************************************/
|
||||
// Primary Header
|
||||
#include "EditorUI.h"
|
||||
|
||||
namespace Pls
|
||||
{
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* ImGui Wrapper Functions - Widgets */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
template<typename Enum>
|
||||
inline bool EditorUI::InputEnumCombo(const std::string& label, Enum& v, int maxVal, std::function<const char* (Enum)> toStrFn)
|
||||
{
|
||||
std::vector<Enum> values;
|
||||
for (int i = 0; i <= maxVal; ++i)
|
||||
{
|
||||
values.emplace_back(static_cast<Enum>(i));
|
||||
}
|
||||
bool b = false;
|
||||
if (ImGui::BeginCombo(label.c_str(), toStrFn(v), ImGuiComboFlags_None))
|
||||
{
|
||||
for (int i = 0; i <= maxVal; ++i)
|
||||
{
|
||||
const auto VALUE = values[i];
|
||||
const bool IS_SELECTED = v == VALUE;
|
||||
if (ImGui::Selectable(toStrFn(VALUE), IS_SELECTED))
|
||||
{
|
||||
v = VALUE;
|
||||
b = true;
|
||||
}
|
||||
if (IS_SELECTED)
|
||||
{
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
} // namespace PlushieEngine
|
|
@ -0,0 +1,207 @@
|
|||
/************************************************************************************//*!
|
||||
\file Editor.cxx
|
||||
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||
\par email: kahwei.tng\@digipen.edu
|
||||
\date Sep 27, 2022
|
||||
\brief Contains the definition of the functions for the ScriptStore managed
|
||||
static class.
|
||||
|
||||
Note: This file is written in C++17/CLI.
|
||||
|
||||
Copyright (C) 2022 DigiPen Institute of Technology.
|
||||
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||
of DigiPen Institute of Technology is prohibited.
|
||||
*//*************************************************************************************/
|
||||
// Precompiled Headers
|
||||
#include "SHpch.h"
|
||||
// Primary Header
|
||||
#include "Editor/Editor.hxx"
|
||||
// External Dependencies
|
||||
#include "Editor/SHEditorUI::.h"
|
||||
// Project Headers
|
||||
#include "Components/Component.hxx"
|
||||
#include "Scripts/ScriptStore.hxx"
|
||||
#include "Utility/Convert.hxx"
|
||||
#include "Utility/Debug.hxx"
|
||||
#include "Serialisation/ReflectionUtilities.hxx"
|
||||
|
||||
// Using Directives
|
||||
using namespace System::Collections::Generic;
|
||||
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
/* Macro Functions */
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Macro expansion that is used in renderFieldInInspector() to check the type of a field
|
||||
/// named "field" against the specified type and if it matches, retrieves the value of
|
||||
/// that field from an object named "object" and pass it into the specified SHEditorUI::
|
||||
/// function named "FUNC" by casting it into the NATIVE_TYPE specified.
|
||||
/// <br/>
|
||||
/// This only works for primitive types that have the same types for managed and native.
|
||||
/// </summary>
|
||||
/// <param name="MANAGED_TYPE">The managed type of the object to edit.</param>
|
||||
/// <param name="NATIVE_TYPE">The native type of the object to edit.</param>
|
||||
/// <param name="FUNC">The SHEditorUI:: function to use for editing.</param>
|
||||
#define RENDER_FIELD(MANAGED_TYPE, NATIVE_TYPE, FUNC) \
|
||||
(field->FieldType == MANAGED_TYPE::typeid) \
|
||||
{ \
|
||||
NATIVE_TYPE val = safe_cast<NATIVE_TYPE>(field->GetValue(object)); \
|
||||
if (SHEditorUI::::FUNC(Convert::ToNative(field->Name), val)) \
|
||||
{ \
|
||||
field->SetValue(object, val); \
|
||||
} \
|
||||
} \
|
||||
/// <summary>
|
||||
/// Macro expansion that is used in renderFieldInInspector() to check the type of a field
|
||||
/// named "field" against the specified type and if it matches, retrieves the value of
|
||||
/// that field from an object named "object" and pass it into the specified SHEditorUI::
|
||||
/// function named "FUNC" by casting it into the NATIVE_TYPE specified.
|
||||
/// <br/>
|
||||
/// This only works for types that have an implementation of Convert::ToNative and
|
||||
/// Convert::ToCLI.
|
||||
/// </summary>
|
||||
/// <param name="MANAGED_TYPE">The managed type of the object to edit.</param>
|
||||
/// <param name="NATIVE_TYPE">The native type of the object to edit.</param>
|
||||
/// <param name="FUNC">The SHEditorUI:: function to use for editing.</param>
|
||||
#define RENDER_FIELD_CASTED(MANAGED_TYPE, NATIVE_TYPE, FUNC) \
|
||||
(field->FieldType == MANAGED_TYPE::typeid) \
|
||||
{ \
|
||||
NATIVE_TYPE val = Convert::ToNative(safe_cast<MANAGED_TYPE>(field->GetValue(object))); \
|
||||
if (SHEditorUI::::FUNC(Convert::ToNative(field->Name), val)) \
|
||||
{ \
|
||||
field->SetValue(object, Convert::ToCLI(val)); \
|
||||
} \
|
||||
} \
|
||||
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
/* Function Definitions */
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
namespace SHADE
|
||||
{
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Script Rendering Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
void Editor::RenderScriptsInInspector(Entity entity)
|
||||
{
|
||||
SAFE_NATIVE_CALL_BEGIN
|
||||
// Get scripts
|
||||
IEnumerable<Script^>^ scripts = ScriptStore::GetAllScripts(entity);
|
||||
|
||||
// Skip if no scripts
|
||||
if (scripts != nullptr)
|
||||
{
|
||||
// Display each script if any
|
||||
int index = 0;
|
||||
for each (Script^ script in scripts)
|
||||
{
|
||||
renderScriptInInspector(entity, script, index++);
|
||||
}
|
||||
}
|
||||
|
||||
// Render Add Script
|
||||
//RenderScriptAddButton(entity);
|
||||
SAFE_NATIVE_CALL_END_N("SHADE_Managed.Editor.RenderScriptsInInspector")
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Helper Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
void Editor::renderScriptInInspector(Entity entity, Script^ script, int index)
|
||||
{
|
||||
// Constants
|
||||
const std::string LABEL = Convert::ToNative(script->GetType()->Name);
|
||||
const char* CONTEXT_MENU_ID = "scriptContextMenu";
|
||||
|
||||
// Header
|
||||
SHEditorUI::::PushID(index);
|
||||
if (SHEditorUI::::CollapsingHeader(LABEL))
|
||||
{
|
||||
SHEditorUI::::PushID(LABEL);
|
||||
SHEditorUI::::Indent();
|
||||
{
|
||||
// Define context menu
|
||||
if (SHEditorUI::::BeginPopup(CONTEXT_MENU_ID))
|
||||
{
|
||||
if (SHEditorUI::::MenuItem("Remove Script"))
|
||||
{
|
||||
// Mark script for removal
|
||||
ScriptStore::RemoveScript(entity, script);
|
||||
}
|
||||
SHEditorUI::::EndPopup();
|
||||
}
|
||||
|
||||
// Context menu button
|
||||
if (SHEditorUI::::SmallButton("..."))
|
||||
{
|
||||
SHEditorUI::::OpenPopup(CONTEXT_MENU_ID);
|
||||
}
|
||||
|
||||
// Go through all fields and output them
|
||||
auto fields = ReflectionUtilities::GetInstanceFields(script);
|
||||
int id = 0;
|
||||
for each (auto field in fields)
|
||||
{
|
||||
// Ignore non-serialisable fields
|
||||
if (!ReflectionUtilities::FieldIsSerialisable(field))
|
||||
continue;
|
||||
|
||||
// Render the input field for this field
|
||||
SHEditorUI::::PushID(LABEL + std::to_string(id++));
|
||||
renderFieldInInspector(field, script);
|
||||
SHEditorUI::::PopID();
|
||||
}
|
||||
|
||||
}
|
||||
SHEditorUI::::Unindent();
|
||||
SHEditorUI::::PopID();
|
||||
}
|
||||
SHEditorUI::::PopID();
|
||||
}
|
||||
void Editor::renderFieldInInspector(Reflection::FieldInfo^ field, Object^ object)
|
||||
{
|
||||
if RENDER_FIELD (Int16, int, InputInt)
|
||||
else if RENDER_FIELD (Int32, int, InputInt)
|
||||
else if RENDER_FIELD (Int64, int, InputInt)
|
||||
else if RENDER_FIELD (UInt16, unsigned int, InputUnsignedInt)
|
||||
else if RENDER_FIELD (UInt32, unsigned int, InputUnsignedInt)
|
||||
else if RENDER_FIELD (UInt64, unsigned int, InputUnsignedInt)
|
||||
else if RENDER_FIELD (Byte, int, InputInt)
|
||||
else if RENDER_FIELD (bool, bool, InputCheckbox)
|
||||
else if RENDER_FIELD (float, float, InputFloat)
|
||||
else if RENDER_FIELD (double, double, InputDouble)
|
||||
else if (field->FieldType->IsSubclassOf(Enum::typeid))
|
||||
{
|
||||
// Get all the names of the enums
|
||||
const array<String^>^ ENUM_NAMES = field->FieldType->GetEnumNames();
|
||||
std::vector<std::string> nativeEnumNames;
|
||||
for each (String^ str in ENUM_NAMES)
|
||||
{
|
||||
nativeEnumNames.emplace_back(Convert::ToNative(str));
|
||||
}
|
||||
|
||||
int val = safe_cast<int>(field->GetValue(object));
|
||||
if (SHEditorUI::::InputEnumCombo(Convert::ToNative(field->Name), val, nativeEnumNames))
|
||||
{
|
||||
field->SetValue(object, val);
|
||||
}
|
||||
}
|
||||
else if RENDER_FIELD_CASTED(Vector2, vec2, InputVec2)
|
||||
else if RENDER_FIELD_CASTED(Vector3, vec3, InputVec3)
|
||||
else if (field->FieldType == String::typeid)
|
||||
{
|
||||
// Prevent issues where String^ is null due to being empty
|
||||
String^ stringVal = safe_cast<String^>(field->GetValue(object));
|
||||
if (stringVal == nullptr)
|
||||
{
|
||||
stringVal = "";
|
||||
}
|
||||
|
||||
// Actual Field
|
||||
std::string val = Convert::ToNative(stringVal);
|
||||
if (SHEditorUI::::InputTextField(Convert::ToNative(field->Name), val))
|
||||
{
|
||||
field->SetValue(object, Convert::ToCLI(val));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/************************************************************************************//*!
|
||||
\file Editor.hxx
|
||||
\author Tng Kah Wei, kahwei.tng, 390009620
|
||||
\par email: kahwei.tng\@digipen.edu
|
||||
\date Sep 27, 2022
|
||||
\brief Contains the definition of the managed Editor static class.
|
||||
|
||||
Note: This file is written in C++17/CLI.
|
||||
|
||||
Copyright (C) 2022 DigiPen Institute of Technology.
|
||||
Reproduction or disclosure of this file or its contents without the prior written consent
|
||||
of DigiPen Institute of Technology is prohibited.
|
||||
*//*************************************************************************************/
|
||||
#pragma once
|
||||
|
||||
// Project Includes
|
||||
#include "Engine/Entity.hxx"
|
||||
#include "Scripts/Script.hxx"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class for Editor-related functions
|
||||
/// </summary>
|
||||
public ref class Editor abstract sealed
|
||||
{
|
||||
public:
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Script Rendering Functions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Renders the set of attached Scripts for the specified Entity into the
|
||||
/// inspector.
|
||||
/// <br/>
|
||||
/// This function is meant for consumption from native code in the inspector
|
||||
/// rendering code.
|
||||
/// </summary>
|
||||
/// <param name="entity">The Entity to render the Scripts of.</param>
|
||||
static void RenderScriptsInInspector(Entity entity);
|
||||
|
||||
private:
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/* Helper Functions */
|
||||
/*-----------------------------------------------------------------------------*/
|
||||
/// <summary>
|
||||
/// Renders a single specified Script's inspector.
|
||||
/// </summary>
|
||||
/// <param name="entity">The Entity to render the Scripts of.</param>
|
||||
/// <param name="script">The Script to render the inspector for.</param>
|
||||
/// <param name="index">
|
||||
/// Indices used internally to differentiate each rendered Script
|
||||
/// inspector. This is required to open and close each Script's inspector
|
||||
/// independently from each other.
|
||||
/// </param>
|
||||
static void renderScriptInInspector(Entity entity, Script^ script, int index);
|
||||
/// <summary>
|
||||
/// Renders a field specified into the inspector.
|
||||
/// </summary>
|
||||
/// <param name="field">The field to render.</param>
|
||||
/// <param name="object">
|
||||
/// The object that contains the data of the field to render.
|
||||
/// </param>
|
||||
static void renderFieldInInspector(System::Reflection::FieldInfo^ field, Object^ object);
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue