WIP Script Inspector

This commit is contained in:
Kah Wei 2022-09-27 19:17:53 +08:00
parent 4effe016e4
commit a57c4d0d73
5 changed files with 1054 additions and 0 deletions

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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));
}
}
}
}

View File

@ -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);
};
}