#pragma once // FROM IMGUI_DEMO.CPP #include "imgui/imgui.h" #include "imgui/imgui_internal.h" struct Log { ImGuiTextBuffer Buf; ImGuiTextFilter Filter; ImVector LineOffsets; // Index to lines offset. We maintain this with AddLog() calls. bool AutoScroll; // Keep scrolling if already at the bottom. Log() { AutoScroll = true; Clear(); } void Clear() { Buf.clear(); LineOffsets.clear(); LineOffsets.push_back(0); } void AddLog(const char* fmt, ...) IM_FMTARGS(2) { int old_size = Buf.size(); va_list args; va_start(args, fmt); Buf.appendfv(fmt, args); va_end(args); for (int new_size = Buf.size(); old_size < new_size; old_size++) if (Buf[old_size] == '\n') LineOffsets.push_back(old_size + 1); } void Draw(const char* title, bool* p_open = NULL) { if (!ImGui::Begin(title, p_open)) { ImGui::End(); return; } // Options menu if (ImGui::BeginPopup("Options")) { ImGui::Checkbox("Auto-scroll", &AutoScroll); ImGui::EndPopup(); } // Main window if (ImGui::Button("Options")) ImGui::OpenPopup("Options"); ImGui::SameLine(); bool clear = ImGui::Button("Clear"); ImGui::SameLine(); bool copy = ImGui::Button("Copy"); ImGui::SameLine(); Filter.Draw("Filter", -100.0f); ImGui::Separator(); ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar); if (clear) Clear(); if (copy) ImGui::LogToClipboard(); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); const char* buf = Buf.begin(); const char* buf_end = Buf.end(); if (Filter.IsActive()) { for (int line_no = 0; line_no < LineOffsets.Size; line_no++) { const char* line_start = buf + LineOffsets[line_no]; const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; if (Filter.PassFilter(line_start, line_end)) ImGui::TextUnformatted(line_start, line_end); } } else { ImGuiListClipper clipper; clipper.Begin(LineOffsets.Size); while (clipper.Step()) { for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++) { const char* line_start = buf + LineOffsets[line_no]; const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end; ImGui::TextUnformatted(line_start, line_end); } } clipper.End(); } ImGui::PopStyleVar(); if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) ImGui::SetScrollHereY(1.0f); ImGui::EndChild(); ImGui::End(); } };