<2021SC@SDUSC>开源游戏引擎Overload代码分析十一:OvEditor——Inspector
作者:互联网
2021SC@SDUSC
开源游戏引擎Overload代码分析十一:OvEditor——Inspector
前言
这是Overload引擎相关的第十三篇文章,同时也是OvEditor分析的第八篇。Overload引擎的Github主页在这里。
本篇文章将会介绍OvEditor的Panels文件夹中与Inspector相关的一些文件,具体应该会涉及Inspector,Hierarchy和HelpWindow。
一、Inspector
1.Inspector.h
class Inspector : public OvUI::Panels::PanelWindow
{
public:
/**
* Constructor
* @param p_title
* @param p_opened
* @param p_windowSettings
*/
Inspector
(
const std::string& p_title,
bool p_opened,
const OvUI::Settings::PanelWindowSettings& p_windowSettings
);
/**
* Destructor
*/
~Inspector();
/**
* Focus the given actor
* @param p_target
*/
void FocusActor(OvCore::ECS::Actor& p_target);
/**
* Unfocus the currently targeted actor
*/
void UnFocus();
/**
* Unfocus the currently targeted actor without removing listeners attached to this actor
*/
void SoftUnFocus();
/**
* Returns the currently selected actor
*/
OvCore::ECS::Actor* GetTargetActor() const;
/**
* Create the actor inspector for the given actor
*/
void CreateActorInspector(OvCore::ECS::Actor& p_target);
/**
* Draw the given component in inspector
*/
void DrawComponent(OvCore::ECS::Components::AComponent& p_component);
/**
* Draw the given behaviour in inspector
*/
void DrawBehaviour(OvCore::ECS::Components::Behaviour& p_behaviour);
/**
* Refresh the inspector
*/
void Refresh();
private:
OvCore::ECS::Actor* m_targetActor = nullptr;
OvUI::Widgets::Layout::Group* m_actorInfo;
OvUI::Widgets::Layout::Group* m_inspectorHeader;
OvUI::Widgets::Selection::ComboBox* m_componentSelectorWidget;
OvUI::Widgets::InputFields::InputText* m_scriptSelectorWidget;
uint64_t m_componentAddedListener = 0;
uint64_t m_componentRemovedListener = 0;
uint64_t m_behaviourAddedListener = 0;
uint64_t m_behaviourRemovedListener = 0;
uint64_t m_destroyedListener = 0;
};
2.Inspector.cpp
OvEditor::Panels::Inspector::Inspector
(
const std::string& p_title,
bool p_opened,
const OvUI::Settings::PanelWindowSettings & p_windowSettings
) : PanelWindow(p_title, p_opened, p_windowSettings)
{
m_inspectorHeader = &CreateWidget<OvUI::Widgets::Layout::Group>();
m_inspectorHeader->enabled = false;
m_actorInfo = &CreateWidget<OvUI::Widgets::Layout::Group>();
auto& headerColumns = m_inspectorHeader->CreateWidget<OvUI::Widgets::Layout::Columns<2>>();
/* Name field */
auto nameGatherer = [this] { return m_targetActor ? m_targetActor->GetName() : "%undef%"; };
auto nameProvider = [this](const std::string& p_newName) { if (m_targetActor) m_targetActor->SetName(p_newName); };
OvCore::Helpers::GUIDrawer::DrawString(headerColumns, "Name", nameGatherer, nameProvider);
/* Tag field */
auto tagGatherer = [this] { return m_targetActor ? m_targetActor->GetTag() : "%undef%"; };
auto tagProvider = [this](const std::string & p_newName) { if (m_targetActor) m_targetActor->SetTag(p_newName); };
OvCore::Helpers::GUIDrawer::DrawString(headerColumns, "Tag", tagGatherer, tagProvider);
/* Active field */
auto activeGatherer = [this] { return m_targetActor ? m_targetActor->IsSelfActive() : false; };
auto activeProvider = [this](bool p_active) { if (m_targetActor) m_targetActor->SetActive(p_active); };
OvCore::Helpers::GUIDrawer::DrawBoolean(headerColumns, "Active", activeGatherer, activeProvider);
/* Component select + button */
{
auto& componentSelectorWidget = m_inspectorHeader->CreateWidget<OvUI::Widgets::Selection::ComboBox>(0);
componentSelectorWidget.lineBreak = false;
componentSelectorWidget.choices.emplace(0, "Model Renderer");
componentSelectorWidget.choices.emplace(1, "Camera");
componentSelectorWidget.choices.emplace(2, "Physical Box");
componentSelectorWidget.choices.emplace(3, "Physical Sphere");
componentSelectorWidget.choices.emplace(4, "Physical Capsule");
componentSelectorWidget.choices.emplace(5, "Point Light");
componentSelectorWidget.choices.emplace(6, "Directional Light");
componentSelectorWidget.choices.emplace(7, "Spot Light");
componentSelectorWidget.choices.emplace(8, "Ambient Box Light");
componentSelectorWidget.choices.emplace(9, "Ambient Sphere Light");
componentSelectorWidget.choices.emplace(10, "Material Renderer");
componentSelectorWidget.choices.emplace(11, "Audio Source");
componentSelectorWidget.choices.emplace(12, "Audio Listener");
auto& addComponentButton = m_inspectorHeader->CreateWidget<OvUI::Widgets::Buttons::Button>("Add Component", OvMaths::FVector2{ 100.f, 0 });
addComponentButton.idleBackgroundColor = OvUI::Types::Color{ 0.7f, 0.5f, 0.f };
addComponentButton.textColor = OvUI::Types::Color::White;
addComponentButton.ClickedEvent += [&componentSelectorWidget, this]
{
switch (componentSelectorWidget.currentChoice)
{
case 0: GetTargetActor()->AddComponent<CModelRenderer>(); GetTargetActor()->AddComponent<CMaterialRenderer>(); break;
case 1: GetTargetActor()->AddComponent<CCamera>(); break;
case 2: GetTargetActor()->AddComponent<CPhysicalBox>(); break;
case 3: GetTargetActor()->AddComponent<CPhysicalSphere>(); break;
case 4: GetTargetActor()->AddComponent<CPhysicalCapsule>(); break;
case 5: GetTargetActor()->AddComponent<CPointLight>(); break;
case 6: GetTargetActor()->AddComponent<CDirectionalLight>(); break;
case 7: GetTargetActor()->AddComponent<CSpotLight>(); break;
case 8: GetTargetActor()->AddComponent<CAmbientBoxLight>(); break;
case 9: GetTargetActor()->AddComponent<CAmbientSphereLight>(); break;
case 10: GetTargetActor()->AddComponent<CMaterialRenderer>(); break;
case 11: GetTargetActor()->AddComponent<CAudioSource>(); break;
case 12: GetTargetActor()->AddComponent<CAudioListener>(); break;
}
componentSelectorWidget.ValueChangedEvent.Invoke(componentSelectorWidget.currentChoice);
};
componentSelectorWidget.ValueChangedEvent += [this, &addComponentButton](int p_value)
{
auto defineButtonsStates = [&addComponentButton](bool p_componentExists)
{
addComponentButton.disabled = p_componentExists;
addComponentButton.idleBackgroundColor = !p_componentExists ? OvUI::Types::Color{ 0.7f, 0.5f, 0.f } : OvUI::Types::Color{ 0.1f, 0.1f, 0.1f };
};
switch (p_value)
{
case 0: defineButtonsStates(GetTargetActor()->GetComponent<CModelRenderer>()); return;
case 1: defineButtonsStates(GetTargetActor()->GetComponent<CCamera>()); return;
case 2: defineButtonsStates(GetTargetActor()->GetComponent<CPhysicalObject>()); return;
case 3: defineButtonsStates(GetTargetActor()->GetComponent<CPhysicalObject>()); return;
case 4: defineButtonsStates(GetTargetActor()->GetComponent<CPhysicalObject>()); return;
case 5: defineButtonsStates(GetTargetActor()->GetComponent<CPointLight>()); return;
case 6: defineButtonsStates(GetTargetActor()->GetComponent<CDirectionalLight>()); return;
case 7: defineButtonsStates(GetTargetActor()->GetComponent<CSpotLight>()); return;
case 8: defineButtonsStates(GetTargetActor()->GetComponent<CAmbientBoxLight>()); return;
case 9: defineButtonsStates(GetTargetActor()->GetComponent<CAmbientSphereLight>()); return;
case 10: defineButtonsStates(GetTargetActor()->GetComponent<CMaterialRenderer>()); return;
case 11: defineButtonsStates(GetTargetActor()->GetComponent<CAudioSource>()); return;
case 12: defineButtonsStates(GetTargetActor()->GetComponent<CAudioListener>()); return;
}
};
m_componentSelectorWidget = &componentSelectorWidget;
}
/* Script selector + button */
{
m_scriptSelectorWidget = &m_inspectorHeader->CreateWidget<OvUI::Widgets::InputFields::InputText>("");
m_scriptSelectorWidget->lineBreak = false;
auto& ddTarget = m_scriptSelectorWidget->AddPlugin<OvUI::Plugins::DDTarget<std::pair<std::string, Layout::Group*>>>("File");
auto& addScriptButton = m_inspectorHeader->CreateWidget<OvUI::Widgets::Buttons::Button>("Add Script", OvMaths::FVector2{ 100.f, 0 });
addScriptButton.idleBackgroundColor = OvUI::Types::Color{ 0.7f, 0.5f, 0.f };
addScriptButton.textColor = OvUI::Types::Color::White;
// Add script button state updater
const auto updateAddScriptButton = [&addScriptButton, this](const std::string& p_script)
{
const std::string realScriptPath = EDITOR_CONTEXT(projectScriptsPath) + p_script + ".lua";
const auto targetActor = GetTargetActor();
const bool isScriptValid = std::filesystem::exists(realScriptPath) && targetActor && !targetActor->GetBehaviour(p_script);
addScriptButton.disabled = !isScriptValid;
addScriptButton.idleBackgroundColor = isScriptValid ? OvUI::Types::Color{ 0.7f, 0.5f, 0.f } : OvUI::Types::Color{ 0.1f, 0.1f, 0.1f };
};
m_scriptSelectorWidget->ContentChangedEvent += updateAddScriptButton;
addScriptButton.ClickedEvent += [updateAddScriptButton, this]
{
const std::string realScriptPath = EDITOR_CONTEXT(projectScriptsPath) + m_scriptSelectorWidget->content + ".lua";
// Ensure that the script is a valid one
if (std::filesystem::exists(realScriptPath))
{
GetTargetActor()->AddBehaviour(m_scriptSelectorWidget->content);
updateAddScriptButton(m_scriptSelectorWidget->content);
}
};
ddTarget.DataReceivedEvent += [updateAddScriptButton, this](std::pair<std::string, Layout::Group*> p_data)
{
m_scriptSelectorWidget->content = EDITOR_EXEC(GetScriptPath(p_data.first));
updateAddScriptButton(m_scriptSelectorWidget->content);
};
}
m_inspectorHeader->CreateWidget<OvUI::Widgets::Visual::Separator>();
m_destroyedListener = OvCore::ECS::Actor::DestroyedEvent += [this](OvCore::ECS::Actor& p_destroyed)
{
if (&p_destroyed == m_targetActor)
UnFocus();
};
}
OvEditor::Panels::Inspector::~Inspector()
{
OvCore::ECS::Actor::DestroyedEvent -= m_destroyedListener;
UnFocus();
}
void OvEditor::Panels::Inspector::FocusActor(OvCore::ECS::Actor& p_target)
{
if (m_targetActor)
UnFocus();
m_actorInfo->RemoveAllWidgets();
m_targetActor = &p_target;
m_componentAddedListener = m_targetActor->ComponentAddedEvent += [this] (auto& useless) { EDITOR_EXEC(DelayAction([this] { Refresh(); })); };
m_behaviourAddedListener = m_targetActor->BehaviourAddedEvent += [this](auto& useless) { EDITOR_EXEC(DelayAction([this] { Refresh(); })); };
m_componentRemovedListener = m_targetActor->ComponentRemovedEvent += [this](auto& useless) { EDITOR_EXEC(DelayAction([this] { Refresh(); })); };
m_behaviourRemovedListener = m_targetActor->BehaviourRemovedEvent += [this](auto& useless) { EDITOR_EXEC(DelayAction([this] { Refresh(); })); };
m_inspectorHeader->enabled = true;
CreateActorInspector(p_target);
// Force component and script selectors to trigger their ChangedEvent to update button states
m_componentSelectorWidget->ValueChangedEvent.Invoke(m_componentSelectorWidget->currentChoice);
m_scriptSelectorWidget->ContentChangedEvent.Invoke(m_scriptSelectorWidget->content);
EDITOR_EVENT(ActorSelectedEvent).Invoke(*m_targetActor);
}
void OvEditor::Panels::Inspector::UnFocus()
{
if (m_targetActor)
{
m_targetActor->ComponentAddedEvent -= m_componentAddedListener;
m_targetActor->ComponentRemovedEvent -= m_componentRemovedListener;
m_targetActor->BehaviourAddedEvent -= m_behaviourAddedListener;
m_targetActor->BehaviourRemovedEvent -= m_behaviourRemovedListener;
}
SoftUnFocus();
}
void OvEditor::Panels::Inspector::SoftUnFocus()
{
if (m_targetActor)
{
EDITOR_EVENT(ActorUnselectedEvent).Invoke(*m_targetActor);
m_inspectorHeader->enabled = false;
m_targetActor = nullptr;
m_actorInfo->RemoveAllWidgets();
}
}
OvCore::ECS::Actor * OvEditor::Panels::Inspector::GetTargetActor() const
{
return m_targetActor;
}
void OvEditor::Panels::Inspector::CreateActorInspector(OvCore::ECS::Actor& p_target)
{
std::map<std::string, OvCore::ECS::Components::AComponent*> components;
for (auto component : p_target.GetComponents())
if (component->GetName() != "Transform")
components[component->GetName()] = component.get();
auto transform = p_target.GetComponent<OvCore::ECS::Components::CTransform>();
if (transform)
DrawComponent(*transform);
for (auto& [name, instance] : components)
DrawComponent(*instance);
auto& behaviours = p_target.GetBehaviours();
for (auto&[name, behaviour] : behaviours)
DrawBehaviour(behaviour);
}
void OvEditor::Panels::Inspector::DrawComponent(OvCore::ECS::Components::AComponent& p_component)
{
if (auto inspectorItem = dynamic_cast<OvCore::API::IInspectorItem*>(&p_component); inspectorItem)
{
auto& header = m_actorInfo->CreateWidget<OvUI::Widgets::Layout::GroupCollapsable>(p_component.GetName());
header.closable = !dynamic_cast<OvCore::ECS::Components::CTransform*>(&p_component);
header.CloseEvent += [this, &header, &p_component]
{
if (p_component.owner.RemoveComponent(p_component))
m_componentSelectorWidget->ValueChangedEvent.Invoke(m_componentSelectorWidget->currentChoice);
};
auto& columns = header.CreateWidget<OvUI::Widgets::Layout::Columns<2>>();
columns.widths[0] = 200;
inspectorItem->OnInspector(columns);
}
}
void OvEditor::Panels::Inspector::DrawBehaviour(OvCore::ECS::Components::Behaviour & p_behaviour)
{
if (auto inspectorItem = dynamic_cast<OvCore::API::IInspectorItem*>(&p_behaviour); inspectorItem)
{
auto& header = m_actorInfo->CreateWidget<OvUI::Widgets::Layout::GroupCollapsable>(p_behaviour.name);
header.closable = true;
header.CloseEvent += [this, &header, &p_behaviour]
{
p_behaviour.owner.RemoveBehaviour(p_behaviour);
};
auto& columns = header.CreateWidget<OvUI::Widgets::Layout::Columns<2>>();
columns.widths[0] = 200;
inspectorItem->OnInspector(columns);
}
}
void OvEditor::Panels::Inspector::Refresh()
{
if (m_targetActor)
{
m_actorInfo->RemoveAllWidgets();
CreateActorInspector(*m_targetActor);
}
}
二、Hierarchy
1.Hierarchy.h
class Hierarchy : public OvUI::Panels::PanelWindow
{
public:
/**
* Constructor
* @param p_title
* @param p_opened
* @param p_windowSettings
*/
Hierarchy
(
const std::string& p_title,
bool p_opened,
const OvUI::Settings::PanelWindowSettings& p_windowSettings
);
/**
* Clear hierarchy nodes
*/
void Clear();
/**
* Unselect every widgets
*/
void UnselectActorsWidgets();
/**
* Select the widget corresponding to the given actor
* @param p_actor
*/
void SelectActorByInstance(OvCore::ECS::Actor& p_actor);
/**
* Select the widget
* @param p_actor
*/
void SelectActorByWidget(OvUI::Widgets::Layout::TreeNode& p_widget);
/**
* Attach the given actor linked widget to its parent widget
* @param p_actor
*/
void AttachActorToParent(OvCore::ECS::Actor& p_actor);
/**
* Detach the given actor linked widget from its parent widget
* @param p_actor
*/
void DetachFromParent(OvCore::ECS::Actor& p_actor);
/**
* Delete the widget referencing the given actor
* @param p_actor
*/
void DeleteActorByInstance(OvCore::ECS::Actor& p_actor);
/**
* Add a widget referencing the given actor
* @param p_actor
*/
void AddActorByInstance(OvCore::ECS::Actor& p_actor);
public:
OvTools::Eventing::Event<OvCore::ECS::Actor&> ActorSelectedEvent;
OvTools::Eventing::Event<OvCore::ECS::Actor&> ActorUnselectedEvent;
private:
OvUI::Widgets::Layout::TreeNode* m_sceneRoot;
std::unordered_map<OvCore::ECS::Actor*, OvUI::Widgets::Layout::TreeNode*> m_widgetActorLink;
};
2.Hierarchy.cpp
class HierarchyContextualMenu : public OvUI::Plugins::ContextualMenu
{
public:
HierarchyContextualMenu(OvCore::ECS::Actor* p_target, OvUI::Widgets::Layout::TreeNode& p_treeNode, bool p_panelMenu = false) :
m_target(p_target),
m_treeNode(p_treeNode)
{
using namespace OvUI::Panels;
using namespace OvUI::Widgets;
using namespace OvUI::Widgets::Menu;
using namespace OvCore::ECS::Components;
if (m_target)
{
auto& focusButton = CreateWidget<OvUI::Widgets::Menu::MenuItem>("Focus");
focusButton.ClickedEvent += [this]
{
EDITOR_EXEC(MoveToTarget(*m_target));
};
auto& duplicateButton = CreateWidget<OvUI::Widgets::Menu::MenuItem>("Duplicate");
duplicateButton.ClickedEvent += [this]
{
EDITOR_EXEC(DelayAction(EDITOR_BIND(DuplicateActor, std::ref(*m_target), nullptr, true), 0));
};
auto& deleteButton = CreateWidget<OvUI::Widgets::Menu::MenuItem>("Delete");
deleteButton.ClickedEvent += [this]
{
EDITOR_EXEC(DestroyActor(std::ref(*m_target)));
};
}
auto& createActor = CreateWidget<OvUI::Widgets::Menu::MenuList>("Create...");
OvEditor::Utils::ActorCreationMenu::GenerateActorCreationMenu(createActor, m_target, std::bind(&OvUI::Widgets::Layout::TreeNode::Open, &m_treeNode));
}
virtual void Execute() override
{
if (m_widgets.size() > 0)
OvUI::Plugins::ContextualMenu::Execute();
}
private:
OvCore::ECS::Actor* m_target;
OvUI::Widgets::Layout::TreeNode& m_treeNode;
};
void ExpandTreeNode(OvUI::Widgets::Layout::TreeNode& p_toExpand, const OvUI::Widgets::Layout::TreeNode* p_root)
{
p_toExpand.Open();
if (&p_toExpand != p_root && p_toExpand.HasParent())
{
ExpandTreeNode(*static_cast<OvUI::Widgets::Layout::TreeNode*>(p_toExpand.GetParent()), p_root);
}
}
std::vector<OvUI::Widgets::Layout::TreeNode*> nodesToCollapse;
std::vector<OvUI::Widgets::Layout::TreeNode*> founds;
void ExpandTreeNodeAndEnable(OvUI::Widgets::Layout::TreeNode& p_toExpand, const OvUI::Widgets::Layout::TreeNode* p_root)
{
if (!p_toExpand.IsOpened())
{
p_toExpand.Open();
nodesToCollapse.push_back(&p_toExpand);
}
p_toExpand.enabled = true;
if (&p_toExpand != p_root && p_toExpand.HasParent())
{
ExpandTreeNodeAndEnable(*static_cast<OvUI::Widgets::Layout::TreeNode*>(p_toExpand.GetParent()), p_root);
}
}
OvEditor::Panels::Hierarchy::Hierarchy
(
const std::string & p_title,
bool p_opened,
const OvUI::Settings::PanelWindowSettings& p_windowSettings
) : PanelWindow(p_title, p_opened, p_windowSettings)
{
auto& searchBar = CreateWidget<OvUI::Widgets::InputFields::InputText>();
searchBar.ContentChangedEvent += [this](const std::string& p_content)
{
founds.clear();
auto content = p_content;
std::transform(content.begin(), content.end(), content.begin(), ::tolower);
for (auto& [actor, item] : m_widgetActorLink)
{
if (!p_content.empty())
{
auto itemName = item->name;
std::transform(itemName.begin(), itemName.end(), itemName.begin(), ::tolower);
if (itemName.find(content) != std::string::npos)
{
founds.push_back(item);
}
item->enabled = false;
}
else
{
item->enabled = true;
}
}
for (auto node : founds)
{
node->enabled = true;
if (node->HasParent())
{
ExpandTreeNodeAndEnable(*static_cast<OvUI::Widgets::Layout::TreeNode*>(node->GetParent()), m_sceneRoot);
}
}
if (p_content.empty())
{
for (auto node : nodesToCollapse)
{
node->Close();
}
nodesToCollapse.clear();
}
};
m_sceneRoot = &CreateWidget<OvUI::Widgets::Layout::TreeNode>("Root", true);
static_cast<OvUI::Widgets::Layout::TreeNode*>(m_sceneRoot)->Open();
m_sceneRoot->AddPlugin<OvUI::Plugins::DDTarget<std::pair<OvCore::ECS::Actor*, OvUI::Widgets::Layout::TreeNode*>>>("Actor").DataReceivedEvent += [this](std::pair<OvCore::ECS::Actor*, OvUI::Widgets::Layout::TreeNode*> p_element)
{
if (p_element.second->HasParent())
p_element.second->GetParent()->UnconsiderWidget(*p_element.second);
m_sceneRoot->ConsiderWidget(*p_element.second);
p_element.first->DetachFromParent();
};
m_sceneRoot->AddPlugin<HierarchyContextualMenu>(nullptr, *m_sceneRoot);
EDITOR_EVENT(ActorUnselectedEvent) += std::bind(&Hierarchy::UnselectActorsWidgets, this);
EDITOR_CONTEXT(sceneManager).SceneUnloadEvent += std::bind(&Hierarchy::Clear, this);
OvCore::ECS::Actor::CreatedEvent += std::bind(&Hierarchy::AddActorByInstance, this, std::placeholders::_1);
OvCore::ECS::Actor::DestroyedEvent += std::bind(&Hierarchy::DeleteActorByInstance, this, std::placeholders::_1);
EDITOR_EVENT(ActorSelectedEvent) += std::bind(&Hierarchy::SelectActorByInstance, this, std::placeholders::_1);
OvCore::ECS::Actor::AttachEvent += std::bind(&Hierarchy::AttachActorToParent, this, std::placeholders::_1);
OvCore::ECS::Actor::DettachEvent += std::bind(&Hierarchy::DetachFromParent, this, std::placeholders::_1);
}
void OvEditor::Panels::Hierarchy::Clear()
{
EDITOR_EXEC(UnselectActor());
m_sceneRoot->RemoveAllWidgets();
m_widgetActorLink.clear();
}
void OvEditor::Panels::Hierarchy::UnselectActorsWidgets()
{
for (auto& widget : m_widgetActorLink)
widget.second->selected = false;
}
void OvEditor::Panels::Hierarchy::SelectActorByInstance(OvCore::ECS::Actor& p_actor)
{
if (auto result = m_widgetActorLink.find(&p_actor); result != m_widgetActorLink.end())
if (result->second)
SelectActorByWidget(*result->second);
}
void OvEditor::Panels::Hierarchy::SelectActorByWidget(OvUI::Widgets::Layout::TreeNode & p_widget)
{
UnselectActorsWidgets();
p_widget.selected = true;
if (p_widget.HasParent())
{
ExpandTreeNode(*static_cast<OvUI::Widgets::Layout::TreeNode*>(p_widget.GetParent()), m_sceneRoot);
}
}
void OvEditor::Panels::Hierarchy::AttachActorToParent(OvCore::ECS::Actor & p_actor)
{
auto actorWidget = m_widgetActorLink.find(&p_actor);
if (actorWidget != m_widgetActorLink.end())
{
auto widget = actorWidget->second;
if (widget->HasParent())
widget->GetParent()->UnconsiderWidget(*widget);
if (p_actor.HasParent())
{
auto parentWidget = m_widgetActorLink.at(p_actor.GetParent());
parentWidget->leaf = false;
parentWidget->ConsiderWidget(*widget);
}
}
}
void OvEditor::Panels::Hierarchy::DetachFromParent(OvCore::ECS::Actor & p_actor)
{
if (auto actorWidget = m_widgetActorLink.find(&p_actor); actorWidget != m_widgetActorLink.end())
{
if (p_actor.HasParent() && p_actor.GetParent()->GetChildren().size() == 1)
{
if (auto parentWidget = m_widgetActorLink.find(p_actor.GetParent()); parentWidget != m_widgetActorLink.end())
{
parentWidget->second->leaf = true;
}
}
auto widget = actorWidget->second;
if (widget->HasParent())
widget->GetParent()->UnconsiderWidget(*widget);
m_sceneRoot->ConsiderWidget(*widget);
}
}
void OvEditor::Panels::Hierarchy::DeleteActorByInstance(OvCore::ECS::Actor& p_actor)
{
if (auto result = m_widgetActorLink.find(&p_actor); result != m_widgetActorLink.end())
{
if (result->second)
{
result->second->Destroy();
}
m_widgetActorLink.erase(result);
}
}
void OvEditor::Panels::Hierarchy::AddActorByInstance(OvCore::ECS::Actor & p_actor)
{
auto& textSelectable = m_sceneRoot->CreateWidget<OvUI::Widgets::Layout::TreeNode>(p_actor.GetName(), true);
textSelectable.leaf = true;
textSelectable.AddPlugin<HierarchyContextualMenu>(&p_actor, textSelectable);
textSelectable.AddPlugin<OvUI::Plugins::DDSource<std::pair<OvCore::ECS::Actor*, OvUI::Widgets::Layout::TreeNode*>>>("Actor", "Attach to...", std::make_pair(&p_actor, &textSelectable));
textSelectable.AddPlugin<OvUI::Plugins::DDTarget<std::pair<OvCore::ECS::Actor*, OvUI::Widgets::Layout::TreeNode*>>>("Actor").DataReceivedEvent += [&p_actor, &textSelectable](std::pair<OvCore::ECS::Actor*, OvUI::Widgets::Layout::TreeNode*> p_element)
{
if (p_element.second->HasParent())
p_element.second->GetParent()->UnconsiderWidget(*p_element.second);
textSelectable.ConsiderWidget(*p_element.second);
p_element.first->SetParent(p_actor);
};
auto& dispatcher = textSelectable.AddPlugin<OvUI::Plugins::DataDispatcher<std::string>>();
OvCore::ECS::Actor* targetPtr = &p_actor;
dispatcher.RegisterGatherer([targetPtr] { return targetPtr->GetName(); });
m_widgetActorLink[targetPtr] = &textSelectable;
textSelectable.ClickedEvent += EDITOR_BIND(SelectActor, std::ref(p_actor));
textSelectable.DoubleClickedEvent += EDITOR_BIND(MoveToTarget, std::ref(p_actor));
}
三、HelpWindow
1.HelpWindow.h
class HelpWindow : public OvUI::Panels::PanelWindow
{
public:
/**
* Constructor
* @param p_title
* @param p_opened
* @param p_windowSettings
*/
HelpWindow
(
const std::string& p_title,
bool p_opened,
const OvUI::Settings::PanelWindowSettings& p_windowSettings
);
};
2.HelpWindow.cpp
OvEditor::Panels::HelpWindow::HelpWindow
(
const std::string& p_title,
bool p_opened,
const OvUI::Settings::PanelWindowSettings& p_windowSettings
) : PanelWindow(p_title, p_opened, p_windowSettings)
{
auto& controls = CreateWidget<OvUI::Widgets::Layout::GroupCollapsable>("Controls");
float columnWidth = 100;
auto& columns = controls.CreateWidget<OvUI::Widgets::Layout::Columns<2>>();
columns.widths[0] = 75;
columns.CreateWidget<OvUI::Widgets::Texts::Text>("Slide:");
columns.CreateWidget<OvUI::Widgets::Texts::Text>("[MB_MIDDLE]");
columns.CreateWidget<OvUI::Widgets::Texts::Text>("Rotate:");
columns.CreateWidget<OvUI::Widgets::Texts::Text>("[MB_RIGHT]");
columns.CreateWidget<OvUI::Widgets::Texts::Text>("Forward:");
columns.CreateWidget<OvUI::Widgets::Texts::Text>("[MB_RIGHT] + [W]");
columns.CreateWidget<OvUI::Widgets::Texts::Text>("Backward:");
columns.CreateWidget<OvUI::Widgets::Texts::Text>("[MB_RIGHT] + [S]");
columns.CreateWidget<OvUI::Widgets::Texts::Text>("Left:");
columns.CreateWidget<OvUI::Widgets::Texts::Text>("[MB_RIGHT] + [A]");
columns.CreateWidget<OvUI::Widgets::Texts::Text>("Right:");
columns.CreateWidget<OvUI::Widgets::Texts::Text>("[MB_RIGHT] + [D]");
columns.CreateWidget<OvUI::Widgets::Texts::Text>("Up:");
columns.CreateWidget<OvUI::Widgets::Texts::Text>("[MB_RIGHT] + [E]");
columns.CreateWidget<OvUI::Widgets::Texts::Text>("Down:");
columns.CreateWidget<OvUI::Widgets::Texts::Text>("[MB_RIGHT] + [Q]");
}
总结
本篇文章讲了Inspector,Hierarchy和HelpWindow三个部分。
标签:std,OvUI,OvEditor,2021SC,OvCore,auto,Overload,actor,CreateWidget 来源: https://blog.csdn.net/chenxiang_200108/article/details/122028658