I have added a simple Log example in imgui_demo.cpp
The way you use it is:
static ExampleAppLog my_log;
[...]
my_log.AddLog("Hello %d world\n", 123);
[...]
my_log.Draw("title");

Complete code below.
The reason I added it is that it is a very common and desirable pattern to have a log window.
Now, this pattern is _SO_ common that I am considering promoting this to a helper, e.g. ImGuiAppLog.
The only reason to do that is most people are too lazy to build their own log window. But if you build own you can make something that's more suited to your application (add multiple channels, add options to find the log emitter object in your game scene, click on filename to open them or folder in Windows Explorer, etc.). So I am on the fence as to whether I should provide this sort of stuff in the main library code. Opinion?
Similar to the memory editor I've posted here https://github.com/ocornut/imgui/issues/270#issuecomment-120568378 , perhaps this is the sign that we could start a wiki or repository to post that sort of higher-level stuff ?
Demo code
struct ExampleAppLog
{
ImGuiTextBuffer Buf;
ImGuiTextFilter Filter;
ImVector<int> LineOffsets; // Index to lines offset
bool ScrollToBottom;
void Clear() { Buf.clear(); LineOffsets.clear(); }
void AddLog(const char* fmt, ...) IM_PRINTFARGS(2)
{
int old_size = Buf.size();
va_list args;
va_start(args, fmt);
Buf.appendv(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);
ScrollToBottom = true;
}
void Draw(const char* title, bool* p_opened = NULL)
{
ImGui::SetNextWindowSize(ImVec2(500,400), ImGuiSetCond_FirstUseEver);
ImGui::Begin(title, p_opened);
if (ImGui::Button("Clear")) Clear();
ImGui::SameLine();
bool copy = ImGui::Button("Copy");
ImGui::SameLine();
Filter.Draw("Filter", -100.0f);
ImGui::Separator();
ImGui::BeginChild("scrolling");
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,1));
if (copy) ImGui::LogToClipboard();
if (Filter.IsActive())
{
const char* buf_begin = Buf.begin();
const char* line = buf_begin;
for (int line_no = 0; line != NULL; line_no++)
{
const char* line_end = (line_no < LineOffsets.Size) ? buf_begin + LineOffsets[line_no] : NULL;
if (Filter.PassFilter(line, line_end))
ImGui::TextUnformatted(line, line_end);
line = line_end && line_end[1] ? line_end + 1 : NULL;
}
}
else
{
ImGui::TextUnformatted(Buf.begin());
}
if (ScrollToBottom)
ImGui::SetScrollHere(1.0f);
ScrollToBottom = false;
ImGui::PopStyleVar();
ImGui::EndChild();
ImGui::End();
}
};
Same without filter
struct ExampleAppLog
{
ImGuiTextBuffer Buf;
bool ScrollToBottom;
void Clear() { Buf.clear(); }
void AddLog(const char* fmt, ...) IM_PRINTFARGS(2)
{
va_list args;
va_start(args, fmt);
Buf.appendv(fmt, args);
va_end(args);
ScrollToBottom = true;
}
void Draw(const char* title, bool* p_opened = NULL)
{
ImGui::SetNextWindowSize(ImVec2(500,400), ImGuiSetCond_FirstUseEver);
ImGui::Begin(title, p_opened);
if (ImGui::Button("Clear")) Clear();
ImGui::SameLine();
bool copy = ImGui::Button("Copy");
ImGui::Separator();
ImGui::BeginChild("scrolling");
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0,1));
if (copy) ImGui::LogToClipboard();
ImGui::TextUnformatted(Buf.begin());
if (ScrollToBottom)
ImGui::SetScrollHere(1.0f);
ScrollToBottom = false;
ImGui::PopStyleVar();
ImGui::EndChild();
ImGui::End();
}
};
Minimal version with no option, no filter:
struct ExampleAppLog
{
ImGuiTextBuffer Buf;
bool ScrollToBottom;
void Clear() { Buf.clear(); }
void AddLog(const char* fmt, ...) IM_PRINTFARGS(2)
{
va_list args;
va_start(args, fmt);
Buf.appendv(fmt, args);
va_end(args);
ScrollToBottom = true;
}
void Draw(const char* title, bool* p_opened = NULL)
{
ImGui::Begin(title, p_opened);
ImGui::TextUnformatted(Buf.begin());
if (ScrollToBottom)
ImGui::SetScrollHere(1.0f);
ScrollToBottom = false;
ImGui::End();
}
};
yes. yes. yes.
thank you sir.
it would be extra nice if you could provide one that only draws the visible lines of text, using imgui's clipping mechanisms.
Could be possible to use GetWindowDrawList().AddText() to emulate this (Zandronum/ZDooM console) ?

With TextUnformatted (&cia) and changing style per call, looks that I can only archive setting colours per line.
Please open a new topic for that.
FYI if you are stumbling on this thread: this is old code. Prefer using the equivalent code in imgui_demo.cpp as a base.
The wiki link appears to be dead. Code in imgui_demo.cpp was very helpful though thanks!
Most helpful comment
The wiki link appears to be dead. Code in imgui_demo.cpp was very helpful though thanks!