LumixEngine/src/editor/log_ui.cpp

229 lines
5.1 KiB
C++
Raw Normal View History

2015-09-14 18:03:45 +02:00
#include "log_ui.h"
2019-06-21 17:14:06 +02:00
#include "engine/delegate_list.h"
2016-05-10 08:24:31 +02:00
#include "engine/log.h"
2018-12-09 11:36:31 +01:00
#include "engine/os.h"
2015-12-23 19:52:09 +01:00
#include "imgui/imgui.h"
2015-09-14 18:03:45 +02:00
2017-05-23 19:57:11 +02:00
namespace Lumix
{
LogUI::LogUI(IAllocator& allocator)
2015-09-14 18:03:45 +02:00
: m_allocator(allocator)
, m_messages(allocator)
, m_level_filter(2 | 4)
2015-09-14 18:03:45 +02:00
, m_notifications(allocator)
, m_last_uid(1)
2017-08-20 00:16:42 +02:00
, m_is_open(false)
2016-06-15 15:28:07 +02:00
, m_are_notifications_hovered(false)
, m_move_notifications_to_front(false)
2015-09-14 18:03:45 +02:00
{
2019-06-21 17:14:06 +02:00
getLogCallback().bind<LogUI, &LogUI::onLog>(this);
2015-09-14 18:03:45 +02:00
2019-06-21 17:14:06 +02:00
for (int i = 0; i < (int)LogLevel::COUNT; ++i)
2015-09-14 18:03:45 +02:00
{
m_new_message_count[i] = 0;
}
}
LogUI::~LogUI()
{
2019-06-21 17:14:06 +02:00
getLogCallback().unbind<LogUI, &LogUI::onLog>(this);
2015-09-14 18:03:45 +02:00
}
int LogUI::addNotification(const char* text)
{
m_move_notifications_to_front = true;
if (!m_notifications.empty() && m_notifications.back().message == text) return -1;
auto& notif = m_notifications.emplace(m_allocator);
notif.time = 10.0f;
notif.message = text;
notif.uid = ++m_last_uid;
return notif.uid;
}
2019-06-21 17:14:06 +02:00
void LogUI::push(LogLevel level, const char* message)
2015-09-14 18:03:45 +02:00
{
MT::CriticalSectionLock lock(m_guard);
2019-06-21 17:14:06 +02:00
++m_new_message_count[(int)level];
2017-10-30 12:10:59 +01:00
Message& msg = m_messages.emplace(m_allocator);
msg.text = message;
2019-06-21 17:14:06 +02:00
msg.level = level;
2015-09-14 18:03:45 +02:00
2019-06-21 17:14:06 +02:00
if (level == LogLevel::ERROR) addNotification(message);
2015-09-14 18:03:45 +02:00
}
2019-06-21 17:14:06 +02:00
void LogUI::onLog(LogLevel level, const char* system, const char* message)
2015-09-14 18:03:45 +02:00
{
2019-06-21 17:14:06 +02:00
push(level, message);
2015-09-14 18:03:45 +02:00
}
2019-07-25 18:50:31 +02:00
void fillLabel(Span<char> output, const char* label, int count)
2015-09-14 18:03:45 +02:00
{
2019-07-25 18:50:31 +02:00
copyString(output, label);
catString(output, "(");
int len = stringLength(output.begin());
2019-07-25 18:50:31 +02:00
toCString(count, output.fromLeft(len));
catString(output, ")###");
catString(output, label);
2015-09-14 18:03:45 +02:00
}
void LogUI::showNotifications()
{
m_are_notifications_hovered = false;
2015-09-14 18:03:45 +02:00
if (m_notifications.empty()) return;
ImGui::SetNextWindowPos(ImVec2(10, 30));
2018-12-15 23:00:09 +01:00
ImGui::SetNextWindowSizeConstraints(ImVec2(-FLT_MAX, 0), ImVec2(FLT_MAX, 200));
2019-04-20 10:50:33 +02:00
ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoSavedSettings;
2018-01-23 18:38:27 +01:00
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1);
2018-10-06 12:44:38 +02:00
if (!ImGui::Begin("Notifications", nullptr, flags)) goto end;
m_are_notifications_hovered = ImGui::IsWindowHovered();
if (ImGui::Button("Close")) m_notifications.clear();
if (m_move_notifications_to_front) ImGui::BringToFront();
m_move_notifications_to_front = false;
2015-09-14 18:03:45 +02:00
for (int i = 0; i < m_notifications.size(); ++i)
{
if (i > 0) ImGui::Separator();
ImGui::Text("%s", m_notifications[i].message.c_str());
2015-09-14 18:03:45 +02:00
}
2018-01-23 18:38:27 +01:00
2019-04-20 10:50:33 +02:00
end:
ImGui::End();
ImGui::PopStyleVar();
2015-09-14 18:03:45 +02:00
}
void LogUI::update(float time_delta)
{
if (m_are_notifications_hovered) return;
2015-09-14 18:03:45 +02:00
for (int i = 0; i < m_notifications.size(); ++i)
{
m_notifications[i].time -= time_delta;
if (m_notifications[i].time < 0)
{
m_notifications.erase(i);
--i;
}
}
}
2016-02-12 22:31:05 +01:00
int LogUI::getUnreadErrorCount() const
{
2019-06-21 17:14:06 +02:00
return m_new_message_count[(int)LogLevel::ERROR];
2016-02-12 22:31:05 +01:00
}
2015-10-03 01:14:38 +02:00
void LogUI::onGUI()
2015-09-14 18:03:45 +02:00
{
MT::CriticalSectionLock lock(m_guard);
2015-09-25 23:03:10 +02:00
showNotifications();
2018-10-06 12:44:38 +02:00
if (!m_is_open) return;
if (ImGui::Begin("Log", &m_is_open))
2015-09-14 18:03:45 +02:00
{
2019-04-20 10:50:33 +02:00
const char* labels[] = {"Info", "Warning", "Error"};
2019-09-10 18:12:05 +02:00
for (u32 i = 0; i < lengthOf(labels); ++i)
2015-09-14 18:03:45 +02:00
{
char label[40];
2019-07-25 18:50:31 +02:00
fillLabel(Span(label), labels[i], m_new_message_count[i]);
2019-04-20 10:50:33 +02:00
if (i > 0) ImGui::SameLine();
2017-10-30 12:10:59 +01:00
bool b = m_level_filter & (1 << i);
if (ImGui::Checkbox(label, &b))
2015-09-14 18:03:45 +02:00
{
2019-04-20 10:50:33 +02:00
if (b)
m_level_filter |= 1 << i;
else
m_level_filter &= ~(1 << i);
2015-09-14 18:03:45 +02:00
m_new_message_count[i] = 0;
}
}
2019-04-20 10:50:33 +02:00
2017-10-30 12:52:58 +01:00
ImGui::SameLine();
2015-09-14 18:03:45 +02:00
char filter[128] = "";
2017-10-19 17:48:53 +02:00
ImGui::LabellessInputText("Filter", filter, sizeof(filter));
2016-06-05 20:25:09 +02:00
int len = 0;
2017-10-30 10:48:54 +01:00
if (ImGui::BeginChild("log_messages", ImVec2(0, 0), true))
2016-06-05 20:25:09 +02:00
{
2017-10-30 12:10:59 +01:00
for (int i = 0; i < m_messages.size(); ++i)
2016-06-05 20:25:09 +02:00
{
2019-06-21 17:14:06 +02:00
if ((m_level_filter & (1 << (int)m_messages[i].level)) == 0) continue;
2017-10-30 12:10:59 +01:00
const char* msg = m_messages[i].text.c_str();
2016-06-05 20:25:09 +02:00
if (filter[0] == '\0' || strstr(msg, filter) != nullptr)
{
2017-10-30 10:48:54 +01:00
ImGui::TextUnformatted(msg);
2016-06-05 20:25:09 +02:00
}
}
2017-10-30 10:48:54 +01:00
}
ImGui::EndChild();
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(1)) ImGui::OpenPopup("Context");
if (ImGui::BeginPopup("Context"))
{
if (ImGui::Selectable("Copy"))
2016-06-05 20:25:09 +02:00
{
2017-10-30 12:10:59 +01:00
for (int i = 0; i < m_messages.size(); ++i)
2016-06-05 20:25:09 +02:00
{
2017-10-30 12:10:59 +01:00
const char* msg = m_messages[i].text.c_str();
if (filter[0] == '\0' || strstr(msg, filter) != nullptr)
{
2017-10-30 10:48:54 +01:00
len += stringLength(msg);
}
2016-06-05 20:25:09 +02:00
}
2017-10-30 10:48:54 +01:00
if (len > 0)
2015-10-15 20:53:13 +02:00
{
2017-10-30 10:48:54 +01:00
char* mem = (char*)m_allocator.allocate(len);
mem[0] = '\0';
2019-07-25 18:50:31 +02:00
const Span<char> memspan(mem, len);
2017-10-30 12:10:59 +01:00
for (int i = 0; i < m_messages.size(); ++i)
2017-10-30 10:48:54 +01:00
{
2017-10-30 12:10:59 +01:00
const char* msg = m_messages[i].text.c_str();
2017-10-30 10:48:54 +01:00
if (filter[0] == '\0' || strstr(msg, filter) != nullptr)
{
2019-07-25 18:50:31 +02:00
catString(memspan, msg);
catString(memspan, "\n");
2017-10-30 10:48:54 +01:00
}
}
2018-12-09 11:36:31 +01:00
OS::copyToClipboard(mem);
2017-10-30 10:48:54 +01:00
m_allocator.deallocate(mem);
2015-10-15 20:53:13 +02:00
}
2015-09-14 18:03:45 +02:00
}
2017-10-30 12:10:59 +01:00
if (ImGui::Selectable("Clear"))
{
Array<Message> filtered_messages(m_allocator);
for (int i = 0; i < m_messages.size(); ++i)
{
2019-06-21 17:14:06 +02:00
if ((m_level_filter & (1 << (int)m_messages[i].level)) == 0) {
2019-04-20 10:50:33 +02:00
filtered_messages.emplace(m_messages[i]);
}
else {
2019-06-21 17:14:06 +02:00
m_new_message_count[(int)m_messages[i].level] = 0;
2019-04-20 10:50:33 +02:00
}
2017-10-30 12:10:59 +01:00
}
m_messages.swap(filtered_messages);
}
2017-10-30 10:48:54 +01:00
ImGui::EndPopup();
2015-09-14 18:03:45 +02:00
}
}
2018-10-06 12:44:38 +02:00
ImGui::End();
2015-09-14 18:03:45 +02:00
}
2017-05-23 19:57:11 +02:00
} // namespace Lumix