diff --git a/3rdparty/ocornut-imgui/imgui.cpp b/3rdparty/ocornut-imgui/imgui.cpp index 73a40ba46..ff23df2f0 100644 --- a/3rdparty/ocornut-imgui/imgui.cpp +++ b/3rdparty/ocornut-imgui/imgui.cpp @@ -396,6 +396,7 @@ - input text: add ImGuiInputTextFlags_EnterToApply? (off #218) - input text multi-line: way to dynamically grow the buffer without forcing the user to initially allocate for worse case (follow up on #200) - input text multi-line: line numbers? status bar? (follow up on #200) + - input text: read-only mode (can still select/copy, always display input buffer) - input number: optional range min/max for Input*() functions - input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled) - input number: use mouse wheel to step up/down @@ -776,13 +777,13 @@ const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) return buf_mid_line; } -const char* ImStristr(const char* haystack, const char* needle, const char* needle_end) +const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end) { if (!needle_end) needle_end = needle + strlen(needle); const char un0 = (char)toupper(*needle); - while (*haystack) + while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end)) { if (toupper(*haystack) == un0) { @@ -815,9 +816,9 @@ int ImFormatStringV(char* buf, int buf_size, const char* fmt, va_list args) return (w == -1) ? buf_size : w; } -// Pass data_size==0 for zero-terminated string +// Pass data_size==0 for zero-terminated strings // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements. -ImU32 ImHash(const void* data, int data_size, ImU32 seed = 0) +ImU32 ImHash(const void* data, int data_size, ImU32 seed) { static ImU32 crc32_lut[256] = { 0 }; if (!crc32_lut[1]) @@ -1282,10 +1283,10 @@ ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) void ImGuiTextFilter::Draw(const char* label, float width) { - if (width > 0.0f) + if (width != 0.0f) ImGui::PushItemWidth(width); ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf)); - if (width > 0.0f) + if (width != 0.0f) ImGui::PopItemWidth(); Build(); } @@ -1325,13 +1326,13 @@ void ImGuiTextFilter::Build() } } -bool ImGuiTextFilter::PassFilter(const char* val) const +bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const { if (Filters.empty()) return true; - if (val == NULL) - val = ""; + if (text == NULL) + text = ""; for (int i = 0; i != Filters.Size; i++) { @@ -1341,13 +1342,13 @@ bool ImGuiTextFilter::PassFilter(const char* val) const if (f.front() == '-') { // Subtract - if (ImStristr(val, f.begin()+1, f.end()) != NULL) + if (ImStristr(text, text_end, f.begin()+1, f.end()) != NULL) return false; } else { // Grep - if (ImStristr(val, f.begin(), f.end()) != NULL) + if (ImStristr(text, text_end, f.begin(), f.end()) != NULL) return true; } } @@ -2634,6 +2635,7 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex // Helper to calculate coarse clipping of large list of evenly sized items. // NB: Prefer using the ImGuiListClipper higher-level helper if you can! +// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX // If you are displaying thousands of items and you have a random access to the list, you can perform clipping yourself to save on CPU. // { // float item_height = ImGui::GetTextLineHeightWithSpacing(); @@ -2824,6 +2826,14 @@ ImVec2 ImGui::GetMousePos() return GImGui->IO.MousePos; } +ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup() +{ + ImGuiState& g = *GImGui; + if (g.CurrentPopupStack.Size > 0) + return g.OpenedPopupStack[g.CurrentPopupStack.Size-1].MousePosOnOpen; + return g.IO.MousePos; +} + ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold) { ImGuiState& g = *GImGui; @@ -2980,7 +2990,7 @@ void ImGui::OpenPopup(const char* str_id) ImGuiWindow* window = GetCurrentWindow(); ImGuiID id = window->GetID(str_id); int current_stack_size = g.CurrentPopupStack.Size; - ImGuiPopupRef popup_ref = ImGuiPopupRef(id, window, window->GetID("##menus")); // Tagged as new ref because constructor sets Window to NULL (we are passing the ParentWindow info here) + ImGuiPopupRef popup_ref = ImGuiPopupRef(id, window, window->GetID("##menus"), g.IO.MousePos); // Tagged as new ref because constructor sets Window to NULL (we are passing the ParentWindow info here) if (g.OpenedPopupStack.Size < current_stack_size + 1) g.OpenedPopupStack.push_back(popup_ref); else if (g.OpenedPopupStack[current_stack_size].PopupID != id) @@ -4672,6 +4682,7 @@ void ImGui::SetScrollFromPosY(float pos_y, float center_y_ratio) window->ScrollTargetCenterRatioY = center_y_ratio; } +// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item. void ImGui::SetScrollHere(float center_y_ratio) { ImGuiWindow* window = GetCurrentWindow(); @@ -8830,7 +8841,7 @@ void ImGui::ShowMetricsWindow(bool* opened) { ImGui::Text("ImGui %s", ImGui::GetVersion()); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); - ImGui::Text("%d vertices, %d triangles", ImGui::GetIO().MetricsRenderVertices, ImGui::GetIO().MetricsRenderIndices / 3); + ImGui::Text("%d vertices, %d indices (%d triangles)", ImGui::GetIO().MetricsRenderVertices, ImGui::GetIO().MetricsRenderIndices, ImGui::GetIO().MetricsRenderIndices / 3); ImGui::Text("%d allocations", ImGui::GetIO().MetricsAllocs); static bool show_clip_rects = true; ImGui::Checkbox("Show clipping rectangles when hovering ImDrawList", &show_clip_rects); diff --git a/3rdparty/ocornut-imgui/imgui.h b/3rdparty/ocornut-imgui/imgui.h index e0cf6c667..2dab96b3e 100644 --- a/3rdparty/ocornut-imgui/imgui.h +++ b/3rdparty/ocornut-imgui/imgui.h @@ -398,6 +398,7 @@ namespace ImGui IMGUI_API bool IsMouseHoveringRect(const ImVec2& pos_min, const ImVec2& pos_max); // is mouse hovering given bounding rect (in screen space). clipped by current clipping settings. disregarding of consideration of focus/window ordering/blocked by a popup. IMGUI_API bool IsMouseDragging(int button = 0, float lock_threshold = -1.0f); // is mouse dragging. if lock_threshold < -1.0f uses io.MouseDraggingThreshold IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls + IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve backup of mouse positioning at the time of opening popup we have BeginPopup() into IMGUI_API ImVec2 GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f); // dragging amount since clicking, also see: GetItemActiveDragDelta(). if lock_threshold < -1.0f uses io.MouseDraggingThreshold IMGUI_API void ResetMouseDragDelta(int button = 0); // IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you @@ -850,8 +851,8 @@ struct ImGuiTextFilter ImGuiTextFilter(const char* default_filter = ""); void Clear() { InputBuf[0] = 0; Build(); } - void Draw(const char* label = "Filter (inc,-exc)", float width = -1.0f); // Helper calling InputText+Build - bool PassFilter(const char* val) const; + void Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f); // Helper calling InputText+Build + bool PassFilter(const char* text, const char* text_end = NULL) const; bool IsActive() const { return !Filters.empty(); } IMGUI_API void Build(); }; @@ -862,10 +863,11 @@ struct ImGuiTextBuffer ImVector Buf; ImGuiTextBuffer() { Buf.push_back(0); } + inline char operator[](int i) { return Buf.Data[i]; } const char* begin() const { return &Buf.front(); } const char* end() const { return &Buf.back(); } // Buf is zero-terminated, so end() will point on the zero-terminator - int size() const { return Buf.Size-1; } - bool empty() { return size() >= 1; } + int size() const { return Buf.Size - 1; } + bool empty() { return Buf.Size >= 2; } void clear() { Buf.clear(); Buf.push_back(0); } IMGUI_API void append(const char* fmt, ...) IM_PRINTFARGS(2); IMGUI_API void appendv(const char* fmt, va_list args); @@ -962,6 +964,7 @@ struct ImColor // for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) // display only visible items // ImGui::Text("line number %d", i); // clipper.End(); +// NB: 'count' is only used to clamp the result, if you don't know your count you can use INT_MAX struct ImGuiListClipper { float ItemsHeight; diff --git a/3rdparty/ocornut-imgui/imgui_demo.cpp b/3rdparty/ocornut-imgui/imgui_demo.cpp index f4f5850c1..dfd85f3c9 100644 --- a/3rdparty/ocornut-imgui/imgui_demo.cpp +++ b/3rdparty/ocornut-imgui/imgui_demo.cpp @@ -44,6 +44,7 @@ #ifndef IMGUI_DISABLE_TEST_WINDOWS static void ShowExampleAppConsole(bool* opened); +static void ShowExampleAppLog(bool* opened); static void ShowExampleAppLayout(bool* opened); static void ShowExampleAppLongText(bool* opened); static void ShowExampleAppAutoResize(bool* opened); @@ -89,6 +90,7 @@ void ImGui::ShowTestWindow(bool* opened) static bool show_app_metrics = false; static bool show_app_main_menu_bar = false; static bool show_app_console = false; + static bool show_app_log = false; static bool show_app_layout = false; static bool show_app_long_text = false; static bool show_app_auto_resize = false; @@ -99,6 +101,7 @@ void ImGui::ShowTestWindow(bool* opened) if (show_app_metrics) ImGui::ShowMetricsWindow(&show_app_metrics); if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); if (show_app_console) ShowExampleAppConsole(&show_app_console); + if (show_app_log) ShowExampleAppLog(&show_app_log); if (show_app_layout) ShowExampleAppLayout(&show_app_layout); if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text); if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); @@ -157,6 +160,7 @@ void ImGui::ShowTestWindow(bool* opened) { ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar); ImGui::MenuItem("Console", NULL, &show_app_console); + ImGui::MenuItem("Log", NULL, &show_app_log); ImGui::MenuItem("Simple layout", NULL, &show_app_layout); ImGui::MenuItem("Long text display", NULL, &show_app_long_text); ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); @@ -1715,7 +1719,7 @@ struct ExampleAppConsole ScrollToBottom = true; } - void Run(const char* title, bool* opened) + void Draw(const char* title, bool* opened) { ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiSetCond_FirstUseEver); if (!ImGui::Begin(title, opened)) @@ -1938,7 +1942,88 @@ struct ExampleAppConsole static void ShowExampleAppConsole(bool* opened) { static ExampleAppConsole console; - console.Run("Example: Console", opened); + console.Draw("Example: Console", opened); +} + +// Usage: +// static ExampleAppLog my_log; +// my_log.AddLog("Hello %d world\n", 123); +// my_log.Draw("title"); +struct ExampleAppLog +{ + ImGuiTextBuffer Buf; + ImGuiTextFilter Filter; + ImVector 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"); + 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::EndChild(); + ImGui::End(); + } +}; + +static void ShowExampleAppLog(bool* opened) +{ + static ExampleAppLog log; + + // Demo fill + static float last_time = -1.0f; + float time = ImGui::GetTime(); + if (time - last_time >= 0.3f) + { + const char* random_words[] = { "system", "info", "warning", "error", "fatal", "notice", "log" }; + log.AddLog("[%s] Hello, time is %.1f, rand() %d\n", random_words[rand() % IM_ARRAYSIZE(random_words)], time, (int)rand()); + last_time = time; + } + + log.Draw("Example: Log", opened); } static void ShowExampleAppLayout(bool* opened) @@ -1999,7 +2084,7 @@ static void ShowExampleAppLongText(bool* opened) static ImGuiTextBuffer log; static int lines = 0; ImGui::Text("Printing unusually long amount of text."); - ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped"); + ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped\0"); ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); if (ImGui::Button("Clear")) { log.clear(); lines = 0; } ImGui::SameLine(); diff --git a/3rdparty/ocornut-imgui/imgui_internal.h b/3rdparty/ocornut-imgui/imgui_internal.h index 8512a635f..8c9b8ab2d 100644 --- a/3rdparty/ocornut-imgui/imgui_internal.h +++ b/3rdparty/ocornut-imgui/imgui_internal.h @@ -81,7 +81,7 @@ int ImTextCountCharsFromUtf8(const char* in_text, const char* in int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string as UTF-8 code-points // Helpers: Misc -ImU32 ImHash(const void* data, int data_size, ImU32 seed); +ImU32 ImHash(const void* data, int data_size, ImU32 seed = 0); // Pass data_size==0 for zero-terminated strings bool ImLoadFileToMemory(const char* filename, const char* file_open_mode, void** out_file_data, int* out_file_size = NULL, int padding_bytes = 0); bool ImIsPointInTriangle(const ImVec2& p, const ImVec2& a, const ImVec2& b, const ImVec2& c); static inline bool ImCharIsSpace(int c) { return c == ' ' || c == '\t' || c == 0x3000; } @@ -93,7 +93,7 @@ int ImStrnicmp(const char* str1, const char* str2, int count); char* ImStrdup(const char* str); int ImStrlenW(const ImWchar* str); const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line -const char* ImStristr(const char* haystack, const char* needle, const char* needle_end); +const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end); int ImFormatString(char* buf, int buf_size, const char* fmt, ...) IM_PRINTFARGS(3); int ImFormatStringV(char* buf, int buf_size, const char* fmt, va_list args); @@ -305,8 +305,9 @@ struct ImGuiPopupRef ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() ImGuiWindow* ParentWindow; // Set on OpenPopup() ImGuiID ParentMenuSet; // Set on OpenPopup() + ImVec2 MousePosOnOpen; // Copy of mouse position at the time of opening popup - ImGuiPopupRef(ImGuiID id, ImGuiWindow* parent_window, ImGuiID parent_menu_set) { PopupID = id; Window = NULL; ParentWindow = parent_window; ParentMenuSet = parent_menu_set; } + ImGuiPopupRef(ImGuiID id, ImGuiWindow* parent_window, ImGuiID parent_menu_set, const ImVec2& mouse_pos) { PopupID = id; Window = NULL; ParentWindow = parent_window; ParentMenuSet = parent_menu_set; MousePosOnOpen = mouse_pos; } }; // Main state for ImGui diff --git a/examples/common/imgui/ocornut_imgui.cpp b/examples/common/imgui/ocornut_imgui.cpp index a3a958940..ad6997c00 100644 --- a/examples/common/imgui/ocornut_imgui.cpp +++ b/examples/common/imgui/ocornut_imgui.cpp @@ -163,7 +163,7 @@ struct OcornutImguiContext vsmem = bgfx::makeRef(vs_ocornut_imgui_mtl, sizeof(vs_ocornut_imgui_mtl) ); fsmem = bgfx::makeRef(fs_ocornut_imgui_mtl, sizeof(fs_ocornut_imgui_mtl) ); break; - + default: vsmem = bgfx::makeRef(vs_ocornut_imgui_glsl, sizeof(vs_ocornut_imgui_glsl) ); fsmem = bgfx::makeRef(fs_ocornut_imgui_glsl, sizeof(fs_ocornut_imgui_glsl) );