Log depth padding relative to start depth. Tree node and headers looking better when logged to text. Added LogText().

This commit is contained in:
ocornut 2014-12-29 20:18:52 +00:00
parent 886d954e3d
commit 036a153cf4
2 changed files with 64 additions and 25 deletions

View File

@ -861,6 +861,7 @@ struct ImGuiState
bool LogEnabled; bool LogEnabled;
FILE* LogFile; FILE* LogFile;
ImGuiTextBuffer* LogClipboard; // pointer so our GImGui static constructor doesn't call heap allocators. ImGuiTextBuffer* LogClipboard; // pointer so our GImGui static constructor doesn't call heap allocators.
int LogStartDepth;
int LogAutoExpandMaxDepth; int LogAutoExpandMaxDepth;
ImGuiState() ImGuiState()
@ -887,6 +888,7 @@ struct ImGuiState
PrivateClipboard = NULL; PrivateClipboard = NULL;
LogEnabled = false; LogEnabled = false;
LogFile = NULL; LogFile = NULL;
LogStartDepth = 0;
LogAutoExpandMaxDepth = 2; LogAutoExpandMaxDepth = 2;
LogClipboard = NULL; LogClipboard = NULL;
} }
@ -1158,23 +1160,24 @@ bool ImGuiTextFilter::PassFilter(const char* val) const
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Helper: Text buffer for logging/accumulating text // Helper: Text buffer for logging/accumulating text
void ImGuiTextBuffer::append(const char* fmt, ...) void ImGuiTextBuffer::appendv(const char* fmt, va_list args)
{ {
va_list args; int len = vsnprintf(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.
va_start(args, fmt);
int len = vsnprintf(NULL, 0, fmt, args);
va_end(args);
if (len <= 0) if (len <= 0)
return; return;
const size_t write_off = Buf.size(); const size_t write_off = Buf.size();
if (write_off + (size_t)len >= Buf.capacity()) if (write_off + (size_t)len >= Buf.capacity())
Buf.reserve(Buf.capacity() * 2); Buf.reserve(Buf.capacity() * 2);
Buf.resize(write_off + (size_t)len); Buf.resize(write_off + (size_t)len);
va_start(args, fmt);
ImFormatStringV(&Buf[write_off] - 1, (size_t)len+1, fmt, args); ImFormatStringV(&Buf[write_off] - 1, (size_t)len+1, fmt, args);
}
void ImGuiTextBuffer::append(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
appendv(fmt, args);
va_end(args); va_end(args);
} }
@ -1764,7 +1767,27 @@ static const char* FindTextDisplayEnd(const char* text, const char* text_end =
return text_display_end; return text_display_end;
} }
// Log ImGui display into text output (tty or file or clipboard) // Pass text data straight to log (without being displayed)
void ImGui::LogText(const char* fmt, ...)
{
ImGuiState& g = GImGui;
if (!g.LogEnabled)
return;
va_list args;
va_start(args, fmt);
if (g.LogFile)
{
vfprintf(g.LogFile, fmt, args);
}
else
{
g.LogClipboard->appendv(fmt, args);
}
va_end(args);
}
// Internal version that takes a position to decide on newline placement and pad items according to their depth.
static void LogText(const ImVec2& ref_pos, const char* text, const char* text_end) static void LogText(const ImVec2& ref_pos, const char* text, const char* text_end)
{ {
ImGuiState& g = GImGui; ImGuiState& g = GImGui;
@ -1777,7 +1800,9 @@ static void LogText(const ImVec2& ref_pos, const char* text, const char* text_en
window->DC.LogLineHeight = ref_pos.y; window->DC.LogLineHeight = ref_pos.y;
const char* text_remaining = text; const char* text_remaining = text;
const int tree_depth = window->DC.TreeDepth; if (g.LogStartDepth > window->DC.TreeDepth) // Re-adjust padding if we have popped out of our starting depth
g.LogStartDepth = window->DC.TreeDepth;
const int tree_depth = (window->DC.TreeDepth - g.LogStartDepth);
while (true) while (true)
{ {
const char* line_end = text_remaining; const char* line_end = text_remaining;
@ -1799,20 +1824,10 @@ static void LogText(const ImVec2& ref_pos, const char* text, const char* text_en
if (line_end != NULL && !(is_last_line && (line_end - text_remaining)==0)) if (line_end != NULL && !(is_last_line && (line_end - text_remaining)==0))
{ {
const int char_count = (int)(line_end - text_remaining); const int char_count = (int)(line_end - text_remaining);
if (g.LogFile) if (log_new_line || !is_first_line)
{ ImGui::LogText("\n%*s%.*s", tree_depth*4, "", char_count, text_remaining);
if (log_new_line || !is_first_line)
fprintf(g.LogFile, "\n%*s%.*s", tree_depth*4, "", char_count, text_remaining);
else
fprintf(g.LogFile, " %.*s", char_count, text_remaining);
}
else else
{ ImGui::LogText(" %.*s", char_count, text_remaining);
if (log_new_line || !is_first_line)
g.LogClipboard->append("\n%*s%.*s", tree_depth*4, "", char_count, text_remaining);
else
g.LogClipboard->append(" %.*s", char_count, text_remaining);
}
} }
if (is_last_line) if (is_last_line)
@ -3434,10 +3449,13 @@ static bool CloseWindowButton(bool* p_opened)
void ImGui::LogToTTY(int max_depth) void ImGui::LogToTTY(int max_depth)
{ {
ImGuiState& g = GImGui; ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (g.LogEnabled) if (g.LogEnabled)
return; return;
g.LogEnabled = true; g.LogEnabled = true;
g.LogFile = stdout; g.LogFile = stdout;
g.LogStartDepth = window->DC.TreeDepth;
if (max_depth >= 0) if (max_depth >= 0)
g.LogAutoExpandMaxDepth = max_depth; g.LogAutoExpandMaxDepth = max_depth;
} }
@ -3446,12 +3464,15 @@ void ImGui::LogToTTY(int max_depth)
void ImGui::LogToFile(int max_depth, const char* filename) void ImGui::LogToFile(int max_depth, const char* filename)
{ {
ImGuiState& g = GImGui; ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (g.LogEnabled) if (g.LogEnabled)
return; return;
if (!filename) if (!filename)
filename = g.IO.LogFilename; filename = g.IO.LogFilename;
g.LogEnabled = true; g.LogEnabled = true;
g.LogFile = fopen(filename, "at"); g.LogFile = fopen(filename, "at");
g.LogStartDepth = window->DC.TreeDepth;
if (max_depth >= 0) if (max_depth >= 0)
g.LogAutoExpandMaxDepth = max_depth; g.LogAutoExpandMaxDepth = max_depth;
} }
@ -3459,11 +3480,14 @@ void ImGui::LogToFile(int max_depth, const char* filename)
// Start logging ImGui output to clipboard // Start logging ImGui output to clipboard
void ImGui::LogToClipboard(int max_depth) void ImGui::LogToClipboard(int max_depth)
{ {
ImGuiWindow* window = GetCurrentWindow();
ImGuiState& g = GImGui; ImGuiState& g = GImGui;
if (g.LogEnabled) if (g.LogEnabled)
return; return;
g.LogEnabled = true; g.LogEnabled = true;
g.LogFile = NULL; g.LogFile = NULL;
g.LogStartDepth = window->DC.TreeDepth;
if (max_depth >= 0) if (max_depth >= 0)
g.LogAutoExpandMaxDepth = max_depth; g.LogAutoExpandMaxDepth = max_depth;
} }
@ -3473,10 +3497,11 @@ void ImGui::LogFinish()
ImGuiState& g = GImGui; ImGuiState& g = GImGui;
if (!g.LogEnabled) if (!g.LogEnabled)
return; return;
ImGui::LogText("\n");
g.LogEnabled = false; g.LogEnabled = false;
if (g.LogFile != NULL) if (g.LogFile != NULL)
{ {
fprintf(g.LogFile, "\n");
if (g.LogFile == stdout) if (g.LogFile == stdout)
fflush(g.LogFile); fflush(g.LogFile);
else else
@ -3485,7 +3510,6 @@ void ImGui::LogFinish()
} }
if (g.LogClipboard->size() > 1) if (g.LogClipboard->size() > 1)
{ {
g.LogClipboard->append("\n");
if (g.IO.SetClipboardTextFn) if (g.IO.SetClipboardTextFn)
g.IO.SetClipboardTextFn(g.LogClipboard->begin()); g.IO.SetClipboardTextFn(g.LogClipboard->begin());
g.LogClipboard->clear(); g.LogClipboard->clear();
@ -3591,7 +3615,18 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, const bool d
// Framed type // Framed type
RenderFrame(bb.Min, bb.Max, col, true); RenderFrame(bb.Min, bb.Max, col, true);
RenderCollapseTriangle(bb.Min + style.FramePadding, opened, 1.0f, true); RenderCollapseTriangle(bb.Min + style.FramePadding, opened, 1.0f, true);
if (g.LogEnabled)
{
// NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here.
const char log_prefix[] = "\n##";
LogText(bb.Min + style.FramePadding, log_prefix, log_prefix+3);
}
RenderText(bb.Min + style.FramePadding + ImVec2(window->FontSize() + style.FramePadding.x*2,0), label); RenderText(bb.Min + style.FramePadding + ImVec2(window->FontSize() + style.FramePadding.x*2,0), label);
if (g.LogEnabled)
{
const char log_suffix[] = "##";
LogText(bb.Min + style.FramePadding, log_suffix, log_suffix+2);
}
} }
else else
{ {
@ -3599,6 +3634,8 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, const bool d
if ((held && hovered) || hovered) if ((held && hovered) || hovered)
RenderFrame(bb.Min, bb.Max, col, false); RenderFrame(bb.Min, bb.Max, col, false);
RenderCollapseTriangle(bb.Min + ImVec2(style.FramePadding.x, window->FontSize()*0.15f), opened, 0.70f, false); RenderCollapseTriangle(bb.Min + ImVec2(style.FramePadding.x, window->FontSize()*0.15f), opened, 0.70f, false);
if (g.LogEnabled)
LogText(bb.Min, ">");
RenderText(bb.Min + ImVec2(window->FontSize() + style.FramePadding.x*2,0), label); RenderText(bb.Min + ImVec2(window->FontSize() + style.FramePadding.x*2,0), label);
} }

View File

@ -286,6 +286,7 @@ namespace ImGui
IMGUI_API void LogToClipboard(int max_depth = -1); // start logging to OS clipboard IMGUI_API void LogToClipboard(int max_depth = -1); // start logging to OS clipboard
IMGUI_API void LogFinish(); // stop logging (close file, etc.) IMGUI_API void LogFinish(); // stop logging (close file, etc.)
IMGUI_API void LogButtons(); // helper to display buttons for logging to tty/file/clipboard IMGUI_API void LogButtons(); // helper to display buttons for logging to tty/file/clipboard
IMGUI_API void LogText(const char* fmt, ...); // pass text data straight to log (without being displayed)
// Utilities // Utilities
IMGUI_API bool IsItemHovered(); // was the last item active area hovered by mouse? IMGUI_API bool IsItemHovered(); // was the last item active area hovered by mouse?
@ -605,6 +606,7 @@ struct ImGuiTextBuffer
bool empty() { return Buf.empty(); } bool empty() { return Buf.empty(); }
void clear() { Buf.clear(); Buf.push_back(0); } void clear() { Buf.clear(); Buf.push_back(0); }
IMGUI_API void append(const char* fmt, ...); IMGUI_API void append(const char* fmt, ...);
IMGUI_API void appendv(const char* fmt, va_list args);
}; };
// Helper: Key->value storage // Helper: Key->value storage