1
0
Fork 0
mirror of https://github.com/ocornut/imgui.git synced 2026-01-21 01:44:21 +00:00

Merge branch 'master' into docking

# Conflicts:
#	backends/imgui_impl_opengl3.cpp
#	imgui.cpp
#	imgui_internal.h
This commit is contained in:
ocornut 2024-01-10 18:34:08 +01:00
commit 2dc85e6e43
10 changed files with 345 additions and 133 deletions

223
imgui.cpp
View file

@ -1,4 +1,4 @@
// dear imgui, v1.90.1 WIP
// dear imgui, v1.90.1
// (main code and documentation)
// Help:
@ -4983,11 +4983,15 @@ void ImGui::NewFrame()
UpdateDebugToolStackQueries();
UpdateDebugToolFlashStyleColor();
if (g.DebugLocateFrames > 0 && --g.DebugLocateFrames == 0)
g.DebugLocateId = 0;
if (g.DebugLogClipperAutoDisableFrames > 0 && --g.DebugLogClipperAutoDisableFrames == 0)
{
DebugLog("(Debug Log: Auto-disabled ImGuiDebugLogFlags_EventClipper after 2 frames)\n");
g.DebugLogFlags &= ~ImGuiDebugLogFlags_EventClipper;
g.DebugLocateId = 0;
g.DebugBreakInLocateId = false;
}
if (g.DebugLogAutoDisableFrames > 0 && --g.DebugLogAutoDisableFrames == 0)
{
DebugLog("(Debug Log: Auto-disabled some ImGuiDebugLogFlags after 2 frames)\n");
g.DebugLogFlags &= ~g.DebugLogAutoDisableFlags;
g.DebugLogAutoDisableFlags = ImGuiDebugLogFlags_None;
}
// Create implicit/fallback window - which we will only render it if the user has added something to it.
@ -6742,6 +6746,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
if (window_just_created)
window = CreateNewWindow(name, flags);
// [DEBUG] Debug break requested by user
if (g.DebugBreakInWindow == window->ID)
IM_DEBUG_BREAK();
// Automatically disable manual moving/resizing when NoInputs is set
if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs)
flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
@ -8751,7 +8759,7 @@ const char* ImGui::GetKeyName(ImGuiKey key)
}
// ImGuiMod_Shortcut is translated to either Ctrl or Super.
void ImGui::GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size)
const char* ImGui::GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size)
{
ImGuiContext& g = *GImGui;
if (key_chord & ImGuiMod_Shortcut)
@ -8762,6 +8770,7 @@ void ImGui::GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_
(key_chord & ImGuiMod_Alt) ? "Alt+" : "",
(key_chord & ImGuiMod_Super) ? (g.IO.ConfigMacOSXBehaviors ? "Cmd+" : "Super+") : "",
GetKeyName((ImGuiKey)(key_chord & ~ImGuiMod_Mask_)));
return out_buf;
}
// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime)
@ -8836,11 +8845,15 @@ static void ImGui::UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt)
rt->EntriesNext.push_back(*routing_entry); // Write alive ones into new buffer
// Apply routing to owner if there's no owner already (RoutingCurr == None at this point)
// This is the result of previous frame's SetShortcutRouting() call.
if (routing_entry->Mods == g.IO.KeyMods)
{
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
if (owner_data->OwnerCurr == ImGuiKeyOwner_None)
{
owner_data->OwnerCurr = routing_entry->RoutingCurr;
//IMGUI_DEBUG_LOG("SetKeyOwner(%s, owner_id=0x%08X) via Routing\n", GetKeyName(key), routing_entry->RoutingCurr);
}
}
}
@ -8962,9 +8975,14 @@ bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiI
else
IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiInputFlags_RouteMask_)); // Check that only 1 routing flag is used
// [DEBUG] Debug break requested by user
if (g.DebugBreakInShortcutRouting == key_chord)
IM_DEBUG_BREAK();
if (flags & ImGuiInputFlags_RouteUnlessBgFocused)
if (g.NavWindow == NULL)
return false;
// Note how ImGuiInputFlags_RouteAlways won't set routing and thus won't set owner. May want to rework this?
if (flags & ImGuiInputFlags_RouteAlways)
return true;
@ -9876,10 +9894,11 @@ bool ImGui::TestKeyOwner(ImGuiKey key, ImGuiID owner_id)
// - SetKeyOwner(..., Any or None, Lock) : set lock
void ImGui::SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(IsNamedKeyOrModKey(key) && (owner_id != ImGuiKeyOwner_Any || (flags & (ImGuiInputFlags_LockThisFrame | ImGuiInputFlags_LockUntilRelease)))); // Can only use _Any with _LockXXX flags (to eat a key away without an ID to retrieve it)
IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetKeyOwner) == 0); // Passing flags not supported by this function!
//IMGUI_DEBUG_LOG("SetKeyOwner(%s, owner_id=0x%08X, flags=%08X)\n", GetKeyName(key), owner_id, flags);
ImGuiContext& g = *GImGui;
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
owner_data->OwnerCurr = owner_data->OwnerNext = owner_id;
@ -9948,6 +9967,9 @@ bool ImGui::IsKeyChordPressed(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiIn
bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags)
{
//ImGuiContext& g = *GImGui;
//IMGUI_DEBUG_LOG("Shortcut(%s, owner_id=0x%08X, flags=%X)\n", GetKeyChordName(key_chord, g.TempBuffer.Data, g.TempBuffer.Size), owner_id, flags);
// When using (owner_id == 0/Any): SetShortcutRouting() will use CurrentFocusScopeId and filter with this, so IsKeyPressed() is fine with he 0/Any.
if ((flags & ImGuiInputFlags_RouteMask_) == 0)
flags |= ImGuiInputFlags_RouteFocused;
@ -13037,6 +13059,7 @@ static void ImGui::NavUpdateWindowing()
}
// Start CTRL+Tab or Square+L/R window selection
// (g.ConfigNavWindowingKeyNext/g.ConfigNavWindowingKeyPrev defaults are ImGuiMod_Ctrl|ImGuiKey_Tab and ImGuiMod_Ctrl|ImGuiMod_Shift|ImGuiKey_Tab)
const ImGuiID owner_id = ImHashStr("###NavUpdateWindowing");
const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
@ -19432,14 +19455,15 @@ static int IMGUI_CDECL ViewportComparerByLastFocusedStampCount(const void* lhs,
// Draw an arbitrary US keyboard layout to visualize translated keys
void ImGui::DebugRenderKeyboardPreview(ImDrawList* draw_list)
{
const ImVec2 key_size = ImVec2(35.0f, 35.0f);
const float key_rounding = 3.0f;
const ImVec2 key_face_size = ImVec2(25.0f, 25.0f);
const ImVec2 key_face_pos = ImVec2(5.0f, 3.0f);
const float key_face_rounding = 2.0f;
const ImVec2 key_label_pos = ImVec2(7.0f, 4.0f);
const float scale = ImGui::GetFontSize() / 13.0f;
const ImVec2 key_size = ImVec2(35.0f, 35.0f) * scale;
const float key_rounding = 3.0f * scale;
const ImVec2 key_face_size = ImVec2(25.0f, 25.0f) * scale;
const ImVec2 key_face_pos = ImVec2(5.0f, 3.0f) * scale;
const float key_face_rounding = 2.0f * scale;
const ImVec2 key_label_pos = ImVec2(7.0f, 4.0f) * scale;
const ImVec2 key_step = ImVec2(key_size.x - 1.0f, key_size.y - 1.0f);
const float key_row_offset = 9.0f;
const float key_row_offset = 9.0f * scale;
ImVec2 board_min = GetCursorScreenPos();
ImVec2 board_max = ImVec2(board_min.x + 3 * key_step.x + 2 * key_row_offset + 10.0f, board_min.y + 3 * key_step.y + 10.0f);
@ -19593,6 +19617,9 @@ void ImGui::ShowMetricsWindow(bool* p_open)
return;
}
// [DEBUG] Clear debug breaks hooks after exactly one cycle.
DebugBreakClearData();
// Basic info
Text("Dear ImGui %s", GetVersion());
Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
@ -19652,24 +19679,16 @@ void ImGui::ShowMetricsWindow(bool* p_open)
// Tools
if (TreeNode("Tools"))
{
bool show_encoding_viewer = TreeNode("UTF-8 Encoding viewer");
SameLine();
MetricsHelpMarker("You can also call ImGui::DebugTextEncoding() from your code with a given string to test that your UTF-8 encoding settings are correct.");
if (show_encoding_viewer)
{
static char buf[100] = "";
SetNextItemWidth(-FLT_MIN);
InputText("##Text", buf, IM_ARRAYSIZE(buf));
if (buf[0] != 0)
DebugTextEncoding(buf);
TreePop();
}
// Debug Break features
// The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted.
if (Checkbox("Show Item Picker", &g.DebugItemPickerActive) && g.DebugItemPickerActive)
DebugStartItemPicker();
SeparatorTextEx(0, "Debug breaks", NULL, CalcTextSize("(?)").x + g.Style.SeparatorTextPadding.x);
SameLine();
MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash.");
if (Checkbox("Show Item Picker", &g.DebugItemPickerActive) && g.DebugItemPickerActive)
DebugStartItemPicker();
Checkbox("Show \"Debug Break\" buttons in other sections", &g.IO.ConfigDebugIsDebuggerPresent);
SeparatorText("Visualize");
Checkbox("Show Debug Log", &cfg->ShowDebugLog);
SameLine();
@ -19742,10 +19761,24 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
Checkbox("Show groups rectangles", &g.DebugShowGroupRects); // Storing in context as this is used by group code and prefers to be in hot-data
SeparatorText("Validate");
Checkbox("Debug Begin/BeginChild return value", &io.ConfigDebugBeginReturnValueLoop);
SameLine();
MetricsHelpMarker("Some calls to Begin()/BeginChild() will return false.\n\nWill cycle through window depths then repeat. Windows should be flickering while running.");
Checkbox("UTF-8 Encoding viewer", &cfg->ShowTextEncodingViewer);
SameLine();
MetricsHelpMarker("You can also call ImGui::DebugTextEncoding() from your code with a given string to test that your UTF-8 encoding settings are correct.");
if (cfg->ShowTextEncodingViewer)
{
static char buf[64] = "";
SetNextItemWidth(-FLT_MIN);
InputText("##DebugTextEncodingBuf", buf, IM_ARRAYSIZE(buf));
if (buf[0] != 0)
DebugTextEncoding(buf);
}
TreePop();
}
@ -20054,7 +20087,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
Text("KEY OWNERS");
{
Indent();
if (BeginChild("##owners", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY, ImGuiWindowFlags_NoSavedSettings))
if (BeginChild("##owners", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY, ImGuiWindowFlags_NoSavedSettings))
for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
{
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
@ -20068,9 +20101,11 @@ void ImGui::ShowMetricsWindow(bool* p_open)
Unindent();
}
Text("SHORTCUT ROUTING");
SameLine();
MetricsHelpMarker("Declared shortcut routes automatically set key owner when mods matches.");
{
Indent();
if (BeginChild("##routes", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY, ImGuiWindowFlags_NoSavedSettings))
if (BeginChild("##routes", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY, ImGuiWindowFlags_NoSavedSettings))
for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
{
ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable;
@ -20078,9 +20113,15 @@ void ImGui::ShowMetricsWindow(bool* p_open)
{
char key_chord_name[64];
ImGuiKeyRoutingData* routing_data = &rt->Entries[idx];
GetKeyChordName(key | routing_data->Mods, key_chord_name, IM_ARRAYSIZE(key_chord_name));
Text("%s: 0x%08X", key_chord_name, routing_data->RoutingCurr);
ImGuiKeyChord key_chord = key | routing_data->Mods;
Text("%s: 0x%08X", GetKeyChordName(key_chord, key_chord_name, IM_ARRAYSIZE(key_chord_name)), routing_data->RoutingCurr);
DebugLocateItemOnHover(routing_data->RoutingCurr);
if (g.IO.ConfigDebugIsDebuggerPresent)
{
SameLine();
if (DebugBreakButton("**DebugBreak**", "in SetShortcutRouting() for this KeyChord"))
g.DebugBreakInShortcutRouting = key_chord;
}
idx = routing_data->NextEntryIndex;
}
}
@ -20207,6 +20248,64 @@ void ImGui::ShowMetricsWindow(bool* p_open)
End();
}
void ImGui::DebugBreakClearData()
{
// Those fields are scattered in their respective subsystem to stay in hot-data locations
ImGuiContext& g = *GImGui;
g.DebugBreakInWindow = 0;
g.DebugBreakInTable = 0;
g.DebugBreakInShortcutRouting = ImGuiKey_None;
}
void ImGui::DebugBreakButtonTooltip(bool keyboard_only, const char* description_of_location)
{
if (!BeginItemTooltip())
return;
Text("To call IM_DEBUG_BREAK() %s:", description_of_location);
Separator();
TextUnformatted(keyboard_only ? "- Press 'Pause/Break' on keyboard." : "- Press 'Pause/Break' on keyboard.\n- or Click (may alter focus/active id).\n- or navigate using keyboard and press space.");
Separator();
TextUnformatted("Choose one way that doesn't interfere with what you are trying to debug!\nYou need a debugger attached or this will crash!");
EndTooltip();
}
// Special button that doesn't take focus, doesn't take input owner, and can be activated without a click etc.
// In order to reduce interferences with the contents we are trying to debug into.
bool ImGui::DebugBreakButton(const char* label, const char* description_of_location)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
ImGuiContext& g = *GImGui;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
ImVec2 pos = window->DC.CursorPos + ImVec2(0.0f, window->DC.CurrLineTextBaseOffset);
ImVec2 size = ImVec2(label_size.x + g.Style.FramePadding.x * 2.0f, label_size.y);
const ImRect bb(pos, pos + size);
ItemSize(size, 0.0f);
if (!ItemAdd(bb, id))
return false;
// WE DO NOT USE ButtonEx() or ButtonBehavior() in order to reduce our side-effects.
bool hovered = ItemHoverable(bb, id, g.CurrentItemFlags);
bool pressed = hovered && (IsKeyChordPressed(g.DebugBreakKeyChord) || IsMouseClicked(0) || g.NavActivateId == id);
DebugBreakButtonTooltip(false, description_of_location);
ImVec4 col4f = GetStyleColorVec4(hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
ImVec4 hsv;
ColorConvertRGBtoHSV(col4f.x, col4f.y, col4f.z, hsv.x, hsv.y, hsv.z);
ColorConvertHSVtoRGB(hsv.x + 0.20f, hsv.y, hsv.z, col4f.x, col4f.y, col4f.z);
RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, GetColorU32(col4f), true, g.Style.FrameRounding);
RenderTextClipped(bb.Min, bb.Max, label, NULL, &label_size, g.Style.ButtonTextAlign, &bb);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return pressed;
}
// [DEBUG] Display contents of Columns
void ImGui::DebugNodeColumns(ImGuiOldColumns* columns)
{
@ -20644,6 +20743,9 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
if (window->MemoryCompacted)
TextDisabled("Note: some memory buffers have been compacted/freed.");
if (g.IO.ConfigDebugIsDebuggerPresent && DebugBreakButton("**DebugBreak**", "in Begin()"))
g.DebugBreakInWindow = window->ID;
ImGuiWindowFlags flags = window->Flags;
DebugNodeDrawList(window, window->Viewport, window->DrawList, "DrawList");
BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f) Ideal (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y, window->ContentSizeIdeal.x, window->ContentSizeIdeal.y);
@ -20757,6 +20859,29 @@ void ImGui::DebugLogV(const char* fmt, va_list args)
#endif
}
// FIXME-LAYOUT: To be done automatically via layout mode once we rework ItemSize/ItemAdd into ItemLayout.
static void SameLineOrWrap(const ImVec2& size)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImVec2 pos(window->DC.CursorPosPrevLine.x + g.Style.ItemSpacing.x, window->DC.CursorPosPrevLine.y);
if (window->ClipRect.Contains(ImRect(pos, pos + size)))
ImGui::SameLine();
}
static void ShowDebugLogFlag(const char* name, ImGuiDebugLogFlags flags)
{
ImGuiContext& g = *GImGui;
ImVec2 size(ImGui::GetFrameHeight() + g.Style.ItemInnerSpacing.x + ImGui::CalcTextSize(name).x, ImGui::GetFrameHeight());
SameLineOrWrap(size); // FIXME-LAYOUT: To be done automatically once we rework ItemSize/ItemAdd into ItemLayout.
if (ImGui::CheckboxFlags(name, &g.DebugLogFlags, flags) && g.IO.KeyShift && (g.DebugLogFlags & flags) != 0)
{
g.DebugLogAutoDisableFrames = 2;
g.DebugLogAutoDisableFlags |= flags;
}
ImGui::SetItemTooltip("Hold SHIFT when clicking to enable for 2 frames only (useful for spammy log entries)");
}
void ImGui::ShowDebugLogWindow(bool* p_open)
{
ImGuiContext& g = *GImGui;
@ -20769,15 +20894,15 @@ void ImGui::ShowDebugLogWindow(bool* p_open)
}
CheckboxFlags("All", &g.DebugLogFlags, ImGuiDebugLogFlags_EventMask_);
SameLine(); CheckboxFlags("ActiveId", &g.DebugLogFlags, ImGuiDebugLogFlags_EventActiveId);
SameLine(); CheckboxFlags("Focus", &g.DebugLogFlags, ImGuiDebugLogFlags_EventFocus);
SameLine(); CheckboxFlags("Popup", &g.DebugLogFlags, ImGuiDebugLogFlags_EventPopup);
SameLine(); CheckboxFlags("Nav", &g.DebugLogFlags, ImGuiDebugLogFlags_EventNav);
SameLine(); if (CheckboxFlags("Clipper", &g.DebugLogFlags, ImGuiDebugLogFlags_EventClipper)) { g.DebugLogClipperAutoDisableFrames = 2; } if (IsItemHovered()) SetTooltip("Clipper log auto-disabled after 2 frames");
//SameLine(); CheckboxFlags("Selection", &g.DebugLogFlags, ImGuiDebugLogFlags_EventSelection);
SameLine(); CheckboxFlags("IO", &g.DebugLogFlags, ImGuiDebugLogFlags_EventIO);
SameLine(); CheckboxFlags("Docking", &g.DebugLogFlags, ImGuiDebugLogFlags_EventDocking);
SameLine(); CheckboxFlags("Viewport", &g.DebugLogFlags, ImGuiDebugLogFlags_EventViewport);
ShowDebugLogFlag("ActiveId", ImGuiDebugLogFlags_EventActiveId);
ShowDebugLogFlag("Clipper", ImGuiDebugLogFlags_EventClipper);
ShowDebugLogFlag("Focus", ImGuiDebugLogFlags_EventFocus);
ShowDebugLogFlag("IO", ImGuiDebugLogFlags_EventIO);
ShowDebugLogFlag("Nav", ImGuiDebugLogFlags_EventNav);
ShowDebugLogFlag("Popup", ImGuiDebugLogFlags_EventPopup);
//ShowDebugLogFlag("Selection", ImGuiDebugLogFlags_EventSelection);
ShowDebugLogFlag("Docking", ImGuiDebugLogFlags_EventDocking);
ShowDebugLogFlag("Viewport", ImGuiDebugLogFlags_EventViewport);
if (SmallButton("Clear"))
{
@ -20866,6 +20991,7 @@ void ImGui::DebugLocateItem(ImGuiID target_id)
ImGuiContext& g = *GImGui;
g.DebugLocateId = target_id;
g.DebugLocateFrames = 2;
g.DebugBreakInLocateId = false;
}
void ImGui::DebugLocateItemOnHover(ImGuiID target_id)
@ -20875,11 +21001,24 @@ void ImGui::DebugLocateItemOnHover(ImGuiID target_id)
ImGuiContext& g = *GImGui;
DebugLocateItem(target_id);
GetForegroundDrawList(g.CurrentWindow)->AddRect(g.LastItemData.Rect.Min - ImVec2(3.0f, 3.0f), g.LastItemData.Rect.Max + ImVec2(3.0f, 3.0f), DEBUG_LOCATE_ITEM_COLOR);
// Can't easily use a context menu here because it will mess with focus, active id etc.
if (g.IO.ConfigDebugIsDebuggerPresent && g.MouseStationaryTimer > 1.0f)
{
DebugBreakButtonTooltip(false, "in ItemAdd()");
if (IsKeyChordPressed(g.DebugBreakKeyChord))
g.DebugBreakInLocateId = true;
}
}
void ImGui::DebugLocateItemResolveWithLastItem()
{
ImGuiContext& g = *GImGui;
// [DEBUG] Debug break requested by user
if (g.DebugBreakInLocateId)
IM_DEBUG_BREAK();
ImGuiLastItemData item_data = g.LastItemData;
g.DebugLocateId = 0;
ImDrawList* draw_list = GetForegroundDrawList(g.CurrentWindow);