Explorar el Código

Merge pull request #75 from mikymod/tools-imgui-2

Improve tools-imgui
Daniele Bartolini hace 8 años
padre
commit
b03a81de3d

+ 110 - 99
3rdparty/ocornut-imgui/imgui.cpp

@@ -1,14 +1,14 @@
-// dear imgui, v1.53 WIP
+// dear imgui, v1.53
 // (main code and documentation)
 
-// See ImGui::ShowTestWindow() in imgui_demo.cpp for demo code.
+// Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code.
 // Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase.
 // Get latest version at https://github.com/ocornut/imgui
 // Releases change-log at https://github.com/ocornut/imgui/releases
 // Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/1269
 // Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
 // This library is free but I need your support to sustain development and maintenance.
-// If you work for a company, please consider financial support, e.g: https://www.patreon.com/imgui
+// If you work for a company, please consider financial support, see Readme. For individuals: https://www.patreon.com/imgui
 
 /*
 
@@ -86,7 +86,7 @@
  - Read the FAQ below this section!
  - Your code creates the UI, if your code doesn't run the UI is gone! == very dynamic UI, no construction/destructions steps, less data retention
    on your side, no state duplication, less sync, less bugs.
- - Call and read ImGui::ShowTestWindow() for demo code demonstrating most features.
+ - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
  - You can learn about immediate-mode gui principles at http://www.johno.se/book/imgui.html or watch http://mollyrocket.com/861
 
  HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
@@ -213,6 +213,9 @@
  Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code.
  Also read releases logs https://github.com/ocornut/imgui/releases for more details.
 
+ - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete).
+ - 2017/12/21 (1.53) - ImDrawList: renamed style.AntiAliasedShapes to style.AntiAliasedFill for consistency and as a way to explicitly break code that manipulate those flag at runtime. You can now manipulate ImDrawList::Flags
+ - 2017/12/21 (1.53) - ImDrawList: removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Prefer manipulating ImDrawList::Flags if you need to toggle them during the frame.
  - 2017/12/14 (1.53) - using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set.
  - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete).
  - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).
@@ -574,7 +577,7 @@
  - tip: the ImGuiOnceUponAFrame helper will allow run the block of code only once a frame. You can use it to quickly add custom UI in the middle
    of a deep nested inner loop in your code.
  - tip: you can call Render() multiple times (e.g for VR renders).
- - tip: call and read the ShowTestWindow() code in imgui_demo.cpp for more example of how to use ImGui!
+ - tip: call and read the ShowDemoWindow() code in imgui_demo.cpp for more example of how to use ImGui!
 
 */
 
@@ -584,7 +587,6 @@
 
 #include "imgui.h"
 #define IMGUI_DEFINE_MATH_OPERATORS
-#define IMGUI_DEFINE_PLACEMENT_NEW
 #include "imgui_internal.h"
 
 #include <ctype.h>      // toupper, isprint
@@ -599,7 +601,6 @@
 
 #ifdef _MSC_VER
 #pragma warning (disable: 4127) // condition expression is constant
-#pragma warning (disable: 4201) // nonstandard extension used: nameless struct/union
 #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
 #endif
@@ -613,10 +614,6 @@
 #pragma clang diagnostic ignored "-Wexit-time-destructors"  // warning : declaration requires an exit-time destructor       // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals.
 #pragma clang diagnostic ignored "-Wglobal-constructors"    // warning : declaration requires a global destructor           // similar to above, not sure what the exact difference it.
 #pragma clang diagnostic ignored "-Wsign-conversion"        // warning : implicit conversion changes signedness             //
-#pragma clang diagnostic ignored "-Wmissing-noreturn"       // warning : function xx could be declared with attribute 'noreturn' warning    // GetDefaultFontData() asserts which some implementation makes it never return.
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"// warning : 'xx' is deprecated: The POSIX name for this item.. // for strdup used in demo code (so user can copy & paste the code)
-#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int'
-#pragma clang diagnostic ignored "-Wunused-function"          // warning: 'xxxx' defined but not used
 #pragma clang diagnostic ignored "-Wformat-pedantic"        // warning : format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic. 
 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' //
 #elif defined(__GNUC__)
@@ -739,8 +736,8 @@ ImGuiStyle::ImGuiStyle()
     DisplayWindowPadding    = ImVec2(22,22);    // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows.
     DisplaySafeAreaPadding  = ImVec2(4,4);      // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
     AntiAliasedLines        = true;             // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU.
-    AntiAliasedShapes       = true;             // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.)
-    CurveTessellationTol    = 1.25f;            // Tessellation tolerance. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
+    AntiAliasedFill         = true;             // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.)
+    CurveTessellationTol    = 1.25f;            // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
 
     ImGui::StyleColorsClassic(this);
 }
@@ -914,17 +911,17 @@ int ImStricmp(const char* str1, const char* str2)
     return d;
 }
 
-int ImStrnicmp(const char* str1, const char* str2, int count)
+int ImStrnicmp(const char* str1, const char* str2, size_t count)
 {
     int d = 0;
     while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
     return d;
 }
 
-void ImStrncpy(char* dst, const char* src, int count)
+void ImStrncpy(char* dst, const char* src, size_t count)
 {
     if (count < 1) return;
-    strncpy(dst, src, (size_t)count);
+    strncpy(dst, src, count);
     dst[count-1] = 0;
 }
 
@@ -995,7 +992,7 @@ static const char* ImAtoi(const char* src, int* output)
 // Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm.
 // B) When buf==NULL vsnprintf() will return the output size.
 #ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
-int ImFormatString(char* buf, int buf_size, const char* fmt, ...)
+int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
 {
     va_list args;
     va_start(args, fmt);
@@ -1003,19 +1000,19 @@ int ImFormatString(char* buf, int buf_size, const char* fmt, ...)
     va_end(args);
     if (buf == NULL)
         return w;
-    if (w == -1 || w >= buf_size)
-        w = buf_size - 1;
+    if (w == -1 || w >= (int)buf_size)
+        w = (int)buf_size - 1;
     buf[w] = 0;
     return w;
 }
 
-int ImFormatStringV(char* buf, int buf_size, const char* fmt, va_list args)
+int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
 {
     int w = vsnprintf(buf, buf_size, fmt, args);
     if (buf == NULL)
         return w;
-    if (w == -1 || w >= buf_size)
-        w = buf_size - 1;
+    if (w == -1 || w >= (int)buf_size)
+        w = (int)buf_size - 1;
     buf[w] = 0;
     return w;
 }
@@ -1823,7 +1820,7 @@ bool ImGuiListClipper::Step()
 // ImGuiWindow
 //-----------------------------------------------------------------------------
 
-ImGuiWindow::ImGuiWindow(const char* name)
+ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
 {
     Name = ImStrdup(name);
     ID = ImHash(name, 0);
@@ -1863,8 +1860,7 @@ ImGuiWindow::ImGuiWindow(const char* name)
     ItemWidthDefault = 0.0f;
     FontWindowScale = 1.0f;
 
-    DrawList = (ImDrawList*)ImGui::MemAlloc(sizeof(ImDrawList));
-    IM_PLACEMENT_NEW(DrawList) ImDrawList();
+    DrawList = IM_NEW(ImDrawList)(&context->DrawListSharedData);
     DrawList->_OwnerName = Name;
     ParentWindow = NULL;
     RootWindow = NULL;
@@ -1877,11 +1873,8 @@ ImGuiWindow::ImGuiWindow(const char* name)
 
 ImGuiWindow::~ImGuiWindow()
 {
-    DrawList->~ImDrawList();
-    ImGui::MemFree(DrawList);
-    DrawList = NULL;
-    ImGui::MemFree(Name);
-    Name = NULL;
+    IM_DELETE(DrawList);
+    IM_DELETE(Name);
 }
 
 ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
@@ -1925,7 +1918,7 @@ static void SetCurrentWindow(ImGuiWindow* window)
     ImGuiContext& g = *GImGui;
     g.CurrentWindow = window;
     if (window)
-        g.FontSize = window->CalcFontSize();
+        g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
 }
 
 void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
@@ -2259,6 +2252,11 @@ ImDrawList* ImGui::GetOverlayDrawList()
     return &GImGui->OverlayDrawList;
 }
 
+ImDrawListSharedData* ImGui::GetDrawListSharedData()
+{
+    return &GImGui->DrawListSharedData;
+}
+
 void ImGui::NewFrame()
 {
     ImGuiContext& g = *GImGui;
@@ -2279,6 +2277,8 @@ void ImGui::NewFrame()
 
     SetCurrentFont(GetDefaultFont());
     IM_ASSERT(g.Font->IsLoaded());
+    g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
+    g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
 
     g.Time += g.IO.DeltaTime;
     g.FrameCount += 1;
@@ -2287,6 +2287,7 @@ void ImGui::NewFrame()
     g.OverlayDrawList.Clear();
     g.OverlayDrawList.PushTextureID(g.IO.Fonts->TexID);
     g.OverlayDrawList.PushClipRectFullScreen();
+    g.OverlayDrawList.Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
 
     // Mark rendering data as invalid to prevent user who may have a handle on it to use it
     g.RenderDrawData.Valid = false;
@@ -2378,9 +2379,10 @@ void ImGui::NewFrame()
         IM_ASSERT(g.MovingWindow->MoveId == g.MovingWindowMoveId);
         if (g.IO.MouseDown[0])
         {
-            g.MovingWindow->RootWindow->PosFloat += g.IO.MouseDelta;
-            if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f)
+            ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset;
+            if (g.MovingWindow->RootWindow->PosFloat.x != pos.x || g.MovingWindow->RootWindow->PosFloat.y != pos.y)
                 MarkIniSettingsDirty(g.MovingWindow->RootWindow);
+            g.MovingWindow->RootWindow->PosFloat = pos;
             FocusWindow(g.MovingWindow);
         }
         else
@@ -2411,7 +2413,8 @@ void ImGui::NewFrame()
     g.HoveredWindow = (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoInputs)) ? g.MovingWindow : FindHoveredWindow(g.IO.MousePos);
     g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;
 
-    if (ImGuiWindow* modal_window = GetFrontMostModalRootWindow())
+    ImGuiWindow* modal_window = GetFrontMostModalRootWindow();
+    if (modal_window != NULL)
     {
         g.ModalWindowDarkeningRatio = ImMin(g.ModalWindowDarkeningRatio + g.IO.DeltaTime * 6.0f, 1.0f);
         if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window))
@@ -2440,15 +2443,19 @@ void ImGui::NewFrame()
         g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0);
     else
         g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (!g.OpenPopupStack.empty());
-    g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != -1) ? (g.WantCaptureKeyboardNextFrame != 0) : (g.ActiveId != 0);
+    if (g.WantCaptureKeyboardNextFrame != -1)
+        g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);
+    else
+        g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);
     g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : 0;
     g.MouseCursor = ImGuiMouseCursor_Arrow;
     g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1;
     g.OsImePosRequest = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default
 
     // If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
-    // FIXME: For patterns of drag and drop between "application" and "imgui" we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
-    if (!mouse_avail_to_imgui)
+    // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
+    bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
+    if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload)
         g.HoveredWindow = g.HoveredRootWindow = NULL;
 
     // Scale & Scrolling
@@ -2570,8 +2577,7 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext& g, ImGuiTextBuffer* buf
 void ImGui::Initialize()
 {
     ImGuiContext& g = *GImGui;
-    g.LogClipboard = (ImGuiTextBuffer*)ImGui::MemAlloc(sizeof(ImGuiTextBuffer));
-    IM_PLACEMENT_NEW(g.LogClipboard) ImGuiTextBuffer();
+    g.LogClipboard = IM_NEW(ImGuiTextBuffer)();
 
     // Add .ini handle for ImGuiWindow type
     ImGuiSettingsHandler ini_handler;
@@ -2604,10 +2610,7 @@ void ImGui::Shutdown()
     SaveIniSettingsToDisk(g.IO.IniFilename);
 
     for (int i = 0; i < g.Windows.Size; i++)
-    {
-        g.Windows[i]->~ImGuiWindow();
-        ImGui::MemFree(g.Windows[i]);
-    }
+        IM_DELETE(g.Windows[i]);
     g.Windows.clear();
     g.WindowsSortBuffer.clear();
     g.CurrentWindow = NULL;
@@ -2619,7 +2622,7 @@ void ImGui::Shutdown()
     g.ActiveIdWindow = NULL;
     g.MovingWindow = NULL;
     for (int i = 0; i < g.SettingsWindows.Size; i++)
-        ImGui::MemFree(g.SettingsWindows[i].Name);
+        IM_DELETE(g.SettingsWindows[i].Name);
     g.ColorModifiers.clear();
     g.StyleModifiers.clear();
     g.FontStack.clear();
@@ -2644,10 +2647,7 @@ void ImGui::Shutdown()
         g.LogFile = NULL;
     }
     if (g.LogClipboard)
-    {
-        g.LogClipboard->~ImGuiTextBuffer();
-        ImGui::MemFree(g.LogClipboard);
-    }
+        IM_DELETE(g.LogClipboard);
 
     g.Initialized = false;
 }
@@ -2716,8 +2716,8 @@ static void LoadIniSettingsFromMemory(const char* buf_readonly)
         if (line[0] == '[' && line_end > line && line_end[-1] == ']')
         {
             // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code.
-            char* name_end = line_end - 1; 
-            *name_end = 0;
+            line_end[-1] = 0;
+            const char* name_end = line_end - 1; 
             const char* type_start = line + 1;
             char* type_end = ImStrchrRange(type_start, name_end, ']');
             const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL;
@@ -2837,15 +2837,17 @@ static void AddDrawListToRenderList(ImVector<ImDrawList*>& out_render_list, ImDr
     IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
     IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
 
-    // Check that draw_list doesn't use more vertices than indexable in a single draw call (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per window)
-    // If this assert triggers because you are drawing lots of stuff manually, you can:
-    // A) Add '#define ImDrawIdx unsigned int' in imconfig.h to set the index size to 4 bytes. You'll need to handle the 4-bytes indices to your renderer.
-    //    For example, the OpenGL example code detect index size at compile-time by doing:
-    //    'glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);'
+    // Check that draw_list doesn't use more vertices than indexable in a single draw call (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
+    // If this assert triggers because you are drawing lots of stuff manually:
+    // A) Make sure you are coarse clipping, because ImDrawList let all your vertices pass. You can use thre Metrics window to inspect draw list contents.
+    // B) If you need/want meshes with more than 64K vertices, uncomment the '#define ImDrawIdx unsigned int' line in imconfig.h to set the index size to 4 bytes. 
+    //    You'll need to handle the 4-bytes indices to your renderer. For example, the OpenGL example code detect index size at compile-time by doing:
+    //      glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
     //    Your own engine or render API may use different parameters or function calls to specify index sizes. 2 and 4 bytes indices are generally supported by most API.
-    // B) If for some reason you cannot use 4 bytes indices or don't want to, a workaround is to call BeginChild()/EndChild() before reaching the 64K limit to split your draw commands in multiple draw lists.
-    IM_ASSERT(((ImU64)draw_list->_VtxCurrentIdx >> (sizeof(ImDrawIdx)*8)) == 0);  // Too many vertices in same ImDrawList. See comment above.
-    
+    // C) If for some reason you cannot use 4 bytes indices or don't want to, a workaround is to call BeginChild()/EndChild() before reaching the 64K limit to split your draw commands in multiple draw lists.
+    if (sizeof(ImDrawIdx) == 2)
+        IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
+
     out_render_list.push_back(draw_list);
     GImGui->IO.MetricsRenderVertices += draw_list->VtxBuffer.Size;
     GImGui->IO.MetricsRenderIndices += draw_list->IdxBuffer.Size;
@@ -2929,6 +2931,7 @@ void ImGui::EndFrame()
                         g.MovingWindow = g.HoveredWindow;
                         g.MovingWindowMoveId = g.MovingWindow->MoveId;
                         SetActiveID(g.MovingWindowMoveId, g.HoveredRootWindow);
+                        g.ActiveIdClickOffset = g.IO.MousePos - g.MovingWindow->RootWindow->Pos;
                     }
                 }
                 else if (g.NavWindow != NULL && GetFrontMostModalRootWindow() == NULL)
@@ -3262,22 +3265,23 @@ void ImGui::RenderTriangle(ImVec2 p_min, ImGuiDir dir, float scale)
     switch (dir)
     {
     case ImGuiDir_Up:
-        r = -r; // ...fall through, no break!
     case ImGuiDir_Down:
+        if (dir == ImGuiDir_Up) r = -r;
         center.y -= r * 0.25f;
         a = ImVec2(0,1) * r;
         b = ImVec2(-0.866f,-0.5f) * r;
         c = ImVec2(+0.866f,-0.5f) * r;
         break;
     case ImGuiDir_Left:
-        r = -r; // ...fall through, no break!
     case ImGuiDir_Right:
+        if (dir == ImGuiDir_Left) r = -r;
         center.x -= r * 0.25f;
         a = ImVec2(1,0) * r;
         b = ImVec2(-0.500f,+0.866f) * r;
         c = ImVec2(-0.500f,-0.866f) * r;
         break;
-    default:
+    case ImGuiDir_None: 
+    case ImGuiDir_Count_: 
         IM_ASSERT(0);
         break;
     }
@@ -3833,15 +3837,13 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
         return false;
     }
 
-    ImGuiWindowFlags flags = extra_flags|ImGuiWindowFlags_Popup|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings;
-
     char name[20];
-    if (flags & ImGuiWindowFlags_ChildMenu)
+    if (extra_flags & ImGuiWindowFlags_ChildMenu)
         ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.CurrentPopupStack.Size);    // Recycle windows based on depth
     else
         ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
 
-    bool is_open = Begin(name, NULL, flags);
+    bool is_open = Begin(name, NULL, extra_flags | ImGuiWindowFlags_Popup);
     if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display)
         EndPopup();
 
@@ -3856,7 +3858,7 @@ bool ImGui::BeginPopup(const char* str_id)
         ClearSetNextWindowData(); // We behave like Begin() and need to consume those values
         return false;
     }
-    return BeginPopupEx(g.CurrentWindow->GetID(str_id), ImGuiWindowFlags_AlwaysAutoResize);
+    return BeginPopupEx(g.CurrentWindow->GetID(str_id), ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings);
 }
 
 bool ImGui::IsPopupOpen(ImGuiID id)
@@ -3931,7 +3933,7 @@ bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button)
     if (IsMouseClicked(mouse_button))
         if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
             OpenPopupEx(id, true);
-    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize);
+    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings);
 }
 
 bool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool also_over_items)
@@ -3943,7 +3945,7 @@ bool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool a
         if (IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
             if (also_over_items || !IsAnyItemHovered())
                 OpenPopupEx(id, true);
-    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize);
+    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings);
 }
 
 bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button)
@@ -3953,7 +3955,7 @@ bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button)
     ImGuiID id = GImGui->CurrentWindow->GetID(str_id);
     if (!IsAnyWindowHovered() && IsMouseClicked(mouse_button))
         OpenPopupEx(id, true);
-    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize);
+    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings);
 }
 
 static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
@@ -4147,8 +4149,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl
     ImGuiContext& g = *GImGui;
 
     // Create window the first time
-    ImGuiWindow* window = (ImGuiWindow*)ImGui::MemAlloc(sizeof(ImGuiWindow));
-    IM_PLACEMENT_NEW(window) ImGuiWindow(name);
+    ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
     window->Flags = flags;
     g.WindowsById.SetVoidPtr(window->ID, window);
 
@@ -4470,8 +4471,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
         window->LastFrameActive = current_frame;
         window->IDStack.resize(1);
 
-        // Clear draw list, setup texture, outer clipping rectangle
+        // Setup draw list and outer clipping rectangle
         window->DrawList->Clear();
+        window->DrawList->Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
         window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
         ImRect fullscreen_rect(GetVisibleRect());
         if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup))
@@ -4656,16 +4658,16 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
         window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window);
         window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
 
-        // Modal window darkens what is behind them
-        if ((flags & ImGuiWindowFlags_Modal) != 0 && window == GetFrontMostModalRootWindow())
-            window->DrawList->AddRectFilled(fullscreen_rect.Min, fullscreen_rect.Max, GetColorU32(ImGuiCol_ModalWindowDarkening, g.ModalWindowDarkeningRatio));
-
         // Apply focus, new windows appears in front
         bool want_focus = false;
         if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
             if (!(flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) || (flags & ImGuiWindowFlags_Popup))
                 want_focus = true;
 
+        // Draw modal window background (darkens what is behind them)
+        if ((flags & ImGuiWindowFlags_Modal) != 0 && window == GetFrontMostModalRootWindow())
+            window->DrawList->AddRectFilled(fullscreen_rect.Min, fullscreen_rect.Max, GetColorU32(ImGuiCol_ModalWindowDarkening, g.ModalWindowDarkeningRatio));
+
         // Draw window + handle manual resize
         ImRect title_bar_rect = window->TitleBarRect();
         if (window->Collapsed)
@@ -5246,7 +5248,11 @@ static void SetCurrentFont(ImFont* font)
     g.Font = font;
     g.FontBaseSize = g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale;
     g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;
-    g.FontTexUvWhitePixel = g.Font->ContainerAtlas->TexUvWhitePixel;
+
+    ImFontAtlas* atlas = g.Font->ContainerAtlas;
+    g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel;
+    g.DrawListSharedData.Font = g.Font;
+    g.DrawListSharedData.FontSize = g.FontSize;
 }
 
 void ImGui::PushFont(ImFont* font)
@@ -5377,7 +5383,6 @@ static const ImGuiStyleVarInfo GStyleVarInfo[ImGuiStyleVar_Count_] =
     { ImGuiDataType_Float,  (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) },        // ImGuiStyleVar_IndentSpacing
     { ImGuiDataType_Float,  (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) },          // ImGuiStyleVar_GrabMinSize
     { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) },      // ImGuiStyleVar_ButtonTextAlign
-    { ImGuiDataType_Float,  (ImU32)IM_OFFSETOF(ImGuiStyle, ViewId) },
 };
 
 static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx)
@@ -5824,7 +5829,7 @@ float ImGui::GetFontSize()
 
 ImVec2 ImGui::GetFontTexUvWhitePixel()
 {
-    return GImGui->FontTexUvWhitePixel;
+    return GImGui->DrawListSharedData.TexUvWhitePixel;
 }
 
 void ImGui::SetWindowFontScale(float scale)
@@ -5832,7 +5837,7 @@ void ImGui::SetWindowFontScale(float scale)
     ImGuiContext& g = *GImGui;
     ImGuiWindow* window = GetCurrentWindow();
     window->FontWindowScale = scale;
-    g.FontSize = window->CalcFontSize();
+    g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
 }
 
 // User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.
@@ -8411,6 +8416,7 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
     const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0;
     const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0;
     const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0;
+    const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0;
 
     if (is_multiline) // Open group before calling GetID() because groups tracks id created during their spawn
         BeginGroup();
@@ -8637,10 +8643,10 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2
             if (InputTextFilterCharacter(&c, flags, callback, user_data))
                 edit_state.OnKeyPressed((int)c);
         }
-        else if (IsKeyPressedMap(ImGuiKey_Escape))                                      { clear_active_id = cancel_edit = true; }
-        else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Z) && is_editable)    { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); }
-        else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Y) && is_editable)    { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); }
-        else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_A))                   { edit_state.SelectAll(); edit_state.CursorFollow = true; }
+        else if (IsKeyPressedMap(ImGuiKey_Escape))                                                       { clear_active_id = cancel_edit = true; }
+        else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Z) && is_editable && is_undoable)      { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); }
+        else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Y) && is_editable && is_undoable)      { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); }
+        else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_A))                                    { edit_state.SelectAll(); edit_state.CursorFollow = true; }
         else if (is_shortcut_key_only && !is_password && ((IsKeyPressedMap(ImGuiKey_X) && is_editable) || IsKeyPressedMap(ImGuiKey_C)) && (!is_multiline || edit_state.HasSelection()))
         {
             // Cut, Copy
@@ -9759,7 +9765,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
     if (menu_is_open)
     {
         SetNextWindowPos(popup_pos, ImGuiCond_Always);
-        ImGuiWindowFlags flags = ImGuiWindowFlags_AlwaysAutoResize | ((window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) ? ImGuiWindowFlags_ChildMenu|ImGuiWindowFlags_ChildWindow : ImGuiWindowFlags_ChildMenu);
+        ImGuiWindowFlags flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ((window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu)) ? ImGuiWindowFlags_ChildMenu|ImGuiWindowFlags_ChildWindow : ImGuiWindowFlags_ChildMenu);
         menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
     }
 
@@ -10241,7 +10247,7 @@ static void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGui
     case ImGuiDir_Right: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), pos, col); return;
     case ImGuiDir_Up:    draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), pos, col); return;
     case ImGuiDir_Down:  draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), pos, col); return;
-    default: return; // Fix warning for ImGuiDir_None
+    case ImGuiDir_None: case ImGuiDir_Count_: break; // Fix warnings
     }
 }
 
@@ -10492,7 +10498,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
         ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle);
         ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle);
         ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle);
-        ImVec2 uv_white = g.FontTexUvWhitePixel;
+        ImVec2 uv_white = GetFontTexUvWhitePixel();
         draw_list->PrimReserve(6, 6);
         draw_list->PrimVtx(tra, uv_white, hue_color32);
         draw_list->PrimVtx(trb, uv_white, hue_color32);
@@ -10851,9 +10857,11 @@ static float OffsetNormToPixels(const ImGuiColumnsSet* columns, float offset_nor
 
 static float PixelsToOffsetNorm(const ImGuiColumnsSet* columns, float offset)
 {
-    return (offset - columns->MinX) / (columns->MaxX - columns->MinX);
+    return offset / (columns->MaxX - columns->MinX);
 }
 
+static inline float GetColumnsRectHalfWidth() { return 4.0f; }
+
 static float GetDraggedColumnOffset(ImGuiColumnsSet* columns, int column_index)
 {
     // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing
@@ -10863,7 +10871,7 @@ static float GetDraggedColumnOffset(ImGuiColumnsSet* columns, int column_index)
     IM_ASSERT(column_index > 0); // We cannot drag column 0. If you get this assert you may have a conflict between the ID of your columns and another widgets.
     IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index));
 
-    float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x - window->Pos.x;
+    float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + GetColumnsRectHalfWidth() - window->Pos.x;
     x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing);
     if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths))
         x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing);
@@ -10936,7 +10944,7 @@ void ImGui::SetColumnOffset(int column_index, float offset)
 
     if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
         offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index));
-    columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset);
+    columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->MinX);
 
     if (preserve_width)
         SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width));
@@ -11000,7 +11008,7 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag
     // Set state for first column
     const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->Size.x -window->ScrollbarSizes.x);
     columns->MinX = window->DC.IndentX - g.Style.ItemSpacing.x; // Lock our horizontal range
-    //column->ColumnsMaxX = content_region_width - window->Scroll.x -((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarSize);// - window->WindowPadding().x;
+    //column->MaxX = content_region_width - window->Scroll.x - ((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarSize);// - window->WindowPadding().x;
     columns->MaxX = content_region_width - window->Scroll.x;
     columns->StartPosY = window->DC.CursorPos.y;
     columns->StartMaxPosX = window->DC.CursorMaxPos.x;
@@ -11028,7 +11036,7 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag
         ImGuiColumnData* column = &columns->Columns[n];
         float t = column->OffsetNorm;
         if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
-            t = ImMin(t, PixelsToOffsetNorm(columns, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - n)));
+            t = ImMin(t, PixelsToOffsetNorm(columns, (columns->MaxX - columns->MinX) - g.Style.ColumnsMinSpacing * (columns->Count - n)));
         column->OffsetNorm = t;
 
         if (n == columns_count)
@@ -11073,7 +11081,7 @@ void ImGui::EndColumns()
         {
             float x = window->Pos.x + GetColumnOffset(n);
             const ImGuiID column_id = columns->ID + ImGuiID(n);
-            const float column_hw = 4.0f; // Half-width for interaction
+            const float column_hw = GetColumnsRectHalfWidth(); // Half-width for interaction
             const ImRect column_rect(ImVec2(x - column_hw, y1), ImVec2(x + column_hw, y2));
             KeepAliveID(column_id);
             if (IsClippedEx(column_rect, column_id, false))
@@ -11085,8 +11093,6 @@ void ImGui::EndColumns()
                 ButtonBehavior(column_rect, column_id, &hovered, &held);
                 if (hovered || held)
                     g.MouseCursor = ImGuiMouseCursor_ResizeEW;
-                if (held && g.ActiveIdIsJustActivated)
-                    g.ActiveIdClickOffset.x -= column_hw; // Store from center of column line (we used a 8 wide rect for columns clicking). This is used by GetDraggedColumnOffset().
                 if (held && !(columns->Columns[n].Flags & ImGuiColumnsFlags_NoResize))
                     dragging_column = n;
             }
@@ -11478,7 +11484,7 @@ void ImGui::EndDragDropTarget()
 #if defined(_WIN32) && !defined(_WINDOWS_) && (!defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) || !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS))
 #undef WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN
-#include <windows.h>
+#include <Windows.h>
 #endif
 
 // Win32 API clipboard implementation
@@ -11612,7 +11618,6 @@ void ImGui::ShowMetricsWindow(bool* p_open)
                     return;
 
                 ImDrawList* overlay_draw_list = &GImGui->OverlayDrawList;   // Render additional visuals into the top-most draw list
-                overlay_draw_list->PushClipRectFullScreen();
                 int elem_offset = 0;
                 for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++)
                 {
@@ -11636,6 +11641,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
                     }
                     if (!pcmd_node_open)
                         continue;
+
+                    // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted.
                     ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
                     while (clipper.Step())
                         for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++)
@@ -11651,11 +11658,15 @@ void ImGui::ShowMetricsWindow(bool* p_open)
                             }
                             ImGui::Selectable(buf, false);
                             if (ImGui::IsItemHovered())
-                                overlay_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f, false);  // Add triangle without AA, more readable for large-thin triangle
+                            {
+                                ImDrawListFlags backup_flags = overlay_draw_list->Flags;
+                                overlay_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines at is more readable for very large and thin triangles.
+                                overlay_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f);
+                                overlay_draw_list->Flags = backup_flags;
+                            }
                         }
                     ImGui::TreePop();
                 }
-                overlay_draw_list->PopClipRect();
                 ImGui::TreePop();
             }
 

+ 44 - 33
3rdparty/ocornut-imgui/imgui.h

@@ -1,8 +1,8 @@
-// dear imgui, v1.53 WIP
+// dear imgui, v1.53
 // (headers)
 
 // See imgui.cpp file for documentation.
-// See ImGui::ShowTestWindow() in imgui_demo.cpp for demo code.
+// Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code.
 // Read 'Programmer guide' in imgui.cpp for notes on how to setup ImGui in your codebase.
 // Get latest version at https://github.com/ocornut/imgui
 
@@ -16,7 +16,7 @@
 #include <stddef.h>         // ptrdiff_t, NULL
 #include <string.h>         // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp
 
-#define IMGUI_VERSION       "1.53 WIP"
+#define IMGUI_VERSION       "1.53"
 
 // Define attributes of all API symbols declarations, e.g. for DLL under Windows.
 #ifndef IMGUI_API
@@ -26,12 +26,12 @@
 // Define assertion handler.
 #ifndef IM_ASSERT
 #include <assert.h>
-#define IM_ASSERT(_EXPR, ...)    assert(_EXPR)
+#define IM_ASSERT(_EXPR)    assert(_EXPR)
 #endif
 
 // Helpers
 // Some compilers support applying printf-style warnings to user functions.
-#if 0 // defined(__clang__) || defined(__GNUC__)
+#if defined(__clang__) || defined(__GNUC__)
 #define IM_FMTARGS(FMT)             __attribute__((format(printf, FMT, FMT+1)))
 #define IM_FMTLIST(FMT)             __attribute__((format(printf, FMT, 0)))
 #else
@@ -50,6 +50,7 @@ struct ImDrawChannel;               // Temporary storage for outputting drawing
 struct ImDrawCmd;                   // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call)
 struct ImDrawData;                  // All draw command lists required to render the frame
 struct ImDrawList;                  // A single draw command list (generally one per window)
+struct ImDrawListSharedData;        // Data shared among multiple draw lists (typically owned by parent ImGui context, but you may create one yourself)
 struct ImDrawVert;                  // A single vertex (20 bytes by default, override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT)
 struct ImFont;                      // Runtime data for a single font within a parent ImFontAtlas
 struct ImFontAtlas;                 // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader
@@ -78,6 +79,7 @@ typedef int ImGuiKey;               // enum: a key identifier (ImGui-side enum)
 typedef int ImGuiMouseCursor;       // enum: a mouse cursor identifier          // enum ImGuiMouseCursor_
 typedef int ImGuiStyleVar;          // enum: a variable identifier for styling  // enum ImGuiStyleVar_
 typedef int ImDrawCornerFlags;      // flags: for ImDrawList::AddRect*() etc.   // enum ImDrawCornerFlags_
+typedef int ImDrawListFlags;        // flags: for ImDrawList                    // enum ImDrawListFlags_
 typedef int ImGuiColorEditFlags;    // flags: for ColorEdit*(), ColorPicker*()  // enum ImGuiColorEditFlags_
 typedef int ImGuiColumnsFlags;      // flags: for *Columns*()                   // enum ImGuiColumnsFlags_
 typedef int ImGuiDragDropFlags;     // flags: for *DragDrop*()                  // enum ImGuiDragDropFlags_
@@ -90,7 +92,7 @@ typedef int ImGuiTreeNodeFlags;     // flags: for TreeNode*(),CollapsingHeader()
 typedef int ImGuiWindowFlags;       // flags: for Begin*()                      // enum ImGuiWindowFlags_
 typedef int (*ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data);
 typedef void (*ImGuiSizeConstraintCallback)(ImGuiSizeConstraintCallbackData* data);
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && !defined(__clang__)
 typedef unsigned __int64 ImU64;     // 64-bit unsigned integer
 #else
 typedef unsigned long long ImU64;   // 64-bit unsigned integer
@@ -134,7 +136,7 @@ namespace ImGui
     IMGUI_API void          Shutdown();
 
     // Demo, Debug, Informations
-    IMGUI_API void          ShowTestWindow(bool* p_open = NULL);        // create demo/test window. demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application!
+    IMGUI_API void          ShowDemoWindow(bool* p_open = NULL);        // create demo/test window (previously called ShowTestWindow). demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application!
     IMGUI_API void          ShowMetricsWindow(bool* p_open = NULL);     // create metrics window. display ImGui internals: draw commands (with individual draw calls and vertices), window list, basic internal state, etc.
     IMGUI_API void          ShowStyleEditor(ImGuiStyle* ref = NULL);    // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style)
     IMGUI_API bool          ShowStyleSelector(const char* label);
@@ -298,6 +300,7 @@ namespace ImGui
 
     // Widgets: Combo Box
     // The new BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it. 
+    // The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose.
     IMGUI_API bool          BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0);
     IMGUI_API void          EndCombo();
     IMGUI_API bool          Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1);
@@ -466,6 +469,7 @@ namespace ImGui
     IMGUI_API float         GetTime();
     IMGUI_API int           GetFrameCount();
     IMGUI_API ImDrawList*   GetOverlayDrawList();                                               // this draw list will be the last rendered one, useful to quickly draw overlays shapes/text
+    IMGUI_API ImDrawListSharedData* GetDrawListSharedData();
     IMGUI_API const char*   GetStyleColorName(ImGuiCol idx);
     IMGUI_API ImVec2        CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = +0.0f);   // utility to find the closest point the last item bounding rectangle edge. useful to visually link items
     IMGUI_API ImVec2        CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f);
@@ -566,6 +570,7 @@ enum ImGuiInputTextFlags_
     ImGuiInputTextFlags_AlwaysInsertMode    = 1 << 13,  // Insert mode
     ImGuiInputTextFlags_ReadOnly            = 1 << 14,  // Read-only mode
     ImGuiInputTextFlags_Password            = 1 << 15,  // Password mode, display all characters as '*'
+    ImGuiInputTextFlags_NoUndoRedo          = 1 << 16,  // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID().
     // [Internal]
     ImGuiInputTextFlags_Multiline           = 1 << 20   // For internal use by InputTextMultiline()
 };
@@ -618,7 +623,7 @@ enum ImGuiFocusedFlags_
 {
     ImGuiFocusedFlags_ChildWindows                  = 1 << 0,   // IsWindowFocused(): Return true if any children of the window is focused
     ImGuiFocusedFlags_RootWindow                    = 1 << 1,   // IsWindowFocused(): Test from root window (top most parent of the current hierarchy)
-    ImGuiFocusedFlags_RootAndChildWindows           = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows,
+    ImGuiFocusedFlags_RootAndChildWindows           = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows
 };
 
 // Flags for ImGui::IsItemHovered(), ImGui::IsWindowHovered()
@@ -757,7 +762,6 @@ enum ImGuiStyleVar_
     ImGuiStyleVar_IndentSpacing,       // float     IndentSpacing
     ImGuiStyleVar_GrabMinSize,         // float     GrabMinSize
     ImGuiStyleVar_ButtonTextAlign,     // ImVec2    ButtonTextAlign
-    ImGuiStyleVar_ViewId,              // uint8_t
     ImGuiStyleVar_Count_
 
     // Obsolete names (will be removed)
@@ -847,15 +851,14 @@ struct ImGuiStyle
     float       ColumnsMinSpacing;          // Minimum horizontal spacing between two columns
     float       ScrollbarSize;              // Width of the vertical scrollbar, Height of the horizontal scrollbar
     float       ScrollbarRounding;          // Radius of grab corners for scrollbar
-    float       GrabMinSize;                // Minimum width/height of a grab box for slider/scrollbar
-    float       ViewId;
+    float       GrabMinSize;                // Minimum width/height of a grab box for slider/scrollbar.
     float       GrabRounding;               // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
     ImVec2      ButtonTextAlign;            // Alignment of button text when button is larger than text. Defaults to (0.5f,0.5f) for horizontally+vertically centered.
     ImVec2      DisplayWindowPadding;       // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows.
     ImVec2      DisplaySafeAreaPadding;     // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
     bool        AntiAliasedLines;           // Enable anti-aliasing on lines/borders. Disable if you are really tight on CPU/GPU.
-    bool        AntiAliasedShapes;          // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.)
-    float       CurveTessellationTol;       // Tessellation tolerance. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
+    bool        AntiAliasedFill;            // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.)
+    float       CurveTessellationTol;       // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
     ImVec4      Colors[ImGuiCol_COUNT];
 
     IMGUI_API ImGuiStyle();
@@ -983,6 +986,7 @@ struct ImGuiIO
 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
 namespace ImGui
 {
+    static inline void  ShowTestWindow() { return ShowDemoWindow(); } // OBSOLETE 1.53+
     static inline bool  IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); } // OBSOLETE 1.53+
     static inline bool  IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); } // OBSOLETE 1.53+
     static inline void  SetNextWindowContentWidth(float width) { SetNextWindowContentSize(ImVec2(width, 0.0f)); } // OBSOLETE 1.53+ (nb: original version preserved last Y value set by SetNextWindowContentSize())
@@ -1003,7 +1007,7 @@ namespace ImGui
 //-----------------------------------------------------------------------------
 
 // Lightweight std::vector<> like class to avoid dragging dependencies (also: windows implementation of STL with debug enabled is absurdly slow, so let's bypass it so our code runs fast in debug).
-// Our implementation does NOT call c++ constructors because we don't use them in ImGui. Don't use this class as a straight std::vector replacement in your code!
+// Our implementation does NOT call C++ constructors/destructors. This is intentional and we do not require it. Do not use this class as a straight std::vector replacement in your code!
 template<typename T>
 class ImVector
 {
@@ -1016,8 +1020,8 @@ public:
     typedef value_type*         iterator;
     typedef const value_type*   const_iterator;
 
-    ImVector()                  { Size = Capacity = 0; Data = NULL; }
-    ~ImVector()                 { if (Data) ImGui::MemFree(Data); }
+    inline ImVector()           { Size = Capacity = 0; Data = NULL; }
+    inline ~ImVector()          { if (Data) ImGui::MemFree(Data); }
 
     inline bool                 empty() const                   { return Size == 0; }
     inline int                  size() const                    { return Size; }
@@ -1033,17 +1037,18 @@ public:
     inline const_iterator       end() const                     { return Data + Size; }
     inline value_type&          front()                         { IM_ASSERT(Size > 0); return Data[0]; }
     inline const value_type&    front() const                   { IM_ASSERT(Size > 0); return Data[0]; }
-    inline value_type&          back()                          { IM_ASSERT(Size > 0); return Data[Size-1]; }
-    inline const value_type&    back() const                    { IM_ASSERT(Size > 0); return Data[Size-1]; }
+    inline value_type&          back()                          { IM_ASSERT(Size > 0); return Data[Size - 1]; }
+    inline const value_type&    back() const                    { IM_ASSERT(Size > 0); return Data[Size - 1]; }
     inline void                 swap(ImVector<T>& rhs)          { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; }
 
-    inline int                  _grow_capacity(int sz) const  { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > sz ? new_capacity : sz; }
+    inline int                  _grow_capacity(int size) const  { int new_capacity = Capacity ? (Capacity + Capacity/2) : 8; return new_capacity > size ? new_capacity : size; }
 
     inline void                 resize(int new_size)            { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
     inline void                 resize(int new_size, const T& v){ if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) Data[n] = v; Size = new_size; }
     inline void                 reserve(int new_capacity)
     {
-        if (new_capacity <= Capacity) return;
+        if (new_capacity <= Capacity) 
+            return;
         T* new_data = (value_type*)ImGui::MemAlloc((size_t)new_capacity * sizeof(T));
         if (Data)
             memcpy(new_data, Data, (size_t)Size * sizeof(T));
@@ -1052,12 +1057,12 @@ public:
         Capacity = new_capacity;
     }
 
-    inline void                 push_back(const value_type& v)  { if (Size == Capacity) reserve(_grow_capacity(Size+1)); Data[Size++] = v; }
+    inline void                 push_back(const value_type& v)  { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); Data[Size++] = v; }
     inline void                 pop_back()                      { IM_ASSERT(Size > 0); Size--; }
     inline void                 push_front(const value_type& v) { if (Size == 0) push_back(v); else insert(Data, v); }
 
     inline iterator             erase(const_iterator it)        { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(value_type)); Size--; return Data + off; }
-    inline iterator             insert(const_iterator it, const value_type& v)  { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(value_type)); Data[off] = v; Size++; return Data + off; }
+    inline iterator             insert(const_iterator it, const value_type& v)  { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(value_type)); Data[off] = v; Size++; return Data + off; }
     inline bool                 contains(const value_type& v) const             { const T* data = Data;  const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; }
 };
 
@@ -1325,9 +1330,8 @@ struct ImDrawCmd
     ImTextureID     TextureId;              // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas.
     ImDrawCallback  UserCallback;           // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally.
     void*           UserCallbackData;       // The draw callback code can access this.
-    unsigned char   ViewId;
 
-    ImDrawCmd() { ElemCount = 0; ClipRect.x = ClipRect.y = -8192.0f; ClipRect.z = ClipRect.w = +8192.0f; TextureId = NULL; UserCallback = NULL; UserCallbackData = NULL; ViewId = 0; }
+    ImDrawCmd() { ElemCount = 0; ClipRect.x = ClipRect.y = ClipRect.z = ClipRect.w = 0.0f; TextureId = NULL; UserCallback = NULL; UserCallbackData = NULL; }
 };
 
 // Vertex index (override with '#define ImDrawIdx unsigned int' inside in imconfig.h)
@@ -1372,21 +1376,28 @@ enum ImDrawCornerFlags_
     ImDrawCornerFlags_All       = 0xF     // In your function calls you may use ~0 (= all bits sets) instead of ImDrawCornerFlags_All, as a convenience
 };
 
+enum ImDrawListFlags_
+{
+    ImDrawListFlags_AntiAliasedLines = 1 << 0,
+    ImDrawListFlags_AntiAliasedFill  = 1 << 1
+};
+
 // Draw command list
 // This is the low-level list of polygons that ImGui functions are filling. At the end of the frame, all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering.
-// At the moment, each ImGui window contains its own ImDrawList but they could potentially be merged in the future.
-// If you want to add custom rendering within a window, you can use ImGui::GetWindowDrawList() to access the current draw list and add your own primitives.
+// Each ImGui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to access the current window draw list and draw custom primitives.
 // You can interleave normal ImGui:: calls and adding primitives to the current draw list.
 // All positions are generally in pixel coordinates (top-left at (0,0), bottom-right at io.DisplaySize), however you are totally free to apply whatever transformation matrix to want to the data (if you apply such transformation you'll want to apply it to ClipRect as well)
-// Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions).
+// Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects.
 struct ImDrawList
 {
     // This is what you have to render
-    ImVector<ImDrawCmd>     CmdBuffer;          // Commands. Typically 1 command = 1 GPU draw call.
+    ImVector<ImDrawCmd>     CmdBuffer;          // Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback.
     ImVector<ImDrawIdx>     IdxBuffer;          // Index buffer. Each command consume ImDrawCmd::ElemCount of those
     ImVector<ImDrawVert>    VtxBuffer;          // Vertex buffer.
 
     // [Internal, used while building lists]
+    ImDrawListFlags         Flags;              // Flags, you may poke into these to adjust anti-aliasing settings per-primitive.
+    const ImDrawListSharedData* _Data;          // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context)
     const char*             _OwnerName;         // Pointer to owner window's name for debugging
     unsigned int            _VtxCurrentIdx;     // [Internal] == VtxBuffer.Size
     ImDrawVert*             _VtxWritePtr;       // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much)
@@ -1398,7 +1409,7 @@ struct ImDrawList
     int                     _ChannelsCount;     // [Internal] number of active channels (1+)
     ImVector<ImDrawChannel> _Channels;          // [Internal] draw channels for columns API (not resized down so _ChannelsCount may be smaller than _Channels.Size)
 
-    ImDrawList()  { _OwnerName = NULL; Clear(); }
+    ImDrawList(const ImDrawListSharedData* shared_data) { _Data = shared_data; _OwnerName = NULL; Clear(); }
     ~ImDrawList() { ClearFreeMemory(); }
     IMGUI_API void  PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false);  // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)
     IMGUI_API void  PushClipRectFullScreen();
@@ -1424,16 +1435,16 @@ struct ImDrawList
     IMGUI_API void  AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a = ImVec2(0,0), const ImVec2& uv_b = ImVec2(1,1), ImU32 col = 0xFFFFFFFF);
     IMGUI_API void  AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a = ImVec2(0,0), const ImVec2& uv_b = ImVec2(1,0), const ImVec2& uv_c = ImVec2(1,1), const ImVec2& uv_d = ImVec2(0,1), ImU32 col = 0xFFFFFFFF);
     IMGUI_API void  AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, int rounding_corners = ImDrawCornerFlags_All);
-    IMGUI_API void  AddPolyline(const ImVec2* points, const int num_points, ImU32 col, bool closed, float thickness, bool anti_aliased);
-    IMGUI_API void  AddConvexPolyFilled(const ImVec2* points, const int num_points, ImU32 col, bool anti_aliased);
+    IMGUI_API void  AddPolyline(const ImVec2* points, const int num_points, ImU32 col, bool closed, float thickness);
+    IMGUI_API void  AddConvexPolyFilled(const ImVec2* points, const int num_points, ImU32 col);
     IMGUI_API void  AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments = 0);
 
     // Stateful path API, add points then finish with PathFill() or PathStroke()
     inline    void  PathClear()                                                 { _Path.resize(0); }
     inline    void  PathLineTo(const ImVec2& pos)                               { _Path.push_back(pos); }
     inline    void  PathLineToMergeDuplicate(const ImVec2& pos)                 { if (_Path.Size == 0 || memcmp(&_Path[_Path.Size-1], &pos, 8) != 0) _Path.push_back(pos); }
-    inline    void  PathFillConvex(ImU32 col)                                   { AddConvexPolyFilled(_Path.Data, _Path.Size, col, true); PathClear(); }
-    inline    void  PathStroke(ImU32 col, bool closed, float thickness = 1.0f)  { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness, true); PathClear(); }
+    inline    void  PathFillConvex(ImU32 col)                                   { AddConvexPolyFilled(_Path.Data, _Path.Size, col); PathClear(); }
+    inline    void  PathStroke(ImU32 col, bool closed, float thickness = 1.0f)  { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); PathClear(); }
     IMGUI_API void  PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments = 10);
     IMGUI_API void  PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12);                                // Use precomputed angles for a 12 steps circle
     IMGUI_API void  PathBezierCurveTo(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, int num_segments = 0);

+ 53 - 26
3rdparty/ocornut-imgui/imgui_demo.cpp

@@ -1,22 +1,22 @@
-// dear imgui, v1.53 WIP
+// dear imgui, v1.53
 // (demo code)
 
 // Message to the person tempted to delete this file when integrating ImGui into their code base:
 // Don't do it! Do NOT remove this file from your project! It is useful reference code that you and other users will want to refer to.
-// Everything in this file will be stripped out by the linker if you don't call ImGui::ShowTestWindow().
-// During development, you can call ImGui::ShowTestWindow() in your code to learn about various features of ImGui. Have it wired in a debug menu!
+// Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow().
+// During development, you can call ImGui::ShowDemoWindow() in your code to learn about various features of ImGui. Have it wired in a debug menu!
 // Removing this file from your project is hindering access to documentation for everyone in your team, likely leading you to poorer usage of the library.
-// Note that you can #define IMGUI_DISABLE_TEST_WINDOWS in imconfig.h for the same effect.
-// If you want to link core ImGui in your public builds but not those test windows, #define IMGUI_DISABLE_TEST_WINDOWS in imconfig.h and those functions will be empty.
-// For any other case, if you have ImGui available you probably want this to be available for reference and execution.
+// Note that you can #define IMGUI_DISABLE_DEMO_WINDOWS in imconfig.h for the same effect.
+// If you want to link core ImGui in your final builds but not those demo windows, #define IMGUI_DISABLE_DEMO_WINDOWS in imconfig.h and those functions will be empty.
+// In other situation, when you have ImGui available you probably want this to be available for reference and execution.
 // Thank you,
 // -Your beloved friend, imgui_demo.cpp (that you won't delete)
 
-// Message to beginner C/C++ programmer about the meaning of 'static': in this demo code, we frequently we use 'static' variables inside functions. 
-// We do this as a way to gather code and data in the same place, make the demo code faster to read, faster to write, and smaller. A static variable persist across calls, 
-// so it is essentially like a global variable but declared inside the scope of the function.
+// Message to beginner C/C++ programmers. About the meaning of 'static': in this demo code, we frequently we use 'static' variables inside functions. 
+// We do this as a way to gather code and data in the same place, just to make the demo code faster to read, faster to write, and use less code. 
+// A static variable persist across calls, so it is essentially like a global variable but declared inside the scope of the function. 
 // It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be reentrant or used in threads.
-// This may be a pattern you want to use in your code (simple is beautiful!), but most of the real data you would be editing is likely to be stored outside your function.
+// This might be a pattern you occasionally want to use in your code, but most of the real data you would be editing is likely to be stored outside your function.
 
 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
 #define _CRT_SECURE_NO_WARNINGS
@@ -52,25 +52,28 @@
 #pragma GCC diagnostic ignored "-Wdouble-promotion"             // warning: implicit conversion from 'float' to 'double' when passing argument to function
 #pragma GCC diagnostic ignored "-Wconversion"                   // warning: conversion to 'xxxx' from 'xxxx' may alter its value
 #if (__GNUC__ >= 6)
-#pragma GCC diagnostic ignored "-Wmisleading-indentation"       // warning: this 'if' clause does not guard this statement      // GCC 6.0+ only. See #883 on github.
+#pragma GCC diagnostic ignored "-Wmisleading-indentation"       // warning: this 'if' clause does not guard this statement      // GCC 6.0+ only. See #883 on GitHub.
 #endif
 #endif
 
-// Play it nice with Windows users. Notepad in 2015 still doesn't display text data with Unix-style \n.
+// Play it nice with Windows users. Notepad in 2017 still doesn't display text data with Unix-style \n.
 #ifdef _WIN32
 #define IM_NEWLINE "\r\n"
 #else
 #define IM_NEWLINE "\n"
 #endif
 
-#define IM_ARRAYSIZE(_ARR)  ((int)(sizeof(_ARR)/sizeof(*_ARR)))
 #define IM_MAX(_A,_B)       (((_A) >= (_B)) ? (_A) : (_B))
 
 //-----------------------------------------------------------------------------
 // DEMO CODE
 //-----------------------------------------------------------------------------
 
-#ifndef IMGUI_DISABLE_TEST_WINDOWS
+#if !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && defined(IMGUI_DISABLE_TEST_WINDOWS) && !defined(IMGUI_DISABLE_DEMO_WINDOWS)   // Obsolete name since 1.53, TEST->DEMO
+#define IMGUI_DISABLE_DEMO_WINDOWS
+#endif
+
+#if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
 
 static void ShowExampleAppConsole(bool* p_open);
 static void ShowExampleAppLog(bool* p_open);
@@ -121,7 +124,7 @@ void ImGui::ShowUserGuide()
 }
 
 // Demonstrate most ImGui features (big function!)
-void ImGui::ShowTestWindow(bool* p_open)
+void ImGui::ShowDemoWindow(bool* p_open)
 {
     // Examples apps
     static bool show_app_main_menu_bar = false;
@@ -231,7 +234,7 @@ void ImGui::ShowTestWindow(bool* p_open)
     ImGui::Spacing();
     if (ImGui::CollapsingHeader("Help"))
     {
-        ImGui::TextWrapped("This window is being created by the ShowTestWindow() function. Please refer to the code in imgui_demo.cpp for reference.\n\n");
+        ImGui::TextWrapped("This window is being created by the ShowDemoWindow() function. Please refer to the code in imgui_demo.cpp for reference.\n\n");
         ImGui::Text("USER GUIDE:");
         ImGui::ShowUserGuide();
     }
@@ -319,12 +322,28 @@ void ImGui::ShowTestWindow(bool* p_open)
 
             ImGui::LabelText("label", "Value");
 
-            static int item = 1;
-            ImGui::Combo("combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");   // Combo using values packed in a single constant string (for really quick combo)
-
-            const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO", "PPPP", "QQQQQQQQQQ", "RRR", "SSSS" };
-            static int item2 = -1;
-            ImGui::Combo("combo scroll", &item2, items, IM_ARRAYSIZE(items));   // Combo using proper array. You can also pass a callback to retrieve array value, no need to create/copy an array just for that.
+            {
+                // Simplified one-liner Combo() API, using values packed in a single constant string
+                static int current_item_1 = 1;
+                ImGui::Combo("combo", &current_item_1, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
+                //ImGui::Combo("combo w/ array of char*", &current_item_2_idx, items, IM_ARRAYSIZE(items));   // Combo using proper array. You can also pass a callback to retrieve array value, no need to create/copy an array just for that.
+
+                // General BeginCombo() API, you have full control over your selection data and display type
+                const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO", "PPPP", "QQQQQQQQQQ", "RRR", "SSSS" };
+                static const char* current_item_2 = NULL;
+                if (ImGui::BeginCombo("combo 2", current_item_2)) // The second parameter is the label previewed before opening the combo.
+                {
+                    for (int n = 0; n < IM_ARRAYSIZE(items); n++)
+                    {
+                        bool is_selected = (current_item_2 == items[n]); // You can store your selection however you want, outside or inside your objects
+                        if (ImGui::Selectable(items[n], is_selected))
+                            current_item_2 = items[n];
+                        if (is_selected)
+                            ImGui::SetItemDefaultFocus();   // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch)
+                    }
+                    ImGui::EndCombo();
+                }
+            }
 
             {
                 static char str0[128] = "Hello, world!";
@@ -1304,7 +1323,8 @@ void ImGui::ShowTestWindow(bool* p_open)
                     if (n > 0) ImGui::SameLine();
                     ImGui::PushID(n + line * 1000);
                     char num_buf[16];
-                    const char* label = (!(n%15)) ? "FizzBuzz" : (!(n%3)) ? "Fizz" : (!(n%5)) ? "Buzz" : (sprintf(num_buf, "%d", n), num_buf);
+                    sprintf(num_buf, "%d", n);
+                    const char* label = (!(n%15)) ? "FizzBuzz" : (!(n%3)) ? "Fizz" : (!(n%5)) ? "Buzz" : num_buf;
                     float hue = n*0.05f;
                     ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f));
                     ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f));
@@ -1734,7 +1754,10 @@ void ImGui::ShowTestWindow(bool* p_open)
 
         if (ImGui::TreeNode("Keyboard & Mouse State"))
         {
-            ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
+            if (ImGui::IsMousePosValid())
+                ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
+            else
+                ImGui::Text("Mouse pos: <INVALID>");
             ImGui::Text("Mouse down:");     for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseDownDuration[i] >= 0.0f)   { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
             ImGui::Text("Mouse clicked:");  for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseClicked(i))          { ImGui::SameLine(); ImGui::Text("b%d", i); }
             ImGui::Text("Mouse dbl-clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); }
@@ -1907,6 +1930,8 @@ void ImGui::ShowTestWindow(bool* p_open)
     ImGui::End();
 }
 
+// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
+// Here we use the simplified Combo() api that packs items into a single literal string. Useful for quick combo boxes where the choices are known locally.
 bool ImGui::ShowStyleSelector(const char* label)
 {
     static int style_idx = 0;
@@ -1923,6 +1948,8 @@ bool ImGui::ShowStyleSelector(const char* label)
     return false;
 }
 
+// Demo helper function to select among loaded fonts.
+// Here we use the regular BeginCombo()/EndCombo() api which is more the more flexible one.
 void ImGui::ShowFontSelector(const char* label)
 {
     ImGuiIO& io = ImGui::GetIO();
@@ -1983,7 +2010,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
     if (ImGui::TreeNode("Rendering"))
     {
         ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); ImGui::SameLine(); ShowHelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
-        ImGui::Checkbox("Anti-aliased shapes", &style.AntiAliasedShapes);
+        ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
         ImGui::PushItemWidth(100);
         ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, NULL, 2.0f);
         if (style.CurveTessellationTol < 0.0f) style.CurveTessellationTol = 0.10f;
@@ -3033,7 +3060,7 @@ static void ShowExampleAppLongText(bool* p_open)
 // End of Demo code
 #else
 
-void ImGui::ShowTestWindow(bool*) {}
+void ImGui::ShowDemoWindow(bool*) {}
 void ImGui::ShowUserGuide() {}
 void ImGui::ShowStyleEditor(ImGuiStyle*) {}
 

+ 43 - 54
3rdparty/ocornut-imgui/imgui_draw.cpp

@@ -1,4 +1,4 @@
-// dear imgui, v1.53 WIP
+// dear imgui, v1.53
 // (drawing and font code)
 
 // Contains implementation for
@@ -15,7 +15,6 @@
 
 #include "imgui.h"
 #define IMGUI_DEFINE_MATH_OPERATORS
-#define IMGUI_DEFINE_PLACEMENT_NEW
 #include "imgui_internal.h"
 
 #include <stdio.h>      // vsnprintf, sscanf, printf
@@ -43,6 +42,7 @@
 #pragma clang diagnostic ignored "-Wfloat-equal"            // warning : comparing floating point with == or != is unsafe   // storing and comparing against same constants ok.
 #pragma clang diagnostic ignored "-Wglobal-constructors"    // warning : declaration requires a global destructor           // similar to above, not sure what the exact difference it.
 #pragma clang diagnostic ignored "-Wsign-conversion"        // warning : implicit conversion changes signedness             //
+#pragma clang diagnostic ignored "-Wcomma"                  // warning : possible misuse of comma operator here             //
 #if __has_warning("-Wreserved-id-macro")
 #pragma clang diagnostic ignored "-Wreserved-id-macro"      // warning : macro name is a reserved identifier                //
 #endif
@@ -78,6 +78,7 @@ namespace IMGUI_STB_NAMESPACE
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wunused-function"
 #pragma clang diagnostic ignored "-Wmissing-prototypes"
+#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
 #endif
 
 #ifdef __GNUC__
@@ -224,6 +225,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
     colors[ImGuiCol_DragDropTarget]         = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
 }
 
+// Those light colors are better suited with a thicker font than the default one + FrameBorder
 void ImGui::StyleColorsLight(ImGuiStyle* dst)
 {
     ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
@@ -277,16 +279,34 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
 }
 
 //-----------------------------------------------------------------------------
-// ImDrawList
+// ImDrawListData
 //-----------------------------------------------------------------------------
 
-static const ImVec4 GNullClipRect(-8192.0f, -8192.0f, +8192.0f, +8192.0f); // Large values that are easy to encode in a few bits+shift
+ImDrawListSharedData::ImDrawListSharedData()
+{
+    Font = NULL;
+    FontSize = 0.0f;
+    CurveTessellationTol = 0.0f;
+    ClipRectFullscreen = ImVec4(-8192.0f, -8192.0f, +8192.0f, +8192.0f);
+    
+    // Const data
+    for (int i = 0; i < IM_ARRAYSIZE(CircleVtx12); i++)
+    {
+        const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(CircleVtx12);
+        CircleVtx12[i] = ImVec2(cosf(a), sinf(a));
+    }
+}
+
+//-----------------------------------------------------------------------------
+// ImDrawList
+//-----------------------------------------------------------------------------
 
 void ImDrawList::Clear()
 {
     CmdBuffer.resize(0);
     IdxBuffer.resize(0);
     VtxBuffer.resize(0);
+    Flags = ImDrawListFlags_AntiAliasedLines | ImDrawListFlags_AntiAliasedFill;
     _VtxCurrentIdx = 0;
     _VtxWritePtr = NULL;
     _IdxWritePtr = NULL;
@@ -321,7 +341,7 @@ void ImDrawList::ClearFreeMemory()
 }
 
 // Using macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug builds
-#define GetCurrentClipRect()    (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1]  : GNullClipRect)
+#define GetCurrentClipRect()    (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1]  : _Data->ClipRectFullscreen)
 #define GetCurrentTextureId()   (_TextureIdStack.Size ? _TextureIdStack.Data[_TextureIdStack.Size-1] : NULL)
 
 void ImDrawList::AddDrawCmd()
@@ -329,7 +349,6 @@ void ImDrawList::AddDrawCmd()
     ImDrawCmd draw_cmd;
     draw_cmd.ClipRect = GetCurrentClipRect();
     draw_cmd.TextureId = GetCurrentTextureId();
-    draw_cmd.ViewId = (unsigned char)(GImGui->Style.ViewId);
 
     IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w);
     CmdBuffer.push_back(draw_cmd);
@@ -413,8 +432,7 @@ void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_
 
 void ImDrawList::PushClipRectFullScreen()
 {
-    PushClipRect(ImVec2(GNullClipRect.x, GNullClipRect.y), ImVec2(GNullClipRect.z, GNullClipRect.w));
-    //PushClipRect(GetVisibleRect());   // FIXME-OPT: This would be more correct but we're not supposed to access ImGuiContext from here?
+    PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w));
 }
 
 void ImDrawList::PopClipRect()
@@ -465,7 +483,6 @@ void ImDrawList::ChannelsSplit(int channels_count)
             ImDrawCmd draw_cmd;
             draw_cmd.ClipRect = _ClipRectStack.back();
             draw_cmd.TextureId = _TextureIdStack.back();
-            draw_cmd.ViewId = (unsigned char)(GImGui->Style.ViewId);
             _Channels[i].CmdBuffer.push_back(draw_cmd);
         }
     }
@@ -535,7 +552,7 @@ void ImDrawList::PrimReserve(int idx_count, int vtx_count)
 // Fully unrolled with inline call to keep our debug builds decently fast.
 void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col)
 {
-    ImVec2 b(c.x, a.y), d(a.x, c.y), uv(GImGui->FontTexUvWhitePixel);
+    ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel);
     ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
     _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
     _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
@@ -578,21 +595,19 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c
 }
 
 // TODO: Thickness anti-aliased lines cap are missing their AA fringe.
-void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness, bool anti_aliased)
+void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness)
 {
     if (points_count < 2)
         return;
 
-    const ImVec2 uv = GImGui->FontTexUvWhitePixel;
-    anti_aliased &= GImGui->Style.AntiAliasedLines;
-    //if (ImGui::GetIO().KeyCtrl) anti_aliased = false; // Debug
+    const ImVec2 uv = _Data->TexUvWhitePixel;
 
     int count = points_count;
     if (!closed)
         count = points_count-1;
 
     const bool thick_line = thickness > 1.0f;
-    if (anti_aliased)
+    if (Flags & ImDrawListFlags_AntiAliasedLines)
     {
         // Anti-aliased stroke
         const float AA_SIZE = 1.0f;
@@ -759,13 +774,11 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
     }
 }
 
-void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col, bool anti_aliased)
+void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
 {
-    const ImVec2 uv = GImGui->FontTexUvWhitePixel;
-    anti_aliased &= GImGui->Style.AntiAliasedShapes;
-    //if (ImGui::GetIO().KeyCtrl) anti_aliased = false; // Debug
+    const ImVec2 uv = _Data->TexUvWhitePixel;
 
-    if (anti_aliased)
+    if (Flags & ImDrawListFlags_AntiAliasedFill)
     {
         // Anti-aliased Fill
         const float AA_SIZE = 1.0f;
@@ -844,20 +857,6 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
 
 void ImDrawList::PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12)
 {
-    static ImVec2 circle_vtx[12];
-    static bool circle_vtx_builds = false;
-    const int circle_vtx_count = IM_ARRAYSIZE(circle_vtx);
-    if (!circle_vtx_builds)
-    {
-        for (int i = 0; i < circle_vtx_count; i++)
-        {
-            const float a = ((float)i / (float)circle_vtx_count) * 2*IM_PI;
-            circle_vtx[i].x = cosf(a);
-            circle_vtx[i].y = sinf(a);
-        }
-        circle_vtx_builds = true;
-    }
-
     if (radius == 0.0f || a_min_of_12 > a_max_of_12)
     {
         _Path.push_back(centre);
@@ -866,7 +865,7 @@ void ImDrawList::PathArcToFast(const ImVec2& centre, float radius, int a_min_of_
     _Path.reserve(_Path.Size + (a_max_of_12 - a_min_of_12 + 1));
     for (int a = a_min_of_12; a <= a_max_of_12; a++)
     {
-        const ImVec2& c = circle_vtx[a % circle_vtx_count];
+        const ImVec2& c = _Data->CircleVtx12[a % IM_ARRAYSIZE(_Data->CircleVtx12)];
         _Path.push_back(ImVec2(centre.x + c.x * radius, centre.y + c.y * radius));
     }
 }
@@ -918,7 +917,7 @@ void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImV
     if (num_segments == 0)
     {
         // Auto-tessellated
-        PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, GImGui->Style.CurveTessellationTol, 0);
+        PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0);
     }
     else
     {
@@ -1000,7 +999,7 @@ void ImDrawList::AddRectFilledMultiColor(const ImVec2& a, const ImVec2& c, ImU32
     if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0)
         return;
 
-    const ImVec2 uv = GImGui->FontTexUvWhitePixel;
+    const ImVec2 uv = _Data->TexUvWhitePixel;
     PrimReserve(6, 4);
     PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2));
     PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+3));
@@ -1096,12 +1095,11 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos,
     if (text_begin == text_end)
         return;
 
-    // IMPORTANT: This is one of the few instance of breaking the encapsulation of ImDrawList, as we pull this from ImGui state, but it is just SO useful.
-    // Might just move Font/FontSize to ImDrawList?
+    // Pull default font/size from the shared ImDrawListSharedData instance
     if (font == NULL)
-        font = GImGui->Font;
+        font = _Data->Font;
     if (font_size == 0.0f)
-        font_size = GImGui->FontSize;
+        font_size = _Data->FontSize;
 
     IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back());  // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
 
@@ -1258,8 +1256,8 @@ void ImGui::ShadeVertsLinearUV(ImDrawVert* vert_start, ImDrawVert* vert_end, con
     const ImVec2 size = b - a;
     const ImVec2 uv_size = uv_b - uv_a;
     const ImVec2 scale = ImVec2(
-        size.x ? (uv_size.x / size.x) : 0.0f,
-        size.y ? (uv_size.y / size.y) : 0.0f);
+        size.x != 0.0f ? (uv_size.x / size.x) : 0.0f,
+        size.y != 0.0f ? (uv_size.y / size.y) : 0.0f);
 
     if (clamp)
     {
@@ -1406,10 +1404,7 @@ void    ImFontAtlas::ClearTexData()
 void    ImFontAtlas::ClearFonts()
 {
     for (int i = 0; i < Fonts.Size; i++)
-    {
-        Fonts[i]->~ImFont();
-        ImGui::MemFree(Fonts[i]);
-    }
+        IM_DELETE(Fonts[i]);
     Fonts.clear();
 }
 
@@ -1464,15 +1459,9 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
 
     // Create new font
     if (!font_cfg->MergeMode)
-    {
-        ImFont* font = (ImFont*)ImGui::MemAlloc(sizeof(ImFont));
-        IM_PLACEMENT_NEW(font) ImFont();
-        Fonts.push_back(font);
-    }
+        Fonts.push_back(IM_NEW(ImFont));
     else
-    {
         IM_ASSERT(!Fonts.empty()); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
-    }
 
     ConfigData.push_back(*font_cfg);
     ImFontConfig& new_font_cfg = ConfigData.back();

+ 31 - 14
3rdparty/ocornut-imgui/imgui_internal.h

@@ -1,4 +1,4 @@
-// dear imgui, v1.53 WIP
+// dear imgui, v1.53
 // (internals)
 
 // You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
@@ -103,15 +103,15 @@ IMGUI_API void          ImTriangleBarycentricCoords(const ImVec2& a, const ImVec
 
 // Helpers: String
 IMGUI_API int           ImStricmp(const char* str1, const char* str2);
-IMGUI_API int           ImStrnicmp(const char* str1, const char* str2, int count);
-IMGUI_API void          ImStrncpy(char* dst, const char* src, int count);
+IMGUI_API int           ImStrnicmp(const char* str1, const char* str2, size_t count);
+IMGUI_API void          ImStrncpy(char* dst, const char* src, size_t count);
 IMGUI_API char*         ImStrdup(const char* str);
 IMGUI_API char*         ImStrchrRange(const char* str_begin, const char* str_end, char c);
 IMGUI_API int           ImStrlenW(const ImWchar* str);
 IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line
 IMGUI_API const char*   ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end);
-IMGUI_API int           ImFormatString(char* buf, int buf_size, const char* fmt, ...) IM_FMTARGS(3);
-IMGUI_API int           ImFormatStringV(char* buf, int buf_size, const char* fmt, va_list args) IM_FMTLIST(3);
+IMGUI_API int           ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3);
+IMGUI_API int           ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3);
 
 // Helpers: Math
 // We are keeping those not leaking to the user by default, in the case the user has implicit cast operators between ImVec2 and its own types (when IM_VEC2_CLASS_EXTRA is defined)
@@ -160,10 +160,12 @@ static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs)
 
 // We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
 // Defining a custom placement new() with a dummy parameter allows us to bypass including <new> which on some platforms complains when user has disabled exceptions.
-struct ImPlacementNewDummy {};
-inline void* operator new(size_t, ImPlacementNewDummy, void* ptr) { return ptr; }
-inline void operator delete(void*, ImPlacementNewDummy, void*) {}
-#define IM_PLACEMENT_NEW(_PTR)  new(ImPlacementNewDummy(), _PTR)
+struct ImNewPlacementDummy {};
+inline void* operator   new(size_t, ImNewPlacementDummy, void* ptr) { return ptr; }
+inline void  operator   delete(void*, ImNewPlacementDummy, void*)   {} // This is only required so we can use the symetrical new()
+#define IM_PLACEMENT_NEW(_PTR)              new(ImNewPlacementDummy(), _PTR)
+#define IM_NEW(_TYPE)                       new(ImNewPlacementDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
+template <typename T> void IM_DELETE(T*& p) { if (p) { p->~T(); ImGui::MemFree(p); p = NULL; } }
 
 //-----------------------------------------------------------------------------
 // Types
@@ -230,7 +232,7 @@ enum ImGuiAxis
 {
     ImGuiAxis_None = -1,
     ImGuiAxis_X = 0,
-    ImGuiAxis_Y = 1,
+    ImGuiAxis_Y = 1
 };
 
 enum ImGuiPlotType
@@ -453,6 +455,21 @@ struct ImGuiColumnsSet
     }
 };
 
+struct ImDrawListSharedData
+{
+    ImVec2          TexUvWhitePixel;            // UV of white pixel in the atlas
+    ImFont*         Font;                       // Current/default font (optional, for simplified AddText overload)
+    float           FontSize;                   // Current/default font size (optional, for simplified AddText overload)
+    float           CurveTessellationTol;
+    ImVec4          ClipRectFullscreen;         // Value for PushClipRectFullscreen()
+
+    // Const data
+    // FIXME: Bake rounded corners fill/borders in atlas
+    ImVec2          CircleVtx12[12];
+
+    ImDrawListSharedData();
+};
+
 // Main state for ImGui
 struct ImGuiContext
 {
@@ -462,7 +479,7 @@ struct ImGuiContext
     ImFont*                 Font;                               // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back()
     float                   FontSize;                           // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window.
     float                   FontBaseSize;                       // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height.
-    ImVec2                  FontTexUvWhitePixel;                // (Shortcut) == Font->TexUvWhitePixel
+    ImDrawListSharedData    DrawListSharedData;
 
     float                   Time;
     int                     FrameCount;
@@ -574,12 +591,11 @@ struct ImGuiContext
     int                     WantTextInputNextFrame;
     char                    TempBuffer[1024*3+1];               // temporary text buffer
 
-    ImGuiContext()
+    ImGuiContext() : OverlayDrawList(NULL)
     {
         Initialized = false;
         Font = NULL;
         FontSize = FontBaseSize = 0.0f;
-        FontTexUvWhitePixel = ImVec2(0.0f, 0.0f);
 
         Time = 0.0f;
         FrameCount = 0;
@@ -639,6 +655,7 @@ struct ImGuiContext
         OsImePosRequest = OsImePosSet = ImVec2(-1.0f, -1.0f);
 
         ModalWindowDarkeningRatio = 0.0f;
+        OverlayDrawList._Data = &DrawListSharedData;
         OverlayDrawList._OwnerName = "##Overlay"; // Give it a name for debugging
         MouseCursor = ImGuiMouseCursor_Arrow;
         memset(MouseCursorData, 0, sizeof(MouseCursorData));
@@ -805,7 +822,7 @@ struct IMGUI_API ImGuiWindow
     int                     FocusIdxTabRequestNext;             // "
 
 public:
-    ImGuiWindow(const char* name);
+    ImGuiWindow(ImGuiContext* context, const char* name);
     ~ImGuiWindow();
 
     ImGuiID     GetID(const char* str, const char* str_end = NULL);

+ 137 - 267
tools-imgui/level_editor.cpp

@@ -16,7 +16,6 @@
 #include "core/json/json.h"
 #include "core/json/sjson.h"
 #include "core/json/json_object.h"
-#include "core/network/ip_address.h"
 #include "core/network/socket.h"
 #include "core/strings/dynamic_string.h"
 #include "device/device.h"
@@ -35,19 +34,6 @@
 
 #include <sys/time.h>
 
-#define MAIN_MENU_HEIGHT 24
-#define TOOLBAR_HEIGHT 24
-
-#define Y_OFFSET (MAIN_MENU_HEIGHT + TOOLBAR_HEIGHT)
-
-#define SCENE_VIEW_WIDTH 640 /*1280*/
-#define SCENE_VIEW_HEIGHT 480 /*720*/
-
-#define FILE_BROWSER_WIDTH 640
-#define FILE_BROWSER_HEIGHT 480
-
-#define IM_ARRAYSIZE(_ARR)  ((int)(sizeof(_ARR)/sizeof(*_ARR)))
-
 namespace { const crown::log_internal::System LEVEL_EDITOR = { "LevelEditor" }; }
 
 namespace crown
@@ -55,43 +41,6 @@ namespace crown
 static u16 _width = 1280;
 static u16 _height = 720;
 
-//-----------------------------------------------------------------------------
-struct Console
-{
-	// Console
-	TCPSocket _client;
-	Vector<ImGui::ConsoleLog> _console_items;
-	Vector<DynamicString> _console_history;
-	Vector<DynamicString> _console_commands;
-	bool _console_open;
-
-	Console() : _console_items(default_allocator())
-		, _console_history(default_allocator())
-		, _console_commands(default_allocator())
-		, _console_open(true)
-	{
-		_client.connect(IP_ADDRESS_LOOPBACK, CROWN_DEFAULT_CONSOLE_PORT);
-	}
-
-	~Console()
-	{
-		_client.close();
-	}
-
-	void draw()
-	{
-		if (ImGui::BeginDock("Console", &_console_open))
-		{
-			ImGui::console_draw(_client
-				, _console_items
-				, _console_history
-				, _console_commands
-				);
-		}
-		ImGui::EndDock();
-	}
-};
-
 //-----------------------------------------------------------------------------
 struct Inspector
 {
@@ -106,26 +55,28 @@ struct Inspector
 	char _state_machine[1024];
 	bool _open;
 
-	Inspector() : _visible(true)
-		, _open(false)
+	Inspector()
+		: _visible(true)
+		, _open(true)
 	{
-		memset(_name, 0, 1024);
-		memset(_sprite, 0, 1024);
-		memset(_material, 0, 1024);
-		memset(_position, 0, 3);
-		memset(_rotation, 0, 3);
-		memset(_scale, 0, 3);
-		memset(_state_machine, 0, 1024);
+		memset(_name, 0, sizeof(_name));
+		memset(_sprite, 0, sizeof(_sprite));
+		memset(_material, 0, sizeof(_material));
+		memset(_position, 0, sizeof(_position));
+		memset(_rotation, 0, sizeof(_rotation));
+		memset(_scale, 0, sizeof(_scale));
+		memset(_state_machine, 0, sizeof(_state_machine));
 	}
 
 	void draw()
 	{
+		if (!_open) return;
 		if (ImGui::BeginDock("Inspector", &_open))
 		{
 			ImGui::SetNextTreeNodeOpen(true);
 			if (ImGui::TreeNode("Unit"))
 			{
-				ImGui::InputText("Name", _name, 1024);
+				ImGui::InputText("Name", _name, sizeof(_name));
 				ImGui::TreePop();
 			}
 
@@ -142,8 +93,8 @@ struct Inspector
 			ImGui::SetNextTreeNodeOpen(true);
 			if (ImGui::TreeNode("Renderer"))
 			{
-				ImGui::InputText("Sprite", _sprite, 1024);
-				ImGui::InputText("Material", _material, 1024);
+				ImGui::InputText("Sprite", _sprite, sizeof(_sprite));
+				ImGui::InputText("Material", _material, sizeof(_material));
 				ImGui::Checkbox("Visible", &_visible);
 				ImGui::TreePop();
 			}
@@ -151,7 +102,7 @@ struct Inspector
 			ImGui::SetNextTreeNodeOpen(true);
 			if (ImGui::TreeNode("Animation"))
 			{
-				ImGui::InputText("State Machine", _state_machine, 1024);
+				ImGui::InputText("State Machine", _state_machine, sizeof(_state_machine));
 				ImGui::TreePop();
 			}
 		}
@@ -164,17 +115,26 @@ struct SceneView
 {
 	ImVec2 _pos;
 	ImVec2 _size;
+	ImVec2 _mouse_curr;
+	ImVec2 _mouse_last;
 	bool _open;
 
-	SceneView() : _open(true) {}
+	SceneView()
+		: _open(true)
+	{
+	}
 
 	void draw()
 	{
+		if (!_open) return;
+
+		ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
 		ImGui::SetNextWindowPos(ImVec2(0, 25));
 		if (ImGui::BeginDock("Scene View"
 			, &_open
 			, ImGuiWindowFlags_NoScrollbar
-			| ImGuiWindowFlags_NoScrollWithMouse))
+			| ImGuiWindowFlags_NoScrollWithMouse
+			| ImGuiWindowFlags_NoTitleBar))
 		{
 			uint16_t w, h;
 			device()->resolution(w, h);
@@ -214,6 +174,7 @@ struct SceneView
 		_size = ImGui::GetWindowSize();
 
 		ImGui::EndDock();
+		ImGui::PopStyleVar();
 	}
 };
 
@@ -222,13 +183,15 @@ struct UnitList
 {
 	bool _open;
 
-	UnitList() : _open(true)
+	UnitList()
+		: _open(true)
 	{
-
 	}
 
 	void draw()
 	{
+		if (!_open) return;
+
 		if (ImGui::BeginDock("Unit List", &_open))
 		{
 			ImGui::SetNextTreeNodeOpen(true);
@@ -308,7 +271,7 @@ struct SpriteAnimator
 {
 	bool _open;
 	bool _add_animation_popup_open;
-	// int value = 0;
+
 	Array<const char*> _entities;
 	s32 _cur_entity;
 	TextureResource* _texture;
@@ -353,7 +316,7 @@ struct SpriteAnimator
 		, current(0)
 		, file_list_sprites(default_allocator())
 	{
-		memset(_anim_name, 0, 512);
+		memset(_anim_name, 0, sizeof(_anim_name));
 
 		_fs = CE_NEW(default_allocator(), FilesystemDisk)(default_allocator());
 		_fs->set_prefix(src_dir.c_str());
@@ -445,37 +408,21 @@ struct SpriteAnimator
 
 	void draw()
 	{
-		if (ImGui::Begin("Animator", &_open))
-		{
-			// if (_texture)
-			// {
-			// 	ImGui::Image((void*)(uintptr_t) _texture->handle.idx, ImVec2(_texture_width, _texture_height));
-
-			// 	ImVec2 win = ImGui::GetWindowPos();
-			// 	ImVec2 pad = ImGui::GetStyle().WindowPadding;
-			// 	ImDrawList* drawList = ImGui::GetWindowDrawList();
-
-			// 	for (uint32_t i = 0; i < array::size(_frames); i++)
-			// 	{
-			// 		const ImVec4& v = _frames[i].region;
-			// 		ImVec2 start(v.x + win.x + pad.x, v.y + win.y + pad.y + 24);
-			// 		ImVec2 end(v.x + v.z + win.x + pad.x, v.y + v.w + win.y + pad.y + 24);
-			// 		drawList->AddRect(start, end, IM_COL32(255,0,0,255));
-			// 	}
-			// }
+		if (!_open) return;
 
+		if (ImGui::BeginDock("Animator", &_open))
+		{
 			if (_texture)
 			{
 				Frame f = _frames[0];
 				ImVec2 start = pixel_to_uv(_texture_width, _texture_height, f.region.x, f.region.y);
 				ImVec2 end = pixel_to_uv(_texture_width, _texture_height, f.region.x+f.region.z, f.region.y+f.region.w);
-				ImGui::Image(
-					  (void*)(uintptr_t) _texture->handle.idx
+				ImGui::Image((void*)(uintptr_t) _texture->handle.idx
 					, ImVec2(f.region.z, f.region.w)
 					, start
 					, end
 					, ImColor(255, 255, 255, 55)
-					);
+				);
 			}
 
 			if (ImGui::Combo("Entities", &_cur_entity, (const char* const*) array::begin(_entities), array::size(_entities)))
@@ -541,7 +488,7 @@ struct SpriteAnimator
 
 			if (ImGui::BeginPopup("Add animation"))
 			{
-				ImGui::InputText("Name", _anim_name, 512);
+				ImGui::InputText("Name", _anim_name, sizeof(_anim_name));
 				ImGui::InputFloat("Time", &_anim_time, 0.1f, 0.1f, 1);
 				ImGui::ListBox("Animation Frames", &_listbox_item_current, (const char* const*)array::begin(_listbox_items), array::size(_listbox_items));
 				if (ImGui::Button("Clear Frames", ImVec2(100.0f, 25.0f)))
@@ -617,9 +564,8 @@ struct SpriteAnimator
 
 				ImGui::EndPopup();
 			}
-
-			ImGui::End();
 		}
+		ImGui::EndDock();
 	}
 };
 
@@ -628,12 +574,6 @@ struct LevelEditor
 {
 	DynamicString _source_dir;
 
-	// File Browser
-	FilesystemDisk* _fs;
-	DynamicString* _prefix;
-	DynamicString* _cur_dir;
-	Vector<DynamicString>* _cur_dir_files;
-
 	// FX
 	TextureResource* tex_move;
 	TextureResource* tex_place;
@@ -662,10 +602,6 @@ struct LevelEditor
 	ImVec2 _toolbar_pos;
 	ImVec2 _toolbar_size;
 
-	// Workaround https://github.com/ocornut/imgui/issues/331
-	bool _open_new_popup;
-	bool _open_open_popup;
-
 	Console _console;
 	Inspector _inspector;
 	SceneView _scene_view;
@@ -686,13 +622,10 @@ struct LevelEditor
 
 		, _main_menu_pos(0, 0)
 		, _main_menu_size(0, 0)
-		, _open_new_popup(false)
-		, _open_open_popup(false)
-
-		, _animator(source_dir)
 
 		, _toolbar_pos(0, 0)
 		, _toolbar_size(0, 0)
+		, _animator(source_dir)
 	{
 		ResourceManager* resman = device()->_resource_manager;
 		tex_move = (TextureResource*)resman->get(RESOURCE_TYPE_TEXTURE, StringId64("core/editors/gui/tool-move"));
@@ -707,35 +640,20 @@ struct LevelEditor
 
 		imgui_create();
 
-		// _prefix = CE_NEW(default_allocator(), DynamicString)(default_allocator());
-		// _cur_dir = CE_NEW(default_allocator(), DynamicString)(default_allocator());
-		// _cur_dir_files = CE_NEW(default_allocator(), Vector<DynamicString>)(default_allocator());
-
-		// *_prefix = "/";
-		// *_cur_dir = "";
-
-		_fs = CE_NEW(default_allocator(), FilesystemDisk)(default_allocator());
-		_fs->set_prefix(source_dir.c_str());
-		// _fs->list_files(_cur_dir->c_str(), *_cur_dir_files);
-
 		ImGui::LoadDock();
 	}
 
 	~LevelEditor()
 	{
-		CE_DELETE(default_allocator(), _fs);
-
-		// CE_DELETE(default_allocator(), _cur_dir_files);
-		// CE_DELETE(default_allocator(), _cur_dir);
-		// CE_DELETE(default_allocator(), _prefix);
-
 		ImGui::SaveDock();
 
 		imgui_destroy();
 	}
 
-	void update()
+	void update(float dt)
 	{
+		CE_UNUSED(dt);
+
 		static f32 last_w = 0.0f;
 		static f32 last_h = 0.0f;
 		if (last_w != _scene_view._size.x || last_h != _scene_view._size.y)
@@ -748,6 +666,8 @@ struct LevelEditor
 
 		TempAllocator4096 ta;
 
+		u32 message_count = 0;
+
 		// Receive response from engine
 		for (;;)
 		{
@@ -762,31 +682,43 @@ struct LevelEditor
 				char msg[8192];
 				rr = _console._client.read(msg, msg_len);
 				msg[msg_len] = '\0';
-
+				message_count++;
+				// logi(LEVEL_EDITOR, "count: %d", message_count);
 				if (ReadResult::SUCCESS == rr.error)
 				{
 					JsonObject obj(ta);
-					DynamicString severity(ta);
-					DynamicString message(ta);
-
+					DynamicString type(ta);
 					json::parse(msg, obj);
-					json::parse_string(obj["severity"], severity);
-					json::parse_string(obj["message"], message);
-
-					LogSeverity::Enum ls = LogSeverity::COUNT;
-					if (strcmp("info", severity.c_str()) == 0)
-						ls = LogSeverity::LOG_INFO;
-					else if (strcmp("warning", severity.c_str()) == 0)
-						ls = LogSeverity::LOG_WARN;
-					else if (strcmp("error", severity.c_str()) == 0)
-						ls = LogSeverity::LOG_ERROR;
-					else
-						CE_FATAL("Unknown severity");
+					json::parse_string(obj["type"], type);
 
-					ImGui::ConsoleLog log(ls, message.c_str());
-					vector::push_back(_console._console_items, log);
+					if (type == "message")
+					{
+						DynamicString severity(ta);
+						DynamicString message(ta);
+
+						json::parse_string(obj["severity"], severity);
+						json::parse_string(obj["message"], message);
+
+						LogSeverity::Enum ls = LogSeverity::COUNT;
+						if (strcmp("info", severity.c_str()) == 0)
+							ls = LogSeverity::LOG_INFO;
+						else if (strcmp("warning", severity.c_str()) == 0)
+							ls = LogSeverity::LOG_WARN;
+						else if (strcmp("error", severity.c_str()) == 0)
+							ls = LogSeverity::LOG_ERROR;
+						else
+							CE_FATAL("Unknown severity");
+
+						ConsoleLog log(ls, message.c_str());
+						vector::push_back(_console._console_items, log);
+					}
+					else
+					{
+						ConsoleLog log(LogSeverity::LOG_ERROR, "Unknown message type");
+						vector::push_back(_console._console_items, log);
+					}
 
-					// printf("msg_len: %d, msg: %s\n", msg_len, msg);
+					console_scroll_to_bottom();
 				}
 			}
 		}
@@ -799,7 +731,7 @@ struct LevelEditor
 		main_menu_bar();
 		// toolbar();
 		_scene_view.draw();
-		_console.draw();
+		console_draw(_console);
 		_unit_list.draw();
 		_inspector.draw();
 		_animator.draw();
@@ -855,98 +787,6 @@ struct LevelEditor
 #endif
 	}
 
-	// void new_popup()
-	// {
-	// 	ImGui::OpenPopup("New project");
-	// 	ImGui::SetNextWindowPos(ImVec2(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.5f)
-	// 		, 0
-	// 		, ImVec2(0.5f, 0.5f)
-	// 		);
-	// 	if (ImGui::BeginPopup("New project"))
-	// 	{
-	// 		ImGui::Text("Lorem ipsum");
-
-	// 		if (ImGui::Button("Ok"))
-	// 		{
-	// 			ImGui::CloseCurrentPopup();
-	// 			_open_new_popup = false;
-	// 		}
-	// 		ImGui::EndPopup();
-	// 	}
-	// }
-
-	// static bool list_getter(void* data, int idx, const char** out_text)
-	// {
-	// 	Vector<DynamicString>* files = (Vector<DynamicString>*) data;
-	// 	DynamicString str_idx = (*files)[idx];
-
-	// 	if (out_text)
-	// 		*out_text = str_idx.c_str();
-
-	// 	return true;
-	// }
-
-	// void file_browser()
-	// {
-	// 	ImGui::OpenPopup("File Selector");
-	// 	if (ImGui::BeginPopupModal("File Selector"))
-	// 	{
-	// 		TempAllocator4096 ta;
-	// 		DynamicString join(ta), path(ta);
-	// 		path::join(join, _prefix->c_str(), _cur_dir->c_str());
-	// 		path::reduce(path, join.c_str());
-
-	// 		ImGui::Text(path.c_str());
-
-	// 		int current_index;
-	// 		ImGui::ListBox("asd", &current_index, list_getter, (void*) _cur_dir_files, vector::size(*_cur_dir_files));
-
-	// 		for (u32 i = 0; i < vector::size(*_cur_dir_files); i++)
-	// 		{
-	// 			DynamicString file(ta);
-
-	// 			if (*_cur_dir != "")
-	// 			{
-	// 				file += *_cur_dir;
-	// 				file += '/';
-	// 			}
-	// 			file += (*_cur_dir_files)[i];
-
-	// 			DynamicString file_row(ta);
-	// 			if (_fs->is_directory(file.c_str()))
-	// 			{
-	// 				file_row += ICON_FA_FOLDER;
-	// 				file_row += " ";
-	// 				file_row += file;
-
-
-
-	// 			}
-	// 			else
-	// 			{
-	// 				// file_row += ICON_FA_FILE;
-	// 				// file_row += " ";
-	// 				// file_row += file;
-
-	// 				// ImGui::Selectable(file_row.c_str());
-	// 			}
-
-	// 			char buff[80];
-	// 			u64 time_mod = _fs->last_modified_time(file.c_str());
-	// 			format_time(time_mod, buff, 80);
-	// 			ImGui::SameLine(FILE_BROWSER_WIDTH - 150);
-	// 			ImGui::Text(buff);
-	// 		}
-
-	// 		if (ImGui::Button("Ok"))
-	// 		{
-	// 			ImGui::CloseCurrentPopup();
-	// 			_open_open_popup = false;
-	// 		}
-	// 		ImGui::EndPopup();
-	// 	}
-	// }
-
 	void main_menu_bar()
 	{
 		// Main Menu
@@ -956,11 +796,11 @@ struct LevelEditor
 			{
 				if (ImGui::MenuItem("New"))
 				{
-					// _open_new_popup = true;
+
 				}
 				if (ImGui::MenuItem("Open", "Ctrl+O"))
 				{
-					// _open_open_popup = true;
+
 				}
 				if (ImGui::MenuItem("Save", "Ctrl+S"))
 				{
@@ -993,26 +833,36 @@ struct LevelEditor
 				{
 					if (ImGui::MenuItem("Cube", NULL, false, true))
 					{
+						_tool_type = tool::ToolType::PLACE;
+						tool_send_state();
 						tool::set_placeable(ss, "unit", "core/units/primitives/cube");
 						send_command(ss);
 					}
 					if (ImGui::MenuItem("Sphere"))
 					{
+						_tool_type = tool::ToolType::PLACE;
+						tool_send_state();
 						tool::set_placeable(ss, "unit", "core/units/primitives/sphere");
 						send_command(ss);
 					}
 					if (ImGui::MenuItem("Cone"))
 					{
+						_tool_type = tool::ToolType::PLACE;
+						tool_send_state();
 						tool::set_placeable(ss, "unit", "core/units/primitives/cone");
 						send_command(ss);
 					}
 					if (ImGui::MenuItem("Cylinder"))
 					{
+						_tool_type = tool::ToolType::PLACE;
+						tool_send_state();
 						tool::set_placeable(ss, "unit", "core/units/primitives/cylinder");
 						send_command(ss);
 					}
 					if (ImGui::MenuItem("Plane"))
 					{
+						_tool_type = tool::ToolType::PLACE;
+						tool_send_state();
 						tool::set_placeable(ss, "unit", "core/units/primitives/plane");
 						send_command(ss);
 					}
@@ -1021,16 +871,22 @@ struct LevelEditor
 
 				if (ImGui::MenuItem("Camera"))
 				{
+					_tool_type = tool::ToolType::PLACE;
+					tool_send_state();
 					tool::set_placeable(ss, "unit", "core/units/camera");
 					send_command(ss);
 				}
 				if (ImGui::MenuItem("Light"))
 				{
+					_tool_type = tool::ToolType::PLACE;
+					tool_send_state();
 					tool::set_placeable(ss, "unit", "core/units/light");
 					send_command(ss);
 				}
 				if (ImGui::MenuItem("Sound"))
 				{
+					_tool_type = tool::ToolType::PLACE;
+					tool_send_state();
 					tool::set_placeable(ss, "sound", "core/units/camera");
 					send_command(ss);
 				}
@@ -1098,7 +954,11 @@ struct LevelEditor
 			}
 			if (ImGui::BeginMenu("Windows"))
 			{
-				if (ImGui::MenuItem("Objects List"))
+				if (ImGui::MenuItem("Scene"))
+				{
+					_scene_view._open = true;
+				}
+				if (ImGui::MenuItem("Unit List"))
 				{
 					_unit_list._open = true;
 				}
@@ -1106,6 +966,15 @@ struct LevelEditor
 				{
 					_inspector._open = true;
 				}
+				if (ImGui::MenuItem("Console"))
+				{
+					_console._open = true;
+				}
+				if (ImGui::MenuItem("Animator"))
+				{
+					_animator._open = true;
+				}
+
 				ImGui::EndMenu();
 			}
 			if (ImGui::BeginMenu("Help"))
@@ -1118,11 +987,6 @@ struct LevelEditor
 			_main_menu_size = ImGui::GetWindowSize();
 
 			ImGui::EndMainMenuBar();
-
-			// if (_open_new_popup)
-			// 	new_popup();
-			// if (_open_open_popup)
-			// 	file_browser();
 		}
 	}
 
@@ -1196,7 +1060,7 @@ void tool_init()
 
 void tool_update(float dt)
 {
-	s_editor->update();
+	s_editor->update(dt);
 }
 
 void tool_shutdown()
@@ -1209,6 +1073,7 @@ extern bool next_event(OsEvent& ev);
 bool tool_process_events()
 {
 	ImGuiIO& io = ImGui::GetIO();
+
 	bool exit = false;
 	bool reset = false;
 
@@ -1293,18 +1158,25 @@ bool tool_process_events()
 
 					if (!io.WantCaptureMouse)
 					{
-						if (ev.pressed)
-							tool::mouse_down(ss, io.MousePos.x, io.MousePos.y);
-						else
-							tool::mouse_up(ss, io.MousePos.x, io.MousePos.y);
+						ImVec2& mouse_curr = s_editor->_scene_view._mouse_curr;
+						mouse_curr.x = io.MousePos.x - s_editor->_scene_view._pos.x;
+						mouse_curr.y = io.MousePos.y - s_editor->_scene_view._pos.y;
 
 						tool::set_mouse_state(ss
-							, io.MousePos.x
-							, io.MousePos.y
+							, mouse_curr.x
+							, mouse_curr.y
 							, io.MouseDown[0]
 							, io.MouseDown[2]
 							, io.MouseDown[1]
 							);
+
+						if (ev.button_num == crown::MouseButton::LEFT)
+						{
+							if (ev.pressed)
+								tool::mouse_down(ss, mouse_curr.x, mouse_curr.y);
+							else
+								tool::mouse_up(ss, mouse_curr.x, mouse_curr.y);
+						}
 					}
 
 					break;
@@ -1326,20 +1198,18 @@ bool tool_process_events()
 
 							if (!io.WantCaptureMouse)
 							{
-								tool::mouse_move(ss
-									, io.MousePos.x
-									, io.MousePos.y
-									, io.MousePos.x - io.MousePosPrev.x
-									, io.MousePos.y - io.MousePosPrev.y
-									);
-
-								tool::set_mouse_state(ss
-									, io.MousePos.x
-									, io.MousePos.y
-									, io.MouseDown[0]
-									, io.MouseDown[2]
-									, io.MouseDown[1]
-									);
+								ImVec2& mouse_curr = s_editor->_scene_view._mouse_curr;
+								ImVec2& mouse_last = s_editor->_scene_view._mouse_last;
+
+								mouse_curr.x = io.MousePos.x - s_editor->_scene_view._pos.x;
+								mouse_curr.y = io.MousePos.y - s_editor->_scene_view._pos.y;
+
+								float delta_x = mouse_curr.x - mouse_last.x;
+								float delta_y = mouse_curr.y - mouse_last.y;
+
+								tool::mouse_move(ss, mouse_curr.x, mouse_curr.y, delta_x, delta_y);
+
+								mouse_last = mouse_curr;
 							}
 
 							break;

+ 49 - 18
tools-imgui/widgets/console.h

@@ -1,17 +1,16 @@
-// forward declarations
 #include "core/containers/vector.h"
 #include "core/network/socket.h"
 #include "core/strings/dynamic_string.h"
 #include "device/log.h"
+#include "core/network/ip_address.h"
+#include "core/memory/temp_allocator.h"
 
-namespace ImGui
+namespace crown
 {
-	using namespace crown;
-
 	struct ConsoleLog
 	{
 		LogSeverity::Enum _severity;
-		DynamicString _message;
+		crown::DynamicString _message;
 
 		ConsoleLog(LogSeverity::Enum severity = LogSeverity::LOG_INFO, const char* message="")
 			: _severity(severity)
@@ -21,18 +20,50 @@ namespace ImGui
 		}
 	};
 
-	void console_draw(TCPSocket& client
-		, Vector<ConsoleLog>& items
-		, Vector<DynamicString>& history
-		, Vector<DynamicString>& commands
-		);
+	//-----------------------------------------------------------------------------
+	struct Console
+	{
+		TCPSocket _client;
+		Vector<ConsoleLog> _console_items;
+		Vector<DynamicString> _console_history;
+		Vector<DynamicString> _console_commands;
+		bool _open;
+
+		bool _has_focus;
+		s32 _history_pos;	// -1: new line, 0 -> (history.size - 1): navigation
+
+		Console()
+			: _console_items(default_allocator())
+			, _console_history(default_allocator())
+			, _console_commands(default_allocator())
+			, _open(true)
+			, _has_focus(false)
+			, _history_pos(-1)
+		{
+			_client.connect(IP_ADDRESS_LOOPBACK, CROWN_DEFAULT_CONSOLE_PORT);
+
+			// FIXME: clear tmp commands
+			TempAllocator128 a;
+			DynamicString str(a);
+			str = "help - Show this";
+			vector::push_back(_console_commands, str);
+			str = "clear - Clear console";
+			vector::push_back(_console_commands, str);
+			str = "history - Show recent commands";
+			vector::push_back(_console_commands, str);
+		}
+
+		~Console()
+		{
+			_client.close();
+		}
+	};
+
+	void console_draw(Console& client);
 
 	// Helpers
-	void console_execute_command(TCPSocket& client
-		, Vector<ConsoleLog>& items
-		, Vector<DynamicString>& history
-		, Vector<DynamicString>& commands
-		, ConsoleLog& command_line
-		);
-
-} // namespace ImGui
+	void console_execute_command(Console& console, ConsoleLog& command_line);
+
+	void console_scroll_to_bottom();
+
+} // namespace crown

+ 121 - 65
tools-imgui/widgets/console.inl

@@ -1,88 +1,132 @@
 #include "core/memory/temp_allocator.h"
 #include "core/strings/string_stream.h"
 
-namespace ImGui
+namespace crown
 {
 
-using namespace crown;
-
 static bool scroll_to_bottom = false;
+static char input_text_buffer[1024] = "";
 
-void console_draw(TCPSocket& client
-	, Vector<ConsoleLog>& items
-	, Vector<DynamicString>& history
-	, Vector<DynamicString>& commands
-	)
+int console_inputtext_callback(ImGuiTextEditCallbackData* data)
 {
-	ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0));
-	static ImGuiTextFilter filter;
-	filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
-	ImGui::PopStyleVar();
-	ImGui::Separator();
-
-	ImGui::BeginChild("ScrollingRegion", ImVec2(0,-ImGui::GetFrameHeightWithSpacing()), false, ImGuiWindowFlags_HorizontalScrollbar);
-
-	ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4,1)); // Tighten spacing
-	for (uint32_t i = 0; i < vector::size(items); i++)
+	if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
 	{
-		ConsoleLog item = items[i];
-		if (!filter.PassFilter(item._message.c_str()))
-			continue;
+		Console* console = (Console*) data->UserData;
+		const Vector<DynamicString>& history = console->_console_history;
+		s32& history_pos = console->_history_pos;
+		const s32 prev_history_pos = history_pos;
 
-		ImVec4 col = ImVec4(1.0f,1.0f,1.0f,1.0f);
+		if (ImGuiKey_UpArrow == data->EventKey)
+		{
+			if (history_pos == -1)
+				history_pos = vector::size(history) - 1;
+			else if (history_pos > 0)
+				history_pos--;
+		}
+		else if (ImGuiKey_DownArrow == data->EventKey)
+		{
+			if (history_pos != -1)
+				if (++history_pos >= vector::size(history))
+					history_pos = -1;
+		}
 
-		switch (item._severity)
+		if (prev_history_pos != history_pos)
 		{
-			case LogSeverity::LOG_INFO: col = ImColor(0.7f, 0.7f, 0.7f, 1.0f); break;
-			case LogSeverity::LOG_WARN: col = ImColor(1.0f, 1.0f, 0.4f, 1.0f); break;
-			case LogSeverity::LOG_ERROR: col = ImColor(1.0f, 0.4f, 0.4f, 1.0f); break;
-			default: CE_FATAL("Unknown Severity"); break;
+			s32 len = snprintf(data->Buf, (size_t) data->BufSize, "%s", (history_pos >= 0) ? history[history_pos].c_str() : "");
+			data->CursorPos = data->SelectionStart = data->SelectionEnd = data->BufTextLen = len;
+			data->BufDirty = true;
 		}
-		ImGui::PushStyleColor(ImGuiCol_Text, col);
-		ImGui::TextUnformatted(item._message.c_str());
-		ImGui::PopStyleColor();
 	}
 
-	if (scroll_to_bottom)
-		ImGui::SetScrollHere();
-	scroll_to_bottom = false;
-	ImGui::PopStyleVar();
-	ImGui::EndChild();
-	ImGui::Separator();
+	return 0;
+}
+
+void console_draw(Console& console)
+{
+	if (!console._open) return;
 
-	// Command-line
-	char buffer[1024] = "";
-	if (ImGui::InputText("Input", buffer, IM_ARRAYSIZE(buffer), ImGuiInputTextFlags_EnterReturnsTrue))
+	if (ImGui::BeginDock("Console", &console._open, ImGuiWindowFlags_NoScrollbar))
 	{
-		char* input_end = buffer + strlen(buffer);
-		while (input_end > buffer && input_end[-1] == ' ')
+		TCPSocket& client = console._client;
+		Vector<ConsoleLog>& items = console._console_items;
+		Vector<DynamicString>& history = console._console_history;
+		Vector<DynamicString>& commands = console._console_commands;
+
+		ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0,0));
+		static ImGuiTextFilter filter;
+		filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
+		ImGui::PopStyleVar();
+		ImGui::Separator();
+
+		ImGui::BeginChild("ScrollingRegion", ImVec2(0,-ImGui::GetFrameHeightWithSpacing()), false, ImGuiWindowFlags_HorizontalScrollbar);
+
+		ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4,1)); // Tighten spacing
+		for (uint32_t i = 0; i < vector::size(items); i++)
 		{
-			input_end--;
+			ConsoleLog item = items[i];
+			if (!filter.PassFilter(item._message.c_str()))
+				continue;
+
+			ImVec4 col = ImVec4(1.0f,1.0f,1.0f,1.0f);
+
+			switch (item._severity)
+			{
+				case LogSeverity::LOG_INFO: col = ImColor(0.7f, 0.7f, 0.7f, 1.0f); break;
+				case LogSeverity::LOG_WARN: col = ImColor(1.0f, 1.0f, 0.4f, 1.0f); break;
+				case LogSeverity::LOG_ERROR: col = ImColor(1.0f, 0.4f, 0.4f, 1.0f); break;
+				default: CE_FATAL("Unknown Severity"); break;
+			}
+			ImGui::PushStyleColor(ImGuiCol_Text, col);
+			ImGui::TextUnformatted(item._message.c_str());
+			ImGui::PopStyleColor();
 		}
 
-		*input_end = 0;
+		if (scroll_to_bottom)
+			ImGui::SetScrollHere();
+
+		scroll_to_bottom = false;
+		ImGui::PopStyleVar();
+		ImGui::EndChild();
+		ImGui::Separator();
 
-		if (buffer[0])
+		if (ImGui::InputText("Input"
+		, input_text_buffer
+		, IM_ARRAYSIZE(input_text_buffer)
+		, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackHistory
+		, console_inputtext_callback
+		, &console))
 		{
-			ConsoleLog log(LogSeverity::LOG_INFO, buffer);
-			console_execute_command(client, items, history, commands, log);
-		}
+			char* input_end = input_text_buffer + strlen(input_text_buffer);
+			while (input_end > input_text_buffer && input_end[-1] == ' ')
+			{
+				input_end--;
+			}
 
-		strcpy(buffer, "");
-	}
+			*input_end = 0;
+
+			if (input_text_buffer[0])
+			{
+				ConsoleLog log(LogSeverity::LOG_INFO, input_text_buffer);
+				console_execute_command(console, log);
+			}
 
-	// Demonstrate keeping auto focus on the input box
-	if (ImGui::IsItemHovered() || (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) && !ImGui::IsAnyItemActive() && !ImGui::IsMouseClicked(0)))
-		ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
+			strcpy(input_text_buffer, "");
+			console._history_pos = -1;
+
+			ImGui::SetKeyboardFocusHere(-1);
+			scroll_to_bottom = true;
+		}
+	}
+	ImGui::EndDock();
 }
 
-void console_execute_command(TCPSocket& client
-	, Vector<ConsoleLog>& items
-	, Vector<DynamicString>& history
-	, Vector<DynamicString>& commands
-	, ConsoleLog& command_line
-	)
+void console_execute_command(Console& console, ConsoleLog& command_line)
 {
+	TCPSocket& client = console._client;
+	Vector<ConsoleLog>& items = console._console_items;
+	Vector<DynamicString>& history = console._console_history;
+	Vector<DynamicString>& commands = console._console_commands;
+
 	vector::push_back(items, command_line);
 	vector::push_back(history, command_line._message);
 
@@ -102,12 +146,19 @@ void console_execute_command(TCPSocket& client
 			vector::push_back(items, log);
 		}
 	}
-	// else if (strcmp(command_line, "help") == 0)
-	// {
-	//  add_log(items, "commands:");
-	//  for (uint32_t i = 0; i < vector::size(commands); i++)
-	//      add_log(items, "- %s", commands[i].c_str());
-	// }
+	else if (strcmp(command_line._message.c_str(), "help") == 0)
+	{
+		ConsoleLog log;
+		log._severity = LogSeverity::LOG_INFO;
+		log._message = "commands: ";
+		vector::push_back(items, log);
+		for (uint32_t i = 0; i < vector::size(commands); i++)
+		{
+			log._severity = LogSeverity::LOG_INFO;
+			log._message = commands[i].c_str();
+			vector::push_back(items, log);
+		}
+	}
 	else
 	{
 		// Send command to engine
@@ -126,4 +177,9 @@ void console_execute_command(TCPSocket& client
 	scroll_to_bottom = true;
 }
 
-} // namespace ImGui
+void console_scroll_to_bottom()
+{
+	scroll_to_bottom = true;
+}
+
+} // namespace crown

+ 2 - 0
tools-imgui/widgets/dock.h

@@ -1,3 +1,5 @@
+#pragma once
+
 namespace ImGui
 {
 	///

+ 33 - 32
tools-imgui/widgets/dock.inl

@@ -1060,13 +1060,13 @@ namespace ImGui
 		void save_dock()
 		{
 			char cwdbuf[1024];
-			const char* bin_dir = os::getcwd(cwdbuf, sizeof(cwdbuf));
+			const char* bin_dir = crown::os::getcwd(cwdbuf, sizeof(cwdbuf));
 			crown::TempAllocator4096 ta;
 			crown::FilesystemDisk fs(ta);
 			fs.set_prefix(bin_dir);
-			crown::File* file = fs.open("docks.config", FileOpenMode::WRITE);
+			crown::File* file = fs.open("docks.config", crown::FileOpenMode::WRITE);
 
-			StringStream ss(ta);
+			crown::StringStream ss(ta);
 			for (uint32_t i = 0; i < m_docks.size(); i++)
 			{
 				Dock& dock = *m_docks[i];
@@ -1090,9 +1090,9 @@ namespace ImGui
 				ss << "},\n";
 			}
 
-			const char* buf = string_stream::c_str(ss);
+			const char* buf = crown::string_stream::c_str(ss);
 			file->write(buf, strlen(buf));
-			file->close();
+			fs.close(*file);
 		}
 
 		void load_dock()
@@ -1105,7 +1105,7 @@ namespace ImGui
 			m_docks.clear();
 
 			char cwdbuf[1024];
-			const char* bin_dir = os::getcwd(cwdbuf, sizeof(cwdbuf));
+			const char* bin_dir = crown::os::getcwd(cwdbuf, sizeof(cwdbuf));
 			crown::TempAllocator4096 ta;
 			crown::FilesystemDisk fs(ta);
 			fs.set_prefix(bin_dir);
@@ -1116,18 +1116,17 @@ namespace ImGui
 				return;
 			}
 
-			crown::File& file = *fs.open("docks.config", FileOpenMode::READ);
-			uint32_t size = file.size();
+			crown::File* file = fs.open("docks.config", crown::FileOpenMode::READ);
+			uint32_t size = file->size();
 			char buf[4096];
-			file.read(buf, size);
+			file->read(buf, size);
 			buf[size] = '\0';
 
 			crown::JsonObject obj(ta);
-			sjson::parse(buf, obj);
-
-			auto cur = json_object::begin(obj);
-			auto end = json_object::end(obj);
+			crown::sjson::parse(buf, obj);
 
+			auto cur = crown::json_object::begin(obj);
+			auto end = crown::json_object::end(obj);
 			for (uint32_t i = 0; i < end-cur; i++)
 			{
 				Dock* dock = (Dock*) MemAlloc(sizeof(Dock));
@@ -1136,33 +1135,35 @@ namespace ImGui
 
 			for (; cur != end; ++cur)
 			{
-				FixedString key = cur->pair.first;
+				crown::FixedString key = cur->pair.first;
 				const char* value = cur->pair.second;
-				JsonObject item(ta);
-				sjson::parse_object(value, item);
+				crown::JsonObject item(ta);
+				crown::sjson::parse_object(value, item);
 
-				DynamicString label(ta), loc(ta);
-				uint32_t id = sjson::parse_int(item["index"]);
-				sjson::parse_string(item["label"], label);
-				sjson::parse_string(item["location"], loc);
+				crown::DynamicString label(ta), loc(ta);
+				uint32_t id = crown::sjson::parse_int(item["index"]);
+				crown::sjson::parse_string(item["label"], label);
+				crown::sjson::parse_string(item["location"], loc);
 				m_docks[id]->id = ImHash(label.c_str(), 0);
 				m_docks[id]->label = strdup(label.c_str());
-				m_docks[id]->pos.x = sjson::parse_int(item["x"]);
-				m_docks[id]->pos.y = sjson::parse_int(item["y"]);
-				m_docks[id]->size.x = sjson::parse_int(item["size_x"]);
-				m_docks[id]->size.y = sjson::parse_int(item["size_y"]);
-				m_docks[id]->status = (Status_)sjson::parse_int(item["status"]);
-				m_docks[id]->active = sjson::parse_int(item["active"]);
-				m_docks[id]->opened = sjson::parse_int(item["opened"]);
-				m_docks[id]->prev_tab = getDockByIndex(sjson::parse_int(item["prev"]));
-				m_docks[id]->next_tab = getDockByIndex(sjson::parse_int(item["next"]));
-				m_docks[id]->children[0] = getDockByIndex(sjson::parse_int(item["child_0"]));
-				m_docks[id]->children[1] = getDockByIndex(sjson::parse_int(item["child_1"]));
-				m_docks[id]->parent = getDockByIndex(sjson::parse_int(item["parent"]));
+				m_docks[id]->pos.x = crown::sjson::parse_int(item["x"]);
+				m_docks[id]->pos.y = crown::sjson::parse_int(item["y"]);
+				m_docks[id]->size.x = crown::sjson::parse_int(item["size_x"]);
+				m_docks[id]->size.y = crown::sjson::parse_int(item["size_y"]);
+				m_docks[id]->status = (Status_)crown::sjson::parse_int(item["status"]);
+				m_docks[id]->active = crown::sjson::parse_int(item["active"]);
+				m_docks[id]->opened = crown::sjson::parse_int(item["opened"]);
+				m_docks[id]->prev_tab = getDockByIndex(crown::sjson::parse_int(item["prev"]));
+				m_docks[id]->next_tab = getDockByIndex(crown::sjson::parse_int(item["next"]));
+				m_docks[id]->children[0] = getDockByIndex(crown::sjson::parse_int(item["child_0"]));
+				m_docks[id]->children[1] = getDockByIndex(crown::sjson::parse_int(item["child_1"]));
+				m_docks[id]->parent = getDockByIndex(crown::sjson::parse_int(item["parent"]));
 				strcpy(m_docks[id]->location, loc.c_str());
 
 				tryDockToStoredLocation(*m_docks[id]);
 			}
+
+			fs.close(*file);
 		}
 
 		void load_default()