Unify panel search behavior and polish console UI
This commit is contained in:
@@ -11,7 +11,6 @@
|
||||
#include <imgui.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
@@ -40,6 +39,8 @@ struct ConsoleSeverityCounts {
|
||||
size_t errorCount = 0;
|
||||
};
|
||||
|
||||
bool CanOpenSourceLocation(const LogEntry& entry);
|
||||
|
||||
struct ConsoleRowData {
|
||||
uint64_t serial = 0;
|
||||
LogEntry entry = {};
|
||||
@@ -143,13 +144,6 @@ bool IsErrorLevel(LogLevel level) {
|
||||
return level == LogLevel::Error || level == LogLevel::Fatal;
|
||||
}
|
||||
|
||||
std::string ToLowerCopy(std::string text) {
|
||||
std::transform(text.begin(), text.end(), text.begin(), [](unsigned char ch) {
|
||||
return static_cast<char>(std::tolower(ch));
|
||||
});
|
||||
return text;
|
||||
}
|
||||
|
||||
std::string BuildEntryKey(const LogEntry& entry) {
|
||||
std::string key;
|
||||
key.reserve(128 + entry.message.Length() + entry.file.Length() + entry.function.Length());
|
||||
@@ -173,15 +167,11 @@ std::string BuildSearchHaystack(const LogEntry& entry) {
|
||||
haystack += entry.file.CStr();
|
||||
haystack.push_back('\n');
|
||||
haystack += entry.function.CStr();
|
||||
return ToLowerCopy(std::move(haystack));
|
||||
return haystack;
|
||||
}
|
||||
|
||||
bool MatchesSearch(const LogEntry& entry, const std::string& searchText) {
|
||||
if (searchText.empty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return BuildSearchHaystack(entry).find(searchText) != std::string::npos;
|
||||
bool MatchesSearch(const LogEntry& entry, const XCEngine::Editor::UI::SearchQuery& searchQuery) {
|
||||
return searchQuery.Matches(BuildSearchHaystack(entry));
|
||||
}
|
||||
|
||||
void CountSeverity(ConsoleSeverityCounts& counts, LogLevel level) {
|
||||
@@ -210,7 +200,7 @@ uint64_t FindLatestSerial(const std::vector<EditorConsoleRecord>& records) {
|
||||
std::vector<ConsoleRowData> BuildVisibleRows(
|
||||
const std::vector<EditorConsoleRecord>& records,
|
||||
const XCEngine::Editor::UI::ConsoleFilterState& filterState,
|
||||
const std::string& searchText,
|
||||
const XCEngine::Editor::UI::SearchQuery& searchQuery,
|
||||
ConsoleSeverityCounts& counts) {
|
||||
std::vector<ConsoleRowData> rows;
|
||||
rows.reserve(records.size());
|
||||
@@ -218,7 +208,7 @@ std::vector<ConsoleRowData> BuildVisibleRows(
|
||||
if (!filterState.Collapse()) {
|
||||
for (const EditorConsoleRecord& record : records) {
|
||||
CountSeverity(counts, record.entry.level);
|
||||
if (!filterState.Allows(record.entry.level) || !MatchesSearch(record.entry, searchText)) {
|
||||
if (!filterState.Allows(record.entry.level) || !MatchesSearch(record.entry, searchQuery)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -236,7 +226,7 @@ std::vector<ConsoleRowData> BuildVisibleRows(
|
||||
rowIndicesByKey.reserve(records.size());
|
||||
for (const EditorConsoleRecord& record : records) {
|
||||
CountSeverity(counts, record.entry.level);
|
||||
if (!filterState.Allows(record.entry.level) || !MatchesSearch(record.entry, searchText)) {
|
||||
if (!filterState.Allows(record.entry.level) || !MatchesSearch(record.entry, searchQuery)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -358,15 +348,6 @@ void DrawSeverityIcon(
|
||||
}
|
||||
}
|
||||
|
||||
void DrawSearchGlyph(ImDrawList* drawList, const ImVec2& center, ImU32 color) {
|
||||
drawList->AddCircle(center, 4.0f, color, 16, 1.5f);
|
||||
drawList->AddLine(
|
||||
ImVec2(center.x + 3.0f, center.y + 3.0f),
|
||||
ImVec2(center.x + 7.0f, center.y + 7.0f),
|
||||
color,
|
||||
1.5f);
|
||||
}
|
||||
|
||||
bool DrawToolbarDropdownButton(
|
||||
const char* id,
|
||||
const char* label,
|
||||
@@ -525,6 +506,37 @@ bool DrawToolbarButton(
|
||||
return pressed;
|
||||
}
|
||||
|
||||
bool DrawCompactCheckedMenuItem(const char* label, bool checked) {
|
||||
if (!label) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool clicked = ImGui::Selectable(label, false, ImGuiSelectableFlags_SpanAvailWidth);
|
||||
if (checked) {
|
||||
const ImRect rect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax());
|
||||
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
||||
const ImU32 color = ImGui::GetColorU32(ImGuiCol_CheckMark);
|
||||
const float height = rect.Max.y - rect.Min.y;
|
||||
const float checkWidth = height * 0.28f;
|
||||
const float checkHeight = height * 0.18f;
|
||||
const float x = rect.Max.x - 12.0f;
|
||||
const float y = rect.Min.y + height * 0.52f;
|
||||
|
||||
drawList->AddLine(
|
||||
ImVec2(x - checkWidth, y - checkHeight * 0.15f),
|
||||
ImVec2(x - checkWidth * 0.42f, y + checkHeight),
|
||||
color,
|
||||
1.4f);
|
||||
drawList->AddLine(
|
||||
ImVec2(x - checkWidth * 0.42f, y + checkHeight),
|
||||
ImVec2(x + checkWidth, y - checkHeight),
|
||||
color,
|
||||
1.4f);
|
||||
}
|
||||
|
||||
return clicked;
|
||||
}
|
||||
|
||||
void DrawToolbarArrowDropdownButton(
|
||||
const char* id,
|
||||
float width,
|
||||
@@ -566,28 +578,6 @@ void DrawToolbarArrowDropdownButton(
|
||||
}
|
||||
}
|
||||
|
||||
bool DrawConsoleSearchField(const char* id, char* buffer, size_t bufferSize) {
|
||||
const float originalCursorY = ImGui::GetCursorPosY();
|
||||
ImGui::SetCursorPosY((std::max)(0.0f, originalCursorY - 1.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(22.0f, 1.0f));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 2.0f);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, XCEngine::Editor::UI::ToolbarButtonColor(false));
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, XCEngine::Editor::UI::ToolbarButtonHoveredColor(false));
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, XCEngine::Editor::UI::ToolbarButtonActiveColor());
|
||||
ImGui::SetNextItemWidth((std::max)(0.0f, ImGui::GetContentRegionAvail().x));
|
||||
const bool changed = ImGui::InputTextWithHint(id, "Search", buffer, bufferSize);
|
||||
const ImVec2 min = ImGui::GetItemRectMin();
|
||||
const ImVec2 max = ImGui::GetItemRectMax();
|
||||
ImDrawList* drawList = ImGui::GetWindowDrawList();
|
||||
DrawSearchGlyph(
|
||||
drawList,
|
||||
ImVec2(min.x + 11.0f, (min.y + max.y) * 0.5f),
|
||||
ImGui::GetColorU32(XCEngine::Editor::UI::ConsoleSecondaryTextColor()));
|
||||
ImGui::PopStyleColor(3);
|
||||
ImGui::PopStyleVar(2);
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool DrawSeverityToggleButton(
|
||||
const char* id,
|
||||
ConsoleSeverityVisual severity,
|
||||
@@ -595,14 +585,14 @@ bool DrawSeverityToggleButton(
|
||||
bool& active,
|
||||
const char* tooltip) {
|
||||
const float originalCursorY = ImGui::GetCursorPosY();
|
||||
ImGui::SetCursorPosY((std::max)(0.0f, originalCursorY - 1.0f));
|
||||
ImGui::SetCursorPosY((std::max)(0.0f, originalCursorY - kConsoleToolbarRowPaddingY));
|
||||
|
||||
const std::string countText = std::to_string(count);
|
||||
const ImVec2 countSize = ImGui::CalcTextSize(countText.c_str());
|
||||
const ImVec2 padding(6.0f, 3.0f);
|
||||
const float iconRadius = 6.0f;
|
||||
const float gap = 4.0f;
|
||||
const float buttonHeight = kConsoleToolbarButtonHeight + 2.0f;
|
||||
const ImVec2 padding(7.0f, 3.0f);
|
||||
const float iconRadius = 10.0f;
|
||||
const float gap = 5.0f;
|
||||
const float buttonHeight = kConsoleToolbarHeight;
|
||||
const ImVec2 size(
|
||||
(std::max)(
|
||||
kConsoleCounterWidth,
|
||||
@@ -643,9 +633,9 @@ bool DrawSeverityToggleButton(
|
||||
float CalculateSeverityToggleButtonWidth(size_t count) {
|
||||
const std::string countText = std::to_string(count);
|
||||
const ImVec2 countSize = ImGui::CalcTextSize(countText.c_str());
|
||||
const ImVec2 padding(6.0f, 3.0f);
|
||||
const float iconRadius = 6.0f;
|
||||
const float gap = 4.0f;
|
||||
const ImVec2 padding(7.0f, 3.0f);
|
||||
const float iconRadius = 10.0f;
|
||||
const float gap = 5.0f;
|
||||
return (std::max)(
|
||||
kConsoleCounterWidth,
|
||||
padding.x * 2.0f + iconRadius * 2.0f + gap + countSize.x);
|
||||
@@ -991,9 +981,9 @@ void ConsolePanel::Render() {
|
||||
m_lastErrorPauseScanSerial = FindLatestSerial(records);
|
||||
}
|
||||
|
||||
const std::string searchText = ToLowerCopy(std::string(m_searchBuffer));
|
||||
const UI::SearchQuery searchQuery(m_searchBuffer);
|
||||
ConsoleSeverityCounts counts;
|
||||
std::vector<ConsoleRowData> rows = BuildVisibleRows(records, m_filterState, searchText, counts);
|
||||
std::vector<ConsoleRowData> rows = BuildVisibleRows(records, m_filterState, searchQuery, counts);
|
||||
const ConsoleRowData* selectedRow = ResolveSelectedRow(rows, m_selectedSerial, m_selectedEntryKey);
|
||||
if (selectedRow) {
|
||||
m_selectedEntryKey = selectedRow->entryKey;
|
||||
@@ -1058,7 +1048,7 @@ void ConsolePanel::Render() {
|
||||
}
|
||||
ImGui::SameLine(0.0f, 1.0f);
|
||||
DrawToolbarArrowDropdownButton("##ConsoleClearOptions", 16.0f, [&]() {
|
||||
if (ImGui::MenuItem("Clear on Play", nullptr, m_filterState.ClearOnPlay())) {
|
||||
if (DrawCompactCheckedMenuItem("Clear on Play", m_filterState.ClearOnPlay())) {
|
||||
m_filterState.ClearOnPlay() = !m_filterState.ClearOnPlay();
|
||||
}
|
||||
});
|
||||
@@ -1077,7 +1067,7 @@ void ConsolePanel::Render() {
|
||||
ImGui::SetKeyboardFocusHere();
|
||||
m_requestSearchFocus = false;
|
||||
}
|
||||
DrawConsoleSearchField("##ConsoleSearch", m_searchBuffer, sizeof(m_searchBuffer));
|
||||
UI::ToolbarSearchField("##ConsoleSearch", "Search", m_searchBuffer, sizeof(m_searchBuffer));
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
DrawSeverityToggleButton("##ConsoleLogFilter", ConsoleSeverityVisual::Log, counts.logCount, m_filterState.ShowLog(), "Log");
|
||||
@@ -1162,8 +1152,8 @@ void ConsolePanel::Render() {
|
||||
|
||||
if (rows.empty()) {
|
||||
UI::DrawEmptyState(
|
||||
searchText.empty() ? "No messages" : "No search results",
|
||||
searchText.empty() ? nullptr : "No console entries match the current search",
|
||||
searchQuery.Empty() ? "No messages" : "No search results",
|
||||
searchQuery.Empty() ? nullptr : "No console entries match the current search",
|
||||
ImVec2(12.0f, 12.0f));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user