2021SC@SDUSC
开源游戏引擎Overload代码分析九:OvEditor——Panels
前言
这是Overload引擎相关的第十一篇文章,同时也是OvEditor分析的第六篇。Overload引擎的Github主页在这里。
本篇文章将会介绍OvEditor的Panels文件夹中剩余的一些文件,具体应该会涉及Console,GameView,HardwareInfo和ProjectSettings。
一、Console
1.console.h
class Console : public OvUI::Panels::PanelWindow
{
public:
Console
(
const std::string& p_title,
bool p_opened,
const OvUI::Settings::PanelWindowSettings& p_windowSettings
);
void OnLogIntercepted(const OvDebug::LogData& p_logData);
void ClearOnPlay();
void Clear();
void FilterLogs();
bool IsAllowedByFilter(OvDebug::ELogLevel p_logLevel);
private:
void SetShowDefaultLogs(bool p_value);
void SetShowInfoLogs(bool p_value);
void SetShowWarningLogs(bool p_value);
void SetShowErrorLogs(bool p_value);
private:
OvUI::Widgets::Layout::Group* m_logGroup;
std::unordered_map<OvUI::Widgets::Texts::TextColored*, OvDebug::ELogLevel> m_logTextWidgets;
bool m_clearOnPlay = true;
bool m_showDefaultLog = true;
bool m_showInfoLog = true;
bool m_showWarningLog = true;
bool m_showErrorLog = true;
};
定义了console类,是引擎内部的控制台,具体函数在实现在下面讲述。
2.console.cpp
接下来按代码顺序说明。
std::pair<OvUI::Types::Color, std::string> GetWidgetSettingsFromLogData(const OvDebug::LogData& p_logData)
{
OvUI::Types::Color logColor;
std::string logHeader;
std::string logDateFormated = "[";
bool isSecondPart = false;
std::for_each(p_logData.date.begin(), p_logData.date.end(), [&logDateFormated, &isSecondPart](char c)
{
if (isSecondPart)
logDateFormated.push_back(c == '-' ? ':' : c);
if (c == '_')
isSecondPart = true;
});
logDateFormated += "] ";
switch (p_logData.logLevel)
{
default:
case OvDebug::ELogLevel::LOG_DEFAULT: return { { 1.f, 1.f, 1.f, 1.f }, logDateFormated };
case OvDebug::ELogLevel::LOG_INFO: return { { 0.f, 1.f, 1.f, 1.f }, logDateFormated };
case OvDebug::ELogLevel::LOG_WARNING: return { { 1.f, 1.f, 0.f, 1.f }, logDateFormated };
case OvDebug::ELogLevel::LOG_ERROR: return { { 1.f, 0.f, 0.f, 1.f }, logDateFormated };
}
}
此函数用于从日志文件中获取设定数据,因为日志文件名有指定格式,所以首先获得用于标记的第二部分,之后根据日志的级别返回标记向量和标记的信息。
OvEditor::Panels::Console::Console
(
const std::string& p_title,
bool p_opened,
const OvUI::Settings::PanelWindowSettings& p_windowSettings
) :
PanelWindow(p_title, p_opened, p_windowSettings)
{
allowHorizontalScrollbar = true;
auto& clearButton = CreateWidget<Buttons::Button>("Clear");
clearButton.size = { 50.f, 0.f };
clearButton.idleBackgroundColor = { 0.5f, 0.f, 0.f };
clearButton.ClickedEvent += std::bind(&Console::Clear, this);
clearButton.lineBreak = false;
auto& clearOnPlay = CreateWidget<Selection::CheckBox>(m_clearOnPlay, "Auto clear on play");
CreateWidget<Layout::Spacing>(5).lineBreak = false;
auto& enableDefault = CreateWidget<Selection::CheckBox>(true, "Default");
auto& enableInfo = CreateWidget<Selection::CheckBox>(true, "Info");
auto& enableWarning = CreateWidget<Selection::CheckBox>(true, "Warning");
auto& enableError = CreateWidget<Selection::CheckBox>(true, "Error");
clearOnPlay.lineBreak = false;
enableDefault.lineBreak = false;
enableInfo.lineBreak = false;
enableWarning.lineBreak = false;
enableError.lineBreak = true;
clearOnPlay.ValueChangedEvent += [this](bool p_value) { m_clearOnPlay = p_value; };
enableDefault.ValueChangedEvent += std::bind(&Console::SetShowDefaultLogs, this, std::placeholders::_1);
enableInfo.ValueChangedEvent += std::bind(&Console::SetShowInfoLogs, this, std::placeholders::_1);
enableWarning.ValueChangedEvent += std::bind(&Console::SetShowWarningLogs, this, std::placeholders::_1);
enableError.ValueChangedEvent += std::bind(&Console::SetShowErrorLogs, this, std::placeholders::_1);
CreateWidget<Visual::Separator>();
m_logGroup = &CreateWidget<Layout::Group>();
m_logGroup->ReverseDrawOrder();
EDITOR_EVENT(PlayEvent) += std::bind(&Console::ClearOnPlay, this);
OvDebug::Logger::LogEvent += std::bind(&Console::OnLogIntercepted, this, std::placeholders::_1);
}
这是构造函数。首先会初始化一个面板窗口,之后初始化一些特有的内容,允许有竖直的滑条,设置了一个用于清空内容的按钮,之后初始化了许多checkbox的小部件,绑定了各自对应的功能,同时有一些日志的群组设计。
接下来是一些用在构造函数中的函数,主要是一些部件的功能:
void OvEditor::Panels::Console::OnLogIntercepted(const OvDebug::LogData & p_logData)
{
auto[logColor, logDate] = GetWidgetSettingsFromLogData(p_logData);
auto& consoleItem1 = m_logGroup->CreateWidget<Texts::TextColored>(logDate + "\t" + p_logData.message, logColor);
consoleItem1.enabled = IsAllowedByFilter(p_logData.logLevel);
m_logTextWidgets[&consoleItem1] = p_logData.logLevel;
}
void OvEditor::Panels::Console::ClearOnPlay()
{
if (m_clearOnPlay)
Clear();
}
void OvEditor::Panels::Console::Clear()
{
m_logTextWidgets.clear();
m_logGroup->RemoveAllWidgets();
}
void OvEditor::Panels::Console::FilterLogs()
{
for (const auto&[widget, logLevel] : m_logTextWidgets)
widget->enabled = IsAllowedByFilter(logLevel);
}
bool OvEditor::Panels::Console::IsAllowedByFilter(OvDebug::ELogLevel p_logLevel)
{
switch (p_logLevel)
{
case OvDebug::ELogLevel::LOG_DEFAULT: return m_showDefaultLog;
case OvDebug::ELogLevel::LOG_INFO: return m_showInfoLog;
case OvDebug::ELogLevel::LOG_WARNING: return m_showWarningLog;
case OvDebug::ELogLevel::LOG_ERROR: return m_showErrorLog;
}
return false;
}
void OvEditor::Panels::Console::SetShowDefaultLogs(bool p_value)
{
m_showDefaultLog = p_value;
FilterLogs();
}
void OvEditor::Panels::Console::SetShowInfoLogs(bool p_value)
{
m_showInfoLog = p_value;
FilterLogs();
}
void OvEditor::Panels::Console::SetShowWarningLogs(bool p_value)
{
m_showWarningLog = p_value;
FilterLogs();
}
void OvEditor::Panels::Console::SetShowErrorLogs(bool p_value)
{
m_showErrorLog = p_value;
FilterLogs();
}
OnLogIntercepted首先通过GetWidgetSettingsFromLogData获得日志的信息,初始化一个以存储信息为初值的部件,用IsAllowedByFilter确定是否要启用此部件。
IsAllowedByFilter根据传入的值返回是否使用日志,如果传入的值不符合期望值,就返回false。
ClearOnPlay会在m_clearOnPlay为真时调用clear()函数,也即清屏设定被开启时就清屏。
Clear会调用次级的清空函数,把m_logTextWidgets和m_logGroup都清空。
FilterLogs会用IsAllowedByFilter过滤得到是否启用部件。
SetShowDefaultLogs,SetShowInfoLogs,SetShowWarningLogs和SetShowErrorLogs都是用于给属性赋值,而在赋值后都会调用FilterLogs来更新是否启用的属性。
二、待续
GameView,HardwareInfo和ProjectSettings这三个部分之后再继续讲。
总结
Console相关的都是与控制台有关的函数,没有特殊的地方。
|