|
@@ -1284,11 +1284,25 @@ void ImStrncpy(char* dst, const char* src, size_t count)
|
|
|
dst[count-1] = 0;
|
|
|
}
|
|
|
|
|
|
-char* ImStrdup(const char *str)
|
|
|
+char* ImStrdup(const char* str)
|
|
|
{
|
|
|
- size_t len = strlen(str) + 1;
|
|
|
- void* buf = ImGui::MemAlloc(len);
|
|
|
- return (char*)memcpy(buf, (const void*)str, len);
|
|
|
+ size_t len = strlen(str);
|
|
|
+ void* buf = ImGui::MemAlloc(len + 1);
|
|
|
+ return (char*)memcpy(buf, (const void*)str, len + 1);
|
|
|
+}
|
|
|
+
|
|
|
+char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src)
|
|
|
+{
|
|
|
+ size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1;
|
|
|
+ size_t src_size = strlen(src) + 1;
|
|
|
+ if (dst_buf_size < src_size)
|
|
|
+ {
|
|
|
+ ImGui::MemFree(dst);
|
|
|
+ dst = (char*)ImGui::MemAlloc(src_size);
|
|
|
+ if (p_dst_size)
|
|
|
+ *p_dst_size = src_size;
|
|
|
+ }
|
|
|
+ return (char*)memcpy(dst, (const void*)src, src_size);
|
|
|
}
|
|
|
|
|
|
const char* ImStrchrRange(const char* str, const char* str_end, char c)
|
|
@@ -1362,6 +1376,12 @@ void ImStrTrimBlanks(char* buf)
|
|
|
// B) When buf==NULL vsnprintf() will return the output size.
|
|
|
#ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
|
|
|
|
|
|
+//#define IMGUI_USE_STB_SPRINTF
|
|
|
+#ifdef IMGUI_USE_STB_SPRINTF
|
|
|
+#define STB_SPRINTF_IMPLEMENTATION
|
|
|
+#include "imstb_sprintf.h"
|
|
|
+#endif
|
|
|
+
|
|
|
#if defined(_MSC_VER) && !defined(vsnprintf)
|
|
|
#define vsnprintf _vsnprintf
|
|
|
#endif
|
|
@@ -1370,7 +1390,11 @@ int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
|
|
|
{
|
|
|
va_list args;
|
|
|
va_start(args, fmt);
|
|
|
+#ifdef IMGUI_USE_STB_SPRINTF
|
|
|
+ int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
|
|
|
+#else
|
|
|
int w = vsnprintf(buf, buf_size, fmt, args);
|
|
|
+#endif
|
|
|
va_end(args);
|
|
|
if (buf == NULL)
|
|
|
return w;
|
|
@@ -1382,7 +1406,11 @@ int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
|
|
|
|
|
|
int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
|
|
|
{
|
|
|
+#ifdef IMGUI_USE_STB_SPRINTF
|
|
|
+ int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
|
|
|
+#else
|
|
|
int w = vsnprintf(buf, buf_size, fmt, args);
|
|
|
+#endif
|
|
|
if (buf == NULL)
|
|
|
return w;
|
|
|
if (w == -1 || w >= (int)buf_size)
|
|
@@ -1392,7 +1420,9 @@ int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
|
|
|
}
|
|
|
#endif // #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
|
|
|
|
|
|
-// Pass data_size==0 for zero-terminated strings
|
|
|
+// Pass data_size == 0 for zero-terminated strings, data_size > 0 for non-string data.
|
|
|
+// Pay attention that data_size==0 will yield different results than passing strlen(data) because the zero-terminated codepath handles ###.
|
|
|
+// This should technically be split into two distinct functions (ImHashData/ImHashStr), perhaps once we remove the silly static variable.
|
|
|
// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
|
|
|
ImU32 ImHash(const void* data, int data_size, ImU32 seed)
|
|
|
{
|
|
@@ -1791,15 +1821,15 @@ ImU32 ImGui::GetColorU32(ImU32 col)
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
// std::lower_bound but without the bullshit
|
|
|
-static ImVector<ImGuiStorage::Pair>::iterator LowerBound(ImVector<ImGuiStorage::Pair>& data, ImGuiID key)
|
|
|
+static ImGuiStorage::Pair* LowerBound(ImVector<ImGuiStorage::Pair>& data, ImGuiID key)
|
|
|
{
|
|
|
- ImVector<ImGuiStorage::Pair>::iterator first = data.begin();
|
|
|
- ImVector<ImGuiStorage::Pair>::iterator last = data.end();
|
|
|
+ ImGuiStorage::Pair* first = data.Data;
|
|
|
+ ImGuiStorage::Pair* last = data.Data + data.Size;
|
|
|
size_t count = (size_t)(last - first);
|
|
|
while (count > 0)
|
|
|
{
|
|
|
size_t count2 = count >> 1;
|
|
|
- ImVector<ImGuiStorage::Pair>::iterator mid = first + count2;
|
|
|
+ ImGuiStorage::Pair* mid = first + count2;
|
|
|
if (mid->key < key)
|
|
|
{
|
|
|
first = ++mid;
|
|
@@ -1832,7 +1862,7 @@ void ImGuiStorage::BuildSortByKey()
|
|
|
|
|
|
int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
|
|
|
{
|
|
|
- ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
|
|
|
+ ImGuiStorage::Pair* it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
|
|
|
if (it == Data.end() || it->key != key)
|
|
|
return default_val;
|
|
|
return it->val_i;
|
|
@@ -1845,7 +1875,7 @@ bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
|
|
|
|
|
|
float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
|
|
|
{
|
|
|
- ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
|
|
|
+ ImGuiStorage::Pair* it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
|
|
|
if (it == Data.end() || it->key != key)
|
|
|
return default_val;
|
|
|
return it->val_f;
|
|
@@ -1853,7 +1883,7 @@ float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
|
|
|
|
|
|
void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
|
|
|
{
|
|
|
- ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
|
|
|
+ ImGuiStorage::Pair* it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
|
|
|
if (it == Data.end() || it->key != key)
|
|
|
return NULL;
|
|
|
return it->val_p;
|
|
@@ -1862,7 +1892,7 @@ void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
|
|
|
// References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer.
|
|
|
int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
|
|
|
{
|
|
|
- ImVector<Pair>::iterator it = LowerBound(Data, key);
|
|
|
+ ImGuiStorage::Pair* it = LowerBound(Data, key);
|
|
|
if (it == Data.end() || it->key != key)
|
|
|
it = Data.insert(it, Pair(key, default_val));
|
|
|
return &it->val_i;
|
|
@@ -1875,7 +1905,7 @@ bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
|
|
|
|
|
|
float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
|
|
|
{
|
|
|
- ImVector<Pair>::iterator it = LowerBound(Data, key);
|
|
|
+ ImGuiStorage::Pair* it = LowerBound(Data, key);
|
|
|
if (it == Data.end() || it->key != key)
|
|
|
it = Data.insert(it, Pair(key, default_val));
|
|
|
return &it->val_f;
|
|
@@ -1883,7 +1913,7 @@ float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
|
|
|
|
|
|
void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
|
|
|
{
|
|
|
- ImVector<Pair>::iterator it = LowerBound(Data, key);
|
|
|
+ ImGuiStorage::Pair* it = LowerBound(Data, key);
|
|
|
if (it == Data.end() || it->key != key)
|
|
|
it = Data.insert(it, Pair(key, default_val));
|
|
|
return &it->val_p;
|
|
@@ -1892,7 +1922,7 @@ void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
|
|
|
// FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame)
|
|
|
void ImGuiStorage::SetInt(ImGuiID key, int val)
|
|
|
{
|
|
|
- ImVector<Pair>::iterator it = LowerBound(Data, key);
|
|
|
+ ImGuiStorage::Pair* it = LowerBound(Data, key);
|
|
|
if (it == Data.end() || it->key != key)
|
|
|
{
|
|
|
Data.insert(it, Pair(key, val));
|
|
@@ -1908,7 +1938,7 @@ void ImGuiStorage::SetBool(ImGuiID key, bool val)
|
|
|
|
|
|
void ImGuiStorage::SetFloat(ImGuiID key, float val)
|
|
|
{
|
|
|
- ImVector<Pair>::iterator it = LowerBound(Data, key);
|
|
|
+ ImGuiStorage::Pair* it = LowerBound(Data, key);
|
|
|
if (it == Data.end() || it->key != key)
|
|
|
{
|
|
|
Data.insert(it, Pair(key, val));
|
|
@@ -1919,7 +1949,7 @@ void ImGuiStorage::SetFloat(ImGuiID key, float val)
|
|
|
|
|
|
void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)
|
|
|
{
|
|
|
- ImVector<Pair>::iterator it = LowerBound(Data, key);
|
|
|
+ ImGuiStorage::Pair* it = LowerBound(Data, key);
|
|
|
if (it == Data.end() || it->key != key)
|
|
|
{
|
|
|
Data.insert(it, Pair(key, val));
|
|
@@ -2420,6 +2450,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
|
|
|
WindowPadding = ImVec2(0.0f, 0.0f);
|
|
|
WindowRounding = 0.0f;
|
|
|
WindowBorderSize = 0.0f;
|
|
|
+ NameBufLen = (int)strlen(name) + 1;
|
|
|
MoveId = GetID("#MOVE");
|
|
|
ChildId = 0;
|
|
|
Scroll = ImVec2(0.0f, 0.0f);
|
|
@@ -2669,7 +2700,8 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
|
|
|
const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y);
|
|
|
//if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
|
|
|
window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y);
|
|
|
- window->DC.CursorPos = ImVec2((float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x), (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y));
|
|
|
+ window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
|
|
|
+ window->DC.CursorPos.y = (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y);
|
|
|
window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
|
|
|
window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
|
|
|
//if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
|
|
@@ -2715,7 +2747,8 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
|
|
|
window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
|
|
|
|
|
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
|
|
- ImGuiTestEngineHook_ItemAdd(bb, id);
|
|
|
+ if (id != 0)
|
|
|
+ ImGuiTestEngineHook_ItemAdd(&g, bb, id);
|
|
|
#endif
|
|
|
|
|
|
// Clipping test
|
|
@@ -3330,7 +3363,7 @@ void ImGui::NewFrame()
|
|
|
ImGuiContext& g = *GImGui;
|
|
|
|
|
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
|
|
- ImGuiTestEngineHook_PreNewFrame();
|
|
|
+ ImGuiTestEngineHook_PreNewFrame(&g);
|
|
|
#endif
|
|
|
|
|
|
// Check user data
|
|
@@ -3552,7 +3585,7 @@ void ImGui::NewFrame()
|
|
|
g.FrameScopePushedImplicitWindow = true;
|
|
|
|
|
|
#ifdef IMGUI_ENABLE_TEST_ENGINE
|
|
|
- ImGuiTestEngineHook_PostNewFrame();
|
|
|
+ ImGuiTestEngineHook_PostNewFrame(&g);
|
|
|
#endif
|
|
|
}
|
|
|
|
|
@@ -4553,7 +4586,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl
|
|
|
if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID))
|
|
|
{
|
|
|
// Retrieve settings from .ini file
|
|
|
- window->SettingsIdx = g.SettingsWindows.index_from_pointer(settings);
|
|
|
+ window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings);
|
|
|
SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
|
|
|
if (settings->ViewportId)
|
|
|
{
|
|
@@ -5036,13 +5069,18 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
|
|
|
window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX);
|
|
|
window->IDStack.resize(1);
|
|
|
|
|
|
- // Update stored window name when it changes (which can only happen with the "###" operator).
|
|
|
- // The title bar always display the 'name' parameter, so we only update storage if the title is displayed to the end-user in a different place.
|
|
|
- bool window_title_visible_elsewhere = (window->Viewport && window->Viewport->Window == window);
|
|
|
- if (!window_just_created && window_title_visible_elsewhere && strcmp(name, window->Name) != 0)
|
|
|
+ // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged).
|
|
|
+ // The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere.
|
|
|
+ bool window_title_visible_elsewhere = false;
|
|
|
+ if (window->Viewport && window->Viewport->Window == window)
|
|
|
+ window_title_visible_elsewhere = true;
|
|
|
+ else if (g.NavWindowingList != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0) // Window titles visible when using CTRL+TAB
|
|
|
+ window_title_visible_elsewhere = true;
|
|
|
+ if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0)
|
|
|
{
|
|
|
- IM_DELETE(window->Name);
|
|
|
- window->Name = ImStrdup(name);
|
|
|
+ size_t buf_len = (size_t)window->NameBufLen;
|
|
|
+ window->Name = ImStrdupcpy(window->Name, &buf_len, name);
|
|
|
+ window->NameBufLen = (int)buf_len;
|
|
|
}
|
|
|
|
|
|
// UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
|
|
@@ -9999,7 +10037,7 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSetting
|
|
|
if (!settings)
|
|
|
{
|
|
|
settings = ImGui::CreateNewWindowSettings(window->Name);
|
|
|
- window->SettingsIdx = g.SettingsWindows.index_from_pointer(settings);
|
|
|
+ window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings);
|
|
|
}
|
|
|
IM_ASSERT(settings->ID == window->ID);
|
|
|
settings->Pos = window->Pos - window->ViewportPos;
|