Merge remote-tracking branch 'origin' into 2015-03-antialiased-primitives

This commit is contained in:
ocornut 2015-04-07 13:51:01 +01:00
commit 323ae8326e
12 changed files with 557 additions and 286 deletions

View File

@ -1,6 +1,7 @@
ImGui
=====
[![Build Status](https://travis-ci.org/ocornut/imgui.svg?branch=master)](https://travis-ci.org/ocornut/imgui)
[![Coverity Status](https://scan.coverity.com/projects/4720/badge.svg)](https://scan.coverity.com/projects/4720)
[![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/imgui) [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U)

View File

@ -1,3 +1,9 @@
Those are standalone ready-to-build applications to demonstrate ImGui.
Unfortunately in 2015 it is still a massive pain to create and maintain portable build files.
I choose to provide Visual Studio 10 .sln files and Makefile for Linux/OSX.
Please let me know if they don't work with your setup!
You can probably just import the .cpp files into your own system and figure out the linkage from there.
opengl_example/
OpenGL example, using GLFW + fixed pipeline.

View File

@ -149,6 +149,7 @@ int main(int, char**)
// Setup ImGui binding
ImGui_ImplDX11_Init(hwnd, g_pd3dDevice, g_pd3dDeviceContext);
//ImGuiIO& io = ImGui::GetIO();
//ImFont* my_font0 = io.Fonts->AddFontDefault();
//ImFont* my_font1 = io.Fonts->AddFontFromFileTTF("../../extra_fonts/DroidSans.ttf", 16.0f);
//ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("../../extra_fonts/Karla-Regular.ttf", 16.0f);
@ -176,7 +177,7 @@ int main(int, char**)
// 1. Show a simple window
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
{
static float f;
static float f = 0.0f;
ImGui::Text("Hello, world!");
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
ImGui::ColorEdit3("clear color", (float*)&clear_col);

View File

@ -57,11 +57,12 @@ static void ImGui_ImplDX9_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_
}
}
g_pVB->Unlock();
g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof( CUSTOMVERTEX ) );
g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
// Setup render state: alpha-blending, no face culling, no depth testing
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing
g_pd3dDevice->SetPixelShader( NULL );
g_pd3dDevice->SetVertexShader( NULL );
g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, false );
g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, false );

View File

@ -73,6 +73,7 @@ int main(int, char**)
// Setup ImGui binding
ImGui_ImplDX9_Init(hwnd, g_pd3dDevice);
//ImGuiIO& io = ImGui::GetIO();
//ImFont* my_font0 = io.Fonts->AddFontDefault();
//ImFont* my_font1 = io.Fonts->AddFontFromFileTTF("../../extra_fonts/DroidSans.ttf", 16.0f);
//ImFont* my_font2 = io.Fonts->AddFontFromFileTTF("../../extra_fonts/Karla-Regular.ttf", 16.0f);
@ -103,7 +104,7 @@ int main(int, char**)
// 1. Show a simple window
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
{
static float f;
static float f = 0.0f;
ImGui::Text("Hello, world!");
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
ImGui::ColorEdit3("clear color", (float*)&clear_col);

View File

@ -48,7 +48,7 @@ int main(int, char**)
// 1. Show a simple window
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
{
static float f;
static float f = 0.0f;
ImGui::Text("Hello, world!");
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
ImGui::ColorEdit3("clear color", (float*)&clear_color);

View File

@ -87,6 +87,7 @@ static void ImGui_ImplGlfw_RenderDrawLists(ImDrawList** const cmd_lists, int cmd
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindTexture(GL_TEXTURE_2D, 0);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);

View File

@ -42,7 +42,7 @@ int main(int, char**)
// 1. Show a simple window
// Tip: if we don't call ImGui::Begin()/ImGui::End() the widgets appears in a window automatically called "Debug"
{
static float f;
static float f = 0.0f;
ImGui::Text("Hello, world!");
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
ImGui::ColorEdit3("clear color", (float*)&clear_color);

View File

@ -1,8 +1,9 @@
The code in imgui.cpp embeds a copy of 'ProggyClean.ttf' that you can use without any external files.
Those are only provided as a convenience, you can load your own .TTF files.
---------------------------------
EXTRA FONTS FOR IMGUI
INCLUDED FONTS
---------------------------------
DroidSans.ttf

View File

@ -31,7 +31,7 @@
//---- Include imgui_user.h at the end of imgui.h
//#define IMGUI_INCLUDE_IMGUI_USER_H
//---- Define implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4.
//---- Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4.
/*
#define IM_VEC2_CLASS_EXTRA \
ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \

465
imgui.cpp
View File

@ -142,6 +142,8 @@
Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix.
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.
- 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
- 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
- 2015/03/17 (1.36) - renamed GetItemRectMin()/GetItemRectMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function (will obsolete).
- 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
- 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function (will obsolete).
@ -565,6 +567,8 @@ ImGuiStyle::ImGuiStyle()
Colors[ImGuiCol_Border] = ImVec4(0.70f, 0.70f, 0.70f, 1.00f);
Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
Colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.30f); // Background of checkbox, radio button, plot, slider, text input
Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.90f, 0.80f, 0.80f, 0.40f);
Colors[ImGuiCol_FrameBgActive] = ImVec4(0.90f, 0.65f, 0.65f, 0.45f);
Colors[ImGuiCol_TitleBg] = ImVec4(0.50f, 0.50f, 1.00f, 0.45f);
Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f);
Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.40f, 0.40f, 0.80f, 0.15f);
@ -572,8 +576,6 @@ ImGuiStyle::ImGuiStyle()
Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f);
Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 0.40f);
Colors[ImGuiCol_ComboBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.99f);
Colors[ImGuiCol_CheckHovered] = ImVec4(0.60f, 0.40f, 0.40f, 0.45f);
Colors[ImGuiCol_CheckActive] = ImVec4(0.65f, 0.50f, 0.50f, 0.55f);
Colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f);
Colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 1.00f);
@ -655,9 +657,11 @@ void ImGuiIO::AddInputCharacter(ImWchar c)
const float PI = 3.14159265358979323846f;
#ifdef INT_MAX
#define IM_INT_MIN INT_MIN
#define IM_INT_MAX INT_MAX
#else
#define IM_INT_MAX 2147483647
#define IM_INT_MIN (-2147483647-1)
#define IM_INT_MAX (2147483647)
#endif
// Play it nice with Windows users. Notepad in 2015 still doesn't display text data with Unix-style \n.
@ -1018,6 +1022,7 @@ struct ImGuiDrawContext
LastItemID = 0;
LastItemRect = ImRect(0.0f,0.0f,0.0f,0.0f);
LastItemHoveredAndUsable = LastItemHoveredRect = false;
ColorEditMode = ImGuiColorEditMode_RGB;
StateStorage = NULL;
ColumnsStartX = 0.0f;
@ -1116,6 +1121,7 @@ struct ImGuiState
ImGuiWindow* MovedWindow; // Track the child window we clicked on to move a window. Only valid if ActiveID is the "#MOVE" identifier of a window.
float SettingsDirtyTimer;
ImVector<ImGuiIniData*> Settings;
int DisableHideTextAfterDoubleHash;
ImVector<ImGuiColMod> ColorModifiers;
ImVector<ImGuiStyleMod> StyleModifiers;
ImVector<ImFont*> FontStack;
@ -1140,9 +1146,12 @@ struct ImGuiState
// Widget state
ImGuiTextEditState InputTextState;
ImGuiID SliderAsInputTextId;
ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc.
ImGuiStorage ColorEditModeStorage; // for user selection
ImGuiID ActiveComboID;
ImVec2 DragLastMouseDelta;
float DragSpeedScaleSlow;
float DragSpeedScaleFast;
float ScrollbarClickDeltaToGrabCenter; // distance between mouse and center of grab box, normalized in parent space
char Tooltip[1024];
char* PrivateClipboard; // if no custom clipboard handler is defined
@ -1181,6 +1190,7 @@ struct ImGuiState
ActiveIdIsFocusedOnly = false;
MovedWindow = NULL;
SettingsDirtyTimer = 0.0f;
DisableHideTextAfterDoubleHash = 0;
SetNextWindowPosVal = ImVec2(0.0f, 0.0f);
SetNextWindowPosCond = 0;
@ -1192,12 +1202,17 @@ struct ImGuiState
SetNextTreeNodeOpenedVal = false;
SetNextTreeNodeOpenedCond = 0;
SliderAsInputTextId = 0;
ScalarAsInputTextId = 0;
ActiveComboID = 0;
DragLastMouseDelta = ImVec2(0.0f, 0.0f);
DragSpeedScaleSlow = 0.01f;
DragSpeedScaleFast = 10.0f;
ScrollbarClickDeltaToGrabCenter = 0.0f;
memset(Tooltip, 0, sizeof(Tooltip));
PrivateClipboard = NULL;
MouseCursor = ImGuiMouseCursor_Arrow;
LogEnabled = false;
LogFile = NULL;
LogClipboard = NULL;
@ -1271,7 +1286,7 @@ public:
float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; }
float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0 : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; }
ImRect TitleBarRect() const { return ImRect(Pos, Pos + ImVec2(SizeFull.x, TitleBarHeight())); }
ImVec2 WindowPadding() const { return ((Flags & ImGuiWindowFlags_ChildWindow) && !(Flags & ImGuiWindowFlags_ShowBorders)) ? ImVec2(0,0) : GImGui->Style.WindowPadding; }
ImVec2 WindowPadding() const { return ((Flags & ImGuiWindowFlags_ChildWindow) && !(Flags & ImGuiWindowFlags_ShowBorders) && !(Flags & ImGuiWindowFlags_ComboBox)) ? ImVec2(0,0) : GImGui->Style.WindowPadding; }
ImU32 Color(ImGuiCol idx, float a=1.f) const { ImVec4 c = GImGui->Style.Colors[idx]; c.w *= GImGui->Style.Alpha * a; return ImGui::ColorConvertFloat4ToU32(c); }
ImU32 Color(const ImVec4& col) const { ImVec4 c = col; c.w *= GImGui->Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); }
};
@ -1663,6 +1678,7 @@ static inline void AddDrawListToRenderList(ImVector<ImDrawList*>& out_render_lis
if (draw_list->commands.back().vtx_count == 0)
draw_list->commands.pop_back();
out_render_list.push_back(draw_list);
GImGui->IO.MetricsVertices += (int)draw_list->vtx_buffer.size();
}
}
@ -1974,7 +1990,6 @@ void ImGui::NewFrame()
float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
float scale = new_font_scale / window->FontWindowScale;
window->FontWindowScale = new_font_scale;
g.FontSize = window->CalcFontSize();
const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
window->Pos += offset;
@ -1989,7 +2004,7 @@ void ImGui::NewFrame()
if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse))
{
const int scroll_lines = (window->Flags & ImGuiWindowFlags_ComboBox) ? 3 : 5;
window->NextScrollY -= g.IO.MouseWheel * g.FontSize * scroll_lines;
window->NextScrollY -= g.IO.MouseWheel * window->CalcFontSize() * scroll_lines;
}
}
}
@ -2147,13 +2162,21 @@ void ImGui::Render()
g.CurrentWindow->Visible = false;
ImGui::End();
// Select window for move/focus when we're done with all our widgets (we use the root window ID here)
if (g.ActiveId == 0 && g.HoveredId == 0 && g.HoveredRootWindow != NULL && g.IO.MouseClicked[0])
if (g.ActiveId == 0 && g.HoveredId == 0 && g.IO.MouseClicked[0])
{
if (g.HoveredRootWindow != NULL)
{
// Select window for move/focus when we're done with all our widgets (we use the root window ID here)
IM_ASSERT(g.MovedWindow == NULL);
g.MovedWindow = g.HoveredWindow;
SetActiveId(g.HoveredRootWindow->MoveID);
}
else if (g.FocusedWindow != NULL)
{
// Clicking on void disable focus
FocusWindow(NULL);
}
}
// Sort the window list so that all child windows are after their parent
// We cannot do that on FocusWindow() because childs may not exist yet
@ -2189,6 +2212,7 @@ void ImGui::Render()
}
// Gather windows to render
g.IO.MetricsVertices = 0;
for (size_t i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++)
g.RenderDrawLists[i].resize(0);
for (size_t i = 0; i != g.Windows.size(); i++)
@ -2250,8 +2274,18 @@ static const char* FindTextDisplayEnd(const char* text, const char* text_end =
const char* text_display_end = text;
if (!text_end)
text_end = (const char*)-1;
ImGuiState& g = *GImGui;
if (g.DisableHideTextAfterDoubleHash > 0)
{
while (text_display_end < text_end && *text_display_end != '\0')
text_display_end++;
}
else
{
while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
text_display_end++;
}
return text_display_end;
}
@ -3109,7 +3143,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
// Clamp into view
if (!(window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Tooltip))
{
if (window->AutoFitFrames == 0 && g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
if (window->AutoFitFrames <= 0 && g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
{
ImVec2 clip_min = style.DisplaySafeAreaPadding;
ImVec2 clip_max = g.IO.DisplaySize - style.DisplaySafeAreaPadding;
@ -3406,7 +3440,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
window->Visible = false;
// Return false if we don't intend to display anything to allow user to perform an early out optimization
window->SkipItems = (window->Collapsed || !window->Visible) && window->AutoFitFrames == 0;
window->SkipItems = (window->Collapsed || !window->Visible) && window->AutoFitFrames <= 0;
return !window->SkipItems;
}
@ -3448,7 +3482,7 @@ static void Scrollbar(ImGuiWindow* window)
// The grabable box size generally represent the amount visible (vs the total scrollable amount)
// But we maintain a minimum size in pixel to allow for the user to still aim inside.
const float grab_h_pixels = ImMax(style.GrabMinSize, scrollbar_height * ImSaturate(window->Size.y / ImMax(window->SizeContents.y, window->Size.y)));
const float grab_h_pixels = ImMin(ImMax(scrollbar_height * ImSaturate(window->Size.y / ImMax(window->SizeContents.y, window->Size.y)), style.GrabMinSize), scrollbar_height);
const float grab_h_norm = grab_h_pixels / scrollbar_height;
// Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar().
@ -3507,6 +3541,10 @@ static void FocusWindow(ImGuiWindow* window)
// Always mark the window we passed as focused. This is used for keyboard interactions such as tabbing.
g.FocusedWindow = window;
// Passing NULL allow to disable keyboard focus
if (!window)
return;
// And move its root window to the top of the pile
if (window->RootWindow)
window = window->RootWindow;
@ -3714,6 +3752,8 @@ const char* ImGui::GetStyleColName(ImGuiCol idx)
case ImGuiCol_Border: return "Border";
case ImGuiCol_BorderShadow: return "BorderShadow";
case ImGuiCol_FrameBg: return "FrameBg";
case ImGuiCol_FrameBgHovered: return "FrameBgHovered";
case ImGuiCol_FrameBgActive: return "FrameBgActive";
case ImGuiCol_TitleBg: return "TitleBg";
case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed";
case ImGuiCol_ScrollbarBg: return "ScrollbarBg";
@ -3721,8 +3761,6 @@ const char* ImGui::GetStyleColName(ImGuiCol idx)
case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
case ImGuiCol_ComboBg: return "ComboBg";
case ImGuiCol_CheckHovered: return "CheckHovered";
case ImGuiCol_CheckActive: return "CheckActive";
case ImGuiCol_CheckMark: return "CheckMark";
case ImGuiCol_SliderGrab: return "SliderGrab";
case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
@ -3890,11 +3928,18 @@ void ImGui::SetWindowFocus()
}
void ImGui::SetWindowFocus(const char* name)
{
if (name)
{
ImGuiWindow* window = FindWindowByName(name);
if (window)
FocusWindow(window);
}
else
{
FocusWindow(NULL);
}
}
void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiSetCond cond)
{
@ -4984,24 +5029,24 @@ static bool SliderFloatAsInputText(const char* label, float* v, ImGuiID id, int
char text_buf[64];
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%.*f", decimal_precision, *v);
SetActiveId(g.SliderAsInputTextId);
SetActiveId(g.ScalarAsInputTextId);
g.HoveredId = 0;
// Our replacement widget will override the focus ID (registered previously to allow for a TAB focus to happen)
window->FocusItemUnregister();
bool value_changed = ImGui::InputText(label, text_buf, IM_ARRAYSIZE(text_buf), ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_AutoSelectAll);
if (g.SliderAsInputTextId == 0)
if (g.ScalarAsInputTextId == 0)
{
// First frame
IM_ASSERT(g.ActiveId == id); // InputText ID expected to match the Slider ID (else we'd need to store them both, which is also possible)
g.SliderAsInputTextId = g.ActiveId;
g.ScalarAsInputTextId = g.ActiveId;
g.HoveredId = id;
}
else if (g.ActiveId != g.SliderAsInputTextId)
else if (g.ActiveId != g.ScalarAsInputTextId)
{
// Release
g.SliderAsInputTextId = 0;
g.ScalarAsInputTextId = 0;
}
if (value_changed)
{
@ -5038,23 +5083,20 @@ static bool SliderBehavior(const ImRect& frame_bb, const ImRect& slider_bb, ImGu
// Draw frame
RenderFrame(frame_bb.Min, frame_bb.Max, window->Color(ImGuiCol_FrameBg), true, style.FrameRounding);
const bool is_finite = (v_min != -FLT_MAX && v_min != FLT_MAX && v_max != -FLT_MAX && v_max != FLT_MAX);
const bool is_non_linear = fabsf(power - 1.0f) > 0.0001f;
const float slider_sz = horizontal ? slider_bb.GetWidth() : slider_bb.GetHeight();
float grab_sz;
if (decimal_precision > 0 || !is_finite)
grab_sz = style.GrabMinSize;
if (decimal_precision > 0)
grab_sz = ImMin(style.GrabMinSize, slider_sz);
else
grab_sz = ImMax(1.0f * (slider_sz / (v_max-v_min+1.0f)), style.GrabMinSize); // Integer sliders, if possible have the grab size represent 1 unit
grab_sz = ImMin(ImMax(1.0f * (slider_sz / (v_max-v_min+1.0f)), style.GrabMinSize), slider_sz); // Integer sliders, if possible have the grab size represent 1 unit
const float slider_usable_sz = slider_sz - grab_sz;
const float slider_usable_pos_min = (horizontal ? slider_bb.Min.x : slider_bb.Min.y) + grab_sz*0.5f;
const float slider_usable_pos_max = (horizontal ? slider_bb.Max.x : slider_bb.Max.y) - grab_sz*0.5f;
bool value_changed = false;
if (is_finite)
{
// For logarithmic sliders that cross over sign boundary we want the exponential increase to be symmetric around 0.0f
float linear_zero_pos = 0.0f; // 0.0->1.0f
if (v_min * v_max < 0.0f)
@ -5163,7 +5205,6 @@ static bool SliderBehavior(const ImRect& frame_bb, const ImRect& slider_bb, ImGu
else
grab_bb = ImRect(ImVec2(frame_bb.Min.x + 2.0f, grab_pos - grab_sz*0.5f), ImVec2(frame_bb.Max.x - 2.0f, grab_pos + grab_sz*0.5f));
window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, window->Color(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab));
}
return value_changed;
}
@ -5189,7 +5230,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c
const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
// NB- we don't call ItemSize() yet becausae we may turn into a text edit box below
// NB- we don't call ItemSize() yet because we may turn into a text edit box below
if (!ItemAdd(total_bb, &id))
{
ItemSize(total_bb, style.FramePadding.y);
@ -5205,37 +5246,36 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c
int decimal_precision = 3;
ParseFormat(display_format, decimal_precision);
const bool tab_focus_requested = window->FocusItemRegister(g.ActiveId == id);
const bool is_finite = (v_min != -FLT_MAX && v_min != FLT_MAX && v_max != -FLT_MAX && v_max != FLT_MAX);
// Tabbing or CTRL-clicking through slider turns into an input box
// Tabbing or CTRL-clicking on Slider turns it into an input box
bool start_text_input = false;
const bool tab_focus_requested = window->FocusItemRegister(g.ActiveId == id);
if (tab_focus_requested || (hovered && g.IO.MouseClicked[0]))
{
SetActiveId(id);
FocusWindow(window);
const bool is_ctrl_down = g.IO.KeyCtrl;
if (tab_focus_requested || is_ctrl_down || !is_finite)
if (tab_focus_requested || is_ctrl_down)
{
start_text_input = true;
g.SliderAsInputTextId = 0;
g.ScalarAsInputTextId = 0;
}
}
if (start_text_input || (g.ActiveId == id && id == g.SliderAsInputTextId))
if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
return SliderFloatAsInputText(label, v, id, decimal_precision);
ItemSize(total_bb, style.FramePadding.y);
// Actual slider behavior + render grab
bool value_changed = SliderBehavior(frame_bb, inner_bb, id, v, v_min, v_max, power, decimal_precision, true);
const bool value_changed = SliderBehavior(frame_bb, inner_bb, id, v, v_min, v_max, power, decimal_precision, true);
// Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
char value_buf[64];
char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v);
const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v);
const ImVec2 value_text_size = CalcTextSize(value_buf, value_buf_end, true);
RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x + style.FramePadding.x, inner_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), value_buf, value_buf_end, &value_text_size, frame_bb.Max);
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
return value_changed;
@ -5291,11 +5331,11 @@ bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float
return value_changed;
}
bool ImGui::SliderAngle(const char* label, float* v, float v_degrees_min, float v_degrees_max)
bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max)
{
float v_deg = *v * 360.0f / (2*PI);
float v_deg = (*v_rad) * 360.0f / (2*PI);
bool value_changed = ImGui::SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, "%.0f deg", 1.0f);
*v = v_deg * (2*PI) / 360.0f;
*v_rad = v_deg * (2*PI) / 360.0f;
return value_changed;
}
@ -5424,6 +5464,129 @@ bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const
return SliderIntN(label, v, 4, v_min, v_max, display_format);
}
// FIXME-WIP: Work in progress. May change API / behavior.
static bool DragScalarBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_step, float v_min, float v_max)
{
ImGuiState& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow();
const ImGuiStyle& style = g.Style;
// Draw frame
const ImU32 frame_col = window->Color(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding);
bool value_changed = false;
// Process clicking on the slider
if (g.ActiveId == id)
{
if (g.IO.MouseDown[0])
{
const ImVec2 mouse_drag_delta = ImGui::GetMouseDragDelta(0);
if (fabsf(mouse_drag_delta.x - g.DragLastMouseDelta.x) > 0.0f)
{
float step = v_step;
if (g.IO.KeyShift && g.DragSpeedScaleFast >= 0.0f)
step = v_step * g.DragSpeedScaleFast;
if (g.IO.KeyAlt && g.DragSpeedScaleSlow >= 0.0f)
step = v_step * g.DragSpeedScaleSlow;
*v += (mouse_drag_delta.x - g.DragLastMouseDelta.x) * step;
if (v_min < v_max)
*v = ImClamp(*v, v_min, v_max);
g.DragLastMouseDelta.x = mouse_drag_delta.x;
value_changed = true;
}
}
else
{
SetActiveId(0);
}
}
return value_changed;
}
bool ImGui::DragFloat(const char* label, float *v, float v_step, float v_min, float v_max, const char* display_format)
{
ImGuiState& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const float w = ImGui::CalcItemWidth();
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y) + style.FramePadding*2.0f);
const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
// NB- we don't call ItemSize() yet because we may turn into a text edit box below
if (!ItemAdd(total_bb, &id))
{
ItemSize(total_bb, style.FramePadding.y);
return false;
}
const bool hovered = IsHovered(frame_bb, id);
if (hovered)
g.HoveredId = id;
if (!display_format)
display_format = "%.3f";
int decimal_precision = 3;
ParseFormat(display_format, decimal_precision);
// Tabbing or CTRL-clicking on Drag turns it into an input box
bool start_text_input = false;
const bool tab_focus_requested = window->FocusItemRegister(g.ActiveId == id);
if (tab_focus_requested || (hovered && (g.IO.MouseClicked[0] | g.IO.MouseDoubleClicked[0])))
{
SetActiveId(id);
FocusWindow(window);
g.DragLastMouseDelta = ImVec2(0.f, 0.f);
if (tab_focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0])
{
start_text_input = true;
g.ScalarAsInputTextId = 0;
}
}
if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
return SliderFloatAsInputText(label, v, id, decimal_precision);
ItemSize(total_bb, style.FramePadding.y);
// Actual drag behavior
const bool value_changed = DragScalarBehavior(frame_bb, id, v, v_step, v_min, v_max);
// Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
char value_buf[64];
const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v);
const ImVec2 value_text_size = CalcTextSize(value_buf, value_buf_end, true);
RenderTextClipped(ImVec2(ImMax(frame_bb.Min.x + style.FramePadding.x, inner_bb.GetCenter().x - value_text_size.x*0.5f), frame_bb.Min.y + style.FramePadding.y), value_buf, value_buf_end, &value_text_size, frame_bb.Max);
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
return value_changed;
}
bool ImGui::DragInt(const char* label, int* v, int v_step, int v_min, int v_max, const char* display_format)
{
if (!display_format)
display_format = "%.0f";
float v_f = (float)*v;
bool value_changed = ImGui::DragFloat(label, &v_f, (float)v_step, (float)v_min, (float)v_max, display_format);
*v = (int)v_f;
return value_changed;
}
enum ImGuiPlotType
{
ImGuiPlotType_Lines,
@ -5595,7 +5758,7 @@ bool ImGui::Checkbox(const char* label, bool* v)
if (pressed)
*v = !(*v);
RenderFrame(check_bb.Min, check_bb.Max, window->Color((held && hovered) ? ImGuiCol_CheckActive : hovered ? ImGuiCol_CheckHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
RenderFrame(check_bb.Min, check_bb.Max, window->Color((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
if (*v)
{
const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight());
@ -5656,7 +5819,7 @@ bool ImGui::RadioButton(const char* label, bool active)
bool hovered, held;
bool pressed = ButtonBehavior(total_bb, id, &hovered, &held, true);
window->DrawList->AddCircleFilled(center, radius, window->Color((held && hovered) ? ImGuiCol_CheckActive : hovered ? ImGuiCol_CheckHovered : ImGuiCol_FrameBg), 16);
window->DrawList->AddCircleFilled(center, radius, window->Color((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16);
if (active)
{
const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight());
@ -6433,6 +6596,7 @@ static bool InputIntN(const char* label, int* v, int components)
ImGui::PopItemWidth();
ImGui::PopID();
window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, style.FramePadding.y);
ImGui::TextUnformatted(label, FindTextDisplayEnd(label));
ImGui::EndGroup();
@ -6563,11 +6727,12 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
const ImVec2 backup_pos = ImGui::GetCursorPos();
const float popup_off_x = 0.0f;//style.ItemInnerSpacing.x;
const float popup_height = (label_size.y + style.ItemSpacing.y) * ImMin(items_count, height_in_items) + style.WindowPadding.y;
const float popup_height = (label_size.y + style.ItemSpacing.y) * ImMin(items_count, height_in_items) + (style.FramePadding.y * 3);
const ImRect popup_rect(ImVec2(frame_bb.Min.x+popup_off_x, frame_bb.Max.y), ImVec2(frame_bb.Max.x+popup_off_x, frame_bb.Max.y + popup_height));
ImGui::SetCursorPos(popup_rect.Min - window->Pos);
const ImGuiWindowFlags flags = ImGuiWindowFlags_ComboBox | ((window->Flags & ImGuiWindowFlags_ShowBorders) ? ImGuiWindowFlags_ShowBorders : 0);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding);
ImGui::BeginChild("#ComboBox", popup_rect.GetSize(), false, flags);
ImGui::Spacing();
@ -6595,6 +6760,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
ImGui::PopID();
}
ImGui::EndChild();
ImGui::PopStyleVar();
ImGui::SetCursorPos(backup_pos);
if (!combo_item_active && g.ActiveId != 0)
@ -6621,8 +6787,9 @@ bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg)
const float w = ImMax(label_size.x, window->Pos.x + ImGui::GetContentRegionMax().x - style.AutoFitPadding.x - window->DC.CursorPos.x);
const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : w, size_arg.y != 0.0f ? size_arg.y : label_size.y);
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
ItemSize(bb);
bb.Max.x += style.AutoFitPadding.x;
// Selectables are meant to be tightly packed together. So for both rendering and collision we extend to compensate for spacing.
ImRect bb_with_spacing = bb;
@ -6822,19 +6989,12 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha)
if (edit_mode == ImGuiColorEditMode_UserSelect || edit_mode == ImGuiColorEditMode_UserSelectShowButton)
edit_mode = g.ColorEditModeStorage.GetInt(id, 0) % 3;
float fx = col[0];
float fy = col[1];
float fz = col[2];
float fw = col[3];
const ImVec4 col_display(fx, fy, fz, 1.0f);
float f[4] = { col[0], col[1], col[2], col[3] };
if (edit_mode == ImGuiColorEditMode_HSV)
ImGui::ColorConvertRGBtoHSV(fx, fy, fz, fx, fy, fz);
ImGui::ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]);
int ix = (int)(fx * 255.0f + 0.5f);
int iy = (int)(fy * 255.0f + 0.5f);
int iz = (int)(fz * 255.0f + 0.5f);
int iw = (int)(fw * 255.0f + 0.5f);
int i[4] = { (int)(f[0] * 255.0f + 0.5f), (int)(f[1] * 255.0f + 0.5f), (int)(f[2] * 255.0f + 0.5f), (int)(f[3] * 255.0f + 0.5f) };
int components = alpha ? 4 : 3;
bool value_changed = false;
@ -6842,34 +7002,35 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha)
ImGui::BeginGroup();
ImGui::PushID(label);
bool hsv = (edit_mode == 1);
const bool hsv = (edit_mode == 1);
switch (edit_mode)
{
case ImGuiColorEditMode_RGB:
case ImGuiColorEditMode_HSV:
{
// 0: RGB 0..255 Sliders
// 1: HSV 0..255 Sliders
// RGB/HSV 0..255 Sliders
const float w_items_all = w_full - (square_sz + style.ItemInnerSpacing.x);
const float w_item_one = ImMax(1.0f, (float)(int)((w_items_all - (style.FramePadding.x*2.0f + style.ItemInnerSpacing.x) * (components-1)) / (float)components));
const float w_item_last = ImMax(1.0f, (float)(int)(w_items_all - (w_item_one + style.FramePadding.x*2.0f + style.ItemInnerSpacing.x) * (components-1)));
const bool hide_prefix = (w_item_one <= CalcTextSize("M:999").x);
const char* ids[4] = { "##X", "##Y", "##Z", "##W" };
const char* fmt_table[3][4] =
{
{ "%3.0f", "%3.0f", "%3.0f", "%3.0f" },
{ "R:%3.0f", "G:%3.0f", "B:%3.0f", "A:%3.0f" },
{ "H:%3.0f", "S:%3.0f", "V:%3.0f", "A:%3.0f" }
};
const char** fmt = hide_prefix ? fmt_table[0] : hsv ? fmt_table[2] : fmt_table[1];
ImGui::PushItemWidth(w_item_one);
value_changed |= ImGui::SliderInt("##X", &ix, 0, 255, hsv ? "H:%3.0f" : "R:%3.0f");
ImGui::SameLine(0, (int)style.ItemInnerSpacing.x);
value_changed |= ImGui::SliderInt("##Y", &iy, 0, 255, hsv ? "S:%3.0f" : "G:%3.0f");
ImGui::SameLine(0, (int)style.ItemInnerSpacing.x);
if (alpha)
for (int n = 0; n < components; n++)
{
value_changed |= ImGui::SliderInt("##Z", &iz, 0, 255, hsv ? "V:%3.0f" : "B:%3.0f");
if (n > 0)
ImGui::SameLine(0, (int)style.ItemInnerSpacing.x);
if (n + 1 == components)
ImGui::PushItemWidth(w_item_last);
value_changed |= ImGui::SliderInt("##W", &iw, 0, 255, "A:%3.0f");
}
else
{
ImGui::PushItemWidth(w_item_last);
value_changed |= ImGui::SliderInt("##Z", &iz, 0, 255, hsv ? "V:%3.0f" : "B:%3.0f");
value_changed |= ImGui::DragInt(ids[n], &i[n], 1, 0, 255, fmt[n]);
}
ImGui::PopItemWidth();
ImGui::PopItemWidth();
@ -6877,46 +7038,42 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha)
break;
case ImGuiColorEditMode_HEX:
{
// 2: RGB Hexadecimal
// RGB Hexadecimal Input
const float w_slider_all = w_full - square_sz;
char buf[64];
if (alpha)
ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ix, iy, iz, iw);
ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", i[0], i[1], i[2], i[3]);
else
ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ix, iy, iz);
ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", i[0], i[1], i[2]);
ImGui::PushItemWidth(w_slider_all - style.ItemInnerSpacing.x);
value_changed |= ImGui::InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal);
value_changed |= ImGui::InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
ImGui::PopItemWidth();
char* p = buf;
while (*p == '#' || ImCharIsSpace(*p))
p++;
// Treat at unsigned (%X is unsigned)
ix = iy = iz = iw = 0;
i[0] = i[1] = i[2] = i[3] = 0;
if (alpha)
sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&ix, (unsigned int*)&iy, (unsigned int*)&iz, (unsigned int*)&iw);
sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]);
else
sscanf(p, "%02X%02X%02X", (unsigned int*)&ix, (unsigned int*)&iy, (unsigned int*)&iz);
sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]);
}
break;
}
ImGui::SameLine(0, (int)style.ItemInnerSpacing.x);
const ImVec4 col_display(col[0], col[1], col[2], 1.0f);
if (ImGui::ColorButton(col_display))
{
// Don't set local copy of 'edit_mode' right away!
g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3);
}
g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3); // Don't set local copy of 'edit_mode' right away!
if (window->DC.ColorEditMode == ImGuiColorEditMode_UserSelectShowButton)
{
ImGui::SameLine(0, (int)style.ItemInnerSpacing.x);
const char* button_titles[3] = { "RGB", "HSV", "HEX" };
if (ImGui::Button(button_titles[edit_mode]))
{
// Don't set local copy of 'edit_mode' right away!
g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3);
}
g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3); // Don't set local copy of 'edit_mode' right away!
ImGui::SameLine();
}
else
@ -6927,20 +7084,18 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha)
ImGui::TextUnformatted(label, FindTextDisplayEnd(label));
// Convert back
fx = ix / 255.0f;
fy = iy / 255.0f;
fz = iz / 255.0f;
fw = iw / 255.0f;
for (int n = 0; n < 4; n++)
f[n] = i[n] / 255.0f;
if (edit_mode == 1)
ImGui::ColorConvertHSVtoRGB(fx, fy, fz, fx, fy, fz);
ImGui::ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]);
if (value_changed)
{
col[0] = fx;
col[1] = fy;
col[2] = fz;
col[0] = f[0];
col[1] = f[1];
col[2] = f[2];
if (alpha)
col[3] = fw;
col[3] = f[3];
}
ImGui::PopID();
@ -8303,7 +8458,7 @@ void ImFontAtlas::RenderCustomTexData(int pass, void* p_rects)
ImVector<stbrp_rect>& rects = *(ImVector<stbrp_rect>*)p_rects;
if (pass == 0)
{
stbrp_rect r;
stbrp_rect r = { 0 };
r.w = (TEX_DATA_W*2)+1;
r.h = TEX_DATA_H+1;
rects.push_back(r);
@ -8363,6 +8518,16 @@ ImFont::ImFont()
Clear();
}
ImFont::~ImFont()
{
// Invalidate active font so that the user gets a clear crash instead of a dangling pointer.
// If you want to delete fonts you need to do it between Render() and NewFrame().
ImGuiState& g = *GImGui;
if (g.Font == this)
g.Font = NULL;
Clear();
}
void ImFont::Clear()
{
FontSize = 0.0f;
@ -9167,6 +9332,7 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int, int)
void ImGui::ShowUserGuide() {}
void ImGui::ShowStyleEditor(ImGuiStyle*) {}
void ImGui::ShowTestWindow(bool*) {}
void ImGui::ShowMetricsWindow(bool*) {}
#else
@ -9307,12 +9473,15 @@ static void ShowExampleAppCustomRendering(bool* opened);
void ImGui::ShowTestWindow(bool* opened)
{
// Examples apps
static bool show_app_metrics = false;
static bool show_app_console = false;
static bool show_app_long_text = false;
static bool show_app_auto_resize = false;
static bool show_app_fixed_overlay = false;
static bool show_app_custom_rendering = false;
static bool show_app_manipulating_window_title = false;
if (show_app_metrics)
ImGui::ShowMetricsWindow(&show_app_metrics);
if (show_app_console)
ShowExampleAppConsole(&show_app_console);
if (show_app_long_text)
@ -9684,33 +9853,46 @@ void ImGui::ShowTestWindow(bool* opened)
static int item2 = -1;
ImGui::Combo("combo scroll", &item2, items, IM_ARRAYSIZE(items));
{
static char str0[128] = "Hello, world!";
static int i0=123;
static float f0=0.001f;
ImGui::InputText("string", str0, IM_ARRAYSIZE(str0));
ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0));
ImGui::InputInt("input int", &i0);
ImGui::InputFloat("input float", &f0, 0.01f, 1.0f);
static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
//ImGui::InputFloat2("input float2", vec4a);
ImGui::InputFloat3("input float3", vec4a);
//ImGui::InputFloat4("input float4", vec4a);
}
/*
{
static int i1=50;
static int i2=42;
ImGui::DragInt("drag int", &i1, 1);
ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100);
static float f1=1.00f;
static float f2=0.0067f;
ImGui::DragFloat("drag float", &f1, 1.0f);
ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f");
}
*/
{
static int i1=0;
static int i2=42;
ImGui::SliderInt("int 0..3", &i1, 0, 3);
ImGui::SliderInt("int -100..100", &i2, -100, 100);
ImGui::SliderInt("slider int 0..3", &i1, 0, 3);
ImGui::SliderInt("slider int -100..100", &i2, -100, 100);
static float f1=1.123f;
static float f2=0;
static float f3=0;
static float f4=123456789.0f;
ImGui::SliderFloat("float", &f1, 0.0f, 2.0f);
ImGui::SliderFloat("log float", &f2, 0.0f, 10.0f, "%.4f", 2.0f);
ImGui::SliderFloat("signed log float", &f3, -10.0f, 10.0f, "%.4f", 3.0f);
ImGui::SliderFloat("unbound float", &f4, -FLT_MAX, FLT_MAX, "%.4f");
static float f3=123456789.0f;
ImGui::SliderFloat("slider float", &f1, 0.0f, 2.0f);
ImGui::SliderFloat("slider log float", &f2, -10.0f, 10.0f, "%.4f", 3.0f);
static float angle = 0.0f;
ImGui::SliderAngle("angle", &angle);
ImGui::SliderAngle("slider angle", &angle);
}
static float col1[3] = { 1.0f,0.0f,0.2f };
static float col2[4] = { 0.4f,0.7f,0.0f,0.5f };
@ -9769,12 +9951,13 @@ void ImGui::ShowTestWindow(bool* opened)
if (i > 0) ImGui::SameLine();
ImGui::PushID(i);
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImColor::HSV(i/7.0f, 0.5f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImColor::HSV(i/7.0f, 0.6f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImColor::HSV(i/7.0f, 0.7f, 0.5f));
ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImColor::HSV(i/7.0f, 0.9f, 0.9f));
ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, ImColor::HSV(i/7.0f, 1.0f, 1.0f));
ImGui::VSliderFloat("##v", ImVec2(18,160), &values[i], 0.0f, 1.0f, "");
if (ImGui::IsItemActive() || ImGui::IsItemHovered())
ImGui::SetTooltip("%.3f", values[i]);
ImGui::PopStyleColor(3);
ImGui::PopStyleColor(4);
ImGui::PopID();
}
ImGui::PopID();
@ -10296,6 +10479,7 @@ void ImGui::ShowTestWindow(bool* opened)
if (ImGui::CollapsingHeader("App Examples"))
{
ImGui::Checkbox("Metrics", &show_app_metrics);
ImGui::Checkbox("Console", &show_app_console);
ImGui::Checkbox("Long text display", &show_app_long_text);
ImGui::Checkbox("Auto-resizing window", &show_app_auto_resize);
@ -10307,6 +10491,69 @@ void ImGui::ShowTestWindow(bool* opened)
ImGui::End();
}
void ImGui::ShowMetricsWindow(bool* opened)
{
if (ImGui::Begin("ImGui Metrics", opened))
{
ImGui::Text("ImGui %s", ImGui::GetVersion());
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Text("%d vertices", ImGui::GetIO().MetricsVertices);
ImGui::Separator();
struct Funcs
{
static void NodeDrawList(ImDrawList* draw_list, const char* label)
{
bool opened = ImGui::TreeNode(draw_list, "%s: %d vtx, %d cmds", label, draw_list->vtx_buffer.size(), draw_list->commands.size());
if (draw_list == ImGui::GetWindowDrawList())
{
ImGui::SameLine();
ImGui::TextColored(ImColor(255,100,100), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered)
}
if (!opened)
return;
for (const ImDrawCmd* pcmd = draw_list->commands.begin(); pcmd < draw_list->commands.end(); pcmd++)
if (pcmd->user_callback)
ImGui::BulletText("Callback %p, user_data %p", pcmd->user_callback, pcmd->user_callback_data);
else
ImGui::BulletText("Draw %d vtx, tex = %p", pcmd->vtx_count, pcmd->texture_id);
ImGui::TreePop();
}
static void NodeWindows(ImVector<ImGuiWindow*>& windows, const char* label)
{
if (!ImGui::TreeNode(label, "%s (%d)", label, (int)windows.size()))
return;
for (int i = 0; i < (int)windows.size(); i++)
Funcs::NodeWindow(windows[i], "Window");
ImGui::TreePop();
}
static void NodeWindow(ImGuiWindow* window, const char* label)
{
if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Visible, window))
return;
NodeDrawList(window->DrawList, "DrawList");
if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow");
if (window->DC.ChildWindows.size() > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows");
ImGui::TreePop();
}
};
ImGuiState& g = *GImGui; // Access private state
g.DisableHideTextAfterDoubleHash++; // Not exposed (yet). Disable processing that hides text after '##' markers.
Funcs::NodeWindows(g.Windows, "Windows");
if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", (int)g.RenderDrawLists[0].size()))
{
for (int i = 0; i < (int)g.RenderDrawLists[0].size(); i++)
Funcs::NodeDrawList(g.RenderDrawLists[0][i], "DrawList");
ImGui::TreePop();
}
g.DisableHideTextAfterDoubleHash--;
}
ImGui::End();
}
static void ShowExampleAppAutoResize(bool* opened)
{
if (!ImGui::Begin("Example: Auto-Resizing Window", opened, ImGuiWindowFlags_AlwaysAutoResize))
@ -10360,7 +10607,7 @@ static void ShowExampleAppManipulatingWindowTitle(bool* opened)
// Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
char buf[128];
ImFormatString(buf, IM_ARRAYSIZE(buf), "Animated title %c %d##AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime()/0.25f)&3], rand());
ImFormatString(buf, IM_ARRAYSIZE(buf), "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime()/0.25f)&3], rand());
ImGui::SetNextWindowPos(ImVec2(100,300), ImGuiSetCond_FirstUseEver);
ImGui::Begin(buf);
ImGui::Text("This window has a changing title.");

88
imgui.h
View File

@ -53,10 +53,10 @@ typedef int (*ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data);
struct ImVec2
{
float x, y;
ImVec2() {}
ImVec2() { x = y = 0.0f; }
ImVec2(float _x, float _y) { x = _x; y = _y; }
#ifdef IM_VEC2_CLASS_EXTRA
#ifdef IM_VEC2_CLASS_EXTRA // Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec2.
IM_VEC2_CLASS_EXTRA
#endif
};
@ -64,10 +64,10 @@ struct ImVec2
struct ImVec4
{
float x, y, z, w;
ImVec4() {}
ImVec4() { x = y = z = w = 0.0f; }
ImVec4(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; }
#ifdef IM_VEC4_CLASS_EXTRA
#ifdef IM_VEC4_CLASS_EXTRA // Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec4.
IM_VEC4_CLASS_EXTRA
#endif
};
@ -147,7 +147,7 @@ public:
// - struct ImFont // TTF font loader, bake glyphs into bitmap
// ImGui end-user API
// In a namespace so that user can add extra functions (e.g. Value() helpers for your vector or common types)
// In a namespace so that user can add extra functions in a separate file (e.g. Value() helpers for your vector or common types)
namespace ImGui
{
// Main
@ -156,9 +156,10 @@ namespace ImGui
IMGUI_API void NewFrame();
IMGUI_API void Render();
IMGUI_API void Shutdown();
IMGUI_API void ShowUserGuide();
IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL);
IMGUI_API void ShowTestWindow(bool* open = NULL);
IMGUI_API void ShowUserGuide(); // help block
IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // style editor block
IMGUI_API void ShowTestWindow(bool* opened = NULL); // test window, demonstrate ImGui features
IMGUI_API void ShowMetricsWindow(bool* opened = NULL); // metrics window
// Window
// See implementation in .cpp for details
@ -191,7 +192,7 @@ namespace ImGui
IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiSetCond cond = 0); // set named window position - call within Begin()/End(). may incur tearing
IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiSetCond cond = 0); // set named window size. set to ImVec2(0,0) to force an auto-fit. may incur tearing
IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiSetCond cond = 0); // set named window collapsed state
IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / front-most
IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / front-most. use NULL to remove focus.
IMGUI_API float GetScrollPosY(); // get scrolling position [0..GetScrollMaxY()]
IMGUI_API float GetScrollMaxY(); // get maximum scrolling position == ContentSize.Y - WindowSize.Y
@ -284,25 +285,41 @@ namespace ImGui
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0));
IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,1), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding
IMGUI_API bool CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false);
IMGUI_API bool Checkbox(const char* label, bool* v);
IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value);
IMGUI_API bool RadioButton(const char* label, bool active);
IMGUI_API bool RadioButton(const char* label, int* v, int v_button);
IMGUI_API bool Combo(const char* label, int* current_item, const char** items, int items_count, int height_in_items = -1);
IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items = -1); // separate items with \0, end item-list with \0\0
IMGUI_API bool Combo(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1);
IMGUI_API bool ColorButton(const ImVec4& col, bool small_height = false, bool outline_border = true);
IMGUI_API bool ColorEdit3(const char* label, float col[3]);
IMGUI_API bool ColorEdit4(const char* label, float col[4], bool show_alpha = true);
IMGUI_API void ColorEditMode(ImGuiColorEditMode mode);
IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0), size_t stride = sizeof(float));
IMGUI_API void PlotLines(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0));
IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0), size_t stride = sizeof(float));
IMGUI_API void PlotHistogram(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0));
// Widgets: Sliders (tip: ctrl+click on a slider to input text)
IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); // adjust display_format to decorate the value with a prefix or a suffix. Use power!=1.0 for logarithmic sliders
IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
IMGUI_API bool SliderAngle(const char* label, float* v, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f); // *v in radians
IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f);
IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* display_format = "%.0f");
IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* display_format = "%.0f");
IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* display_format = "%.0f");
IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* display_format = "%.0f");
IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* display_format = "%.0f");
IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0), size_t stride = sizeof(float));
IMGUI_API void PlotLines(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0));
IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0), size_t stride = sizeof(float));
IMGUI_API void PlotHistogram(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0,0));
IMGUI_API bool Checkbox(const char* label, bool* v);
IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value);
IMGUI_API bool RadioButton(const char* label, bool active);
IMGUI_API bool RadioButton(const char* label, int* v, int v_button);
// Widgets: Drags (tip: ctrl+click on a drag box to input text)
// ImGui 1.38+ work-in-progress, may change name or API.
IMGUI_API bool DragFloat(const char* label, float* v, float v_step = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* display_format = "%.3f"); // If v_max >= v_max we have no bound
IMGUI_API bool DragInt(const char* label, int* v, int v_step = 1, int v_min = 0.0f, int v_max = 0.0f, const char* display_format = "%.0f"); // If v_max >= v_max we have no bound
// Widgets: Input
IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL);
IMGUI_API bool InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, int decimal_precision = -1, ImGuiInputTextFlags extra_flags = 0);
IMGUI_API bool InputFloat2(const char* label, float v[2], int decimal_precision = -1);
@ -312,15 +329,8 @@ namespace ImGui
IMGUI_API bool InputInt2(const char* label, int v[2]);
IMGUI_API bool InputInt3(const char* label, int v[3]);
IMGUI_API bool InputInt4(const char* label, int v[4]);
IMGUI_API bool Combo(const char* label, int* current_item, const char** items, int items_count, int height_in_items = -1);
IMGUI_API bool Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items = -1); // separate items with \0, end item-list with \0\0
IMGUI_API bool Combo(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1);
IMGUI_API bool ColorButton(const ImVec4& col, bool small_height = false, bool outline_border = true);
IMGUI_API bool ColorEdit3(const char* label, float col[3]);
IMGUI_API bool ColorEdit4(const char* label, float col[4], bool show_alpha = true);
IMGUI_API void ColorEditMode(ImGuiColorEditMode mode);
// Trees
// Widgets: Trees
IMGUI_API bool TreeNode(const char* str_label_id); // if returning 'true' the node is open and the user is responsible for calling TreePop
IMGUI_API bool TreeNode(const char* str_id, const char* fmt, ...); // "
IMGUI_API bool TreeNode(const void* ptr_id, const char* fmt, ...); // "
@ -331,7 +341,7 @@ namespace ImGui
IMGUI_API void TreePop();
IMGUI_API void SetNextTreeNodeOpened(bool opened, ImGuiSetCond cond = 0); // set next tree node to be opened.
// Selectable / Lists
// Widgets: Selectable / Lists
IMGUI_API bool Selectable(const char* label, bool selected = false, const ImVec2& size = ImVec2(0,0));
IMGUI_API bool Selectable(const char* label, bool* p_selected, const ImVec2& size = ImVec2(0,0));
IMGUI_API bool ListBox(const char* label, int* current_item, const char** items, int items_count, int height_in_items = -1);
@ -340,7 +350,7 @@ namespace ImGui
IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // "
IMGUI_API void ListBoxFooter(); // terminate the scrolling region
// Value() Helpers: output single value in "name: value" format. Tip: freely declare your own within the ImGui namespace!
// Widgets: Value() Helpers. Output single value in "name: value" format (tip: freely declare your own within the ImGui namespace!)
IMGUI_API void Value(const char* prefix, bool b);
IMGUI_API void Value(const char* prefix, int v);
IMGUI_API void Value(const char* prefix, unsigned int v);
@ -348,7 +358,7 @@ namespace ImGui
IMGUI_API void Color(const char* prefix, const ImVec4& v);
IMGUI_API void Color(const char* prefix, unsigned int v);
// Logging: All text output from your interface are redirected to tty/file/clipboard. Tree nodes are automatically opened.
// Logging: all text output from interface is redirected to tty/file/clipboard. Tree nodes are automatically opened.
IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty
IMGUI_API void LogToFile(int max_depth = -1, const char* filename = NULL); // start logging to file
IMGUI_API void LogToClipboard(int max_depth = -1); // start logging to OS clipboard
@ -480,6 +490,8 @@ enum ImGuiCol_
ImGuiCol_Border,
ImGuiCol_BorderShadow,
ImGuiCol_FrameBg, // Background of checkbox, radio button, plot, slider, text input
ImGuiCol_FrameBgHovered,
ImGuiCol_FrameBgActive,
ImGuiCol_TitleBg,
ImGuiCol_TitleBgCollapsed,
ImGuiCol_ScrollbarBg,
@ -487,8 +499,6 @@ enum ImGuiCol_
ImGuiCol_ScrollbarGrabHovered,
ImGuiCol_ScrollbarGrabActive,
ImGuiCol_ComboBg,
ImGuiCol_CheckHovered,
ImGuiCol_CheckActive,
ImGuiCol_CheckMark,
ImGuiCol_SliderGrab,
ImGuiCol_SliderGrabActive,
@ -546,12 +556,12 @@ enum ImGuiColorEditMode_
enum ImGuiMouseCursor_
{
ImGuiMouseCursor_Arrow = 0,
ImGuiMouseCursor_TextInput,
ImGuiMouseCursor_Move, // Unused by ImGui
ImGuiMouseCursor_ResizeNS, // Unused by ImGui
ImGuiMouseCursor_ResizeEW, // Unused by ImGui
ImGuiMouseCursor_ResizeNESW, // Unused by ImGui
ImGuiMouseCursor_ResizeNWSE,
ImGuiMouseCursor_TextInput, // When hovering over InputText, etc.
ImGuiMouseCursor_Move, // Unused
ImGuiMouseCursor_ResizeNS, // Unused
ImGuiMouseCursor_ResizeEW, // When hovering over a column
ImGuiMouseCursor_ResizeNESW, // Unused
ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window
ImGuiMouseCursor_Count_
};
@ -660,6 +670,7 @@ struct ImGuiIO
bool WantCaptureMouse; // Mouse is hovering a window or widget is active (= ImGui will use your mouse input)
bool WantCaptureKeyboard; // Widget is active (= ImGui will use your keyboard input)
float Framerate; // Framerate estimation, in frame per second. Rolling average estimation based on IO.DeltaTime over 120 frames
int MetricsVertices; // Vertices processed during last call to Render()
//------------------------------------------------------------------
// [Internal] ImGui will maintain those fields for you
@ -873,6 +884,7 @@ IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT;
// 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.
// You can interleave normal ImGui:: calls and adding primitives to the current draw list.
// All positions are in screen coordinates (0,0=top-left, 1 pixel per unit). Primitives are always added to the list and not culled (culling is done at render time and at a higher-level by ImGui:: functions).
// Note that this only gives you access to rendering polygons. If your intent is to create custom widgets and the publicly exposed functions/data aren't sufficient, you can add code in imgui_user.inl
struct ImDrawList
{
@ -1008,7 +1020,7 @@ struct ImFont
// Methods
IMGUI_API ImFont();
IMGUI_API ~ImFont() { Clear(); }
IMGUI_API ~ImFont();
IMGUI_API void Clear();
IMGUI_API void BuildLookupTable();
IMGUI_API const Glyph* FindGlyph(unsigned short c) const;