Merge branch 'dev'

This commit is contained in:
Branimir Karadžić 2015-01-31 19:10:48 -08:00
commit ac7f301c0c
6 changed files with 731 additions and 489 deletions

View file

@ -1,4 +1,4 @@
// ImGui library v1.30 wip // ImGui library v1.30
// See ImGui::ShowTestWindow() for sample code. // See ImGui::ShowTestWindow() for sample code.
// Read 'Programmer guide' below for notes on how to setup ImGui in your codebase. // Read 'Programmer guide' below for notes on how to setup ImGui in your codebase.
// Get latest version at https://github.com/ocornut/imgui // Get latest version at https://github.com/ocornut/imgui
@ -95,7 +95,7 @@
// TODO: store your texture pointer/identifier in 'io.Fonts->TexID' // TODO: store your texture pointer/identifier in 'io.Fonts->TexID'
// Application main loop // Application main loop
while (true) for (;;)
{ {
// 1) get low-level input // 1) get low-level input
// e.g. on Win32, GetKeyboardState(), or poll your events, etc. // e.g. on Win32, GetKeyboardState(), or poll your events, etc.
@ -128,6 +128,7 @@
Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix. 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. 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/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
- 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader. - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
(1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
this sequence: this sequence:
@ -233,6 +234,7 @@
================== ==================
- misc: merge or clarify ImVec4 / ImGuiAabb, they are essentially duplicate containers - misc: merge or clarify ImVec4 / ImGuiAabb, they are essentially duplicate containers
!- i/o: avoid requesting mouse capture if button held and initial click was out of reach for imgui
- window: add horizontal scroll - window: add horizontal scroll
- window: fix resize grip rendering scaling along with Rounding style setting - window: fix resize grip rendering scaling along with Rounding style setting
- window: autofit feedback loop when user relies on any dynamic layout (window width multiplier, column). maybe just clearly drop manual autofit? - window: autofit feedback loop when user relies on any dynamic layout (window width multiplier, column). maybe just clearly drop manual autofit?
@ -362,7 +364,7 @@ namespace IMGUI_STB_NAMESPACE
#define STBRP_STATIC #define STBRP_STATIC
#define STB_RECT_PACK_IMPLEMENTATION #define STB_RECT_PACK_IMPLEMENTATION
#endif #endif
#include <stb/stb_rect_pack.h> #include "stb_rect_pack.h"
#define STBTT_malloc(x,u) ((void)(u), ImGui::MemAlloc(x)) #define STBTT_malloc(x,u) ((void)(u), ImGui::MemAlloc(x))
#define STBTT_free(x,u) ((void)(u), ImGui::MemFree(x)) #define STBTT_free(x,u) ((void)(u), ImGui::MemFree(x))
@ -371,11 +373,11 @@ namespace IMGUI_STB_NAMESPACE
#define STBTT_STATIC #define STBTT_STATIC
#define STB_TRUETYPE_IMPLEMENTATION #define STB_TRUETYPE_IMPLEMENTATION
#endif #endif
#include <stb/stb_truetype.h> #include "stb_truetype.h"
#define STB_TEXTEDIT_STRING ImGuiTextEditState #define STB_TEXTEDIT_STRING ImGuiTextEditState
#define STB_TEXTEDIT_CHARTYPE ImWchar #define STB_TEXTEDIT_CHARTYPE ImWchar
#include <stb/stb_textedit.h> #include "stb_textedit.h"
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop #pragma clang diagnostic pop
@ -425,11 +427,6 @@ static ImU32 ImCrc32(const void* data, size_t data_size, ImU32 seed);
static bool ImLoadFileToMemory(const char* filename, const char* file_open_mode, void** out_file_data, size_t* out_file_size, size_t padding_bytes = 0); static bool ImLoadFileToMemory(const char* filename, const char* file_open_mode, void** out_file_data, size_t* out_file_size, size_t padding_bytes = 0);
static int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } static int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
// Helpers: Color Conversion
static ImU32 ImConvertColorFloat4ToU32(const ImVec4& in);
static void ImConvertColorRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v);
static void ImConvertColorHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b);
// Helpers: UTF-8 <> wchar // Helpers: UTF-8 <> wchar
static int ImTextCharToUtf8(char* buf, size_t buf_size, unsigned int in_char); // return output UTF-8 bytes count static int ImTextCharToUtf8(char* buf, size_t buf_size, unsigned int in_char); // return output UTF-8 bytes count
static ptrdiff_t ImTextStrToUtf8(char* buf, size_t buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count static ptrdiff_t ImTextStrToUtf8(char* buf, size_t buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count
@ -445,6 +442,17 @@ static int ImTextCountUtf8BytesFromWchar(const ImWchar* in_text, const
static const char* GetClipboardTextFn_DefaultImpl(); static const char* GetClipboardTextFn_DefaultImpl();
static void SetClipboardTextFn_DefaultImpl(const char* text); static void SetClipboardTextFn_DefaultImpl(const char* text);
//-----------------------------------------------------------------------------
// Texture Atlas data
//-----------------------------------------------------------------------------
// Technically we should use the rect pack API for that, but it's just simpler to hard-core the positions for now.
// As we start using more of the texture atlas (for rounded corners) we can change that.
static const ImVec2 TEX_ATLAS_SIZE(32, 32);
static const ImVec2 TEX_ATLAS_POS_MOUSE_CURSOR_BLACK(1, 3);
static const ImVec2 TEX_ATLAS_POS_MOUSE_CURSOR_WHITE(14, 3);
static const ImVec2 TEX_ATLAS_SIZE_MOUSE_CURSOR(12, 19);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// User facing structures // User facing structures
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -512,7 +520,9 @@ static ImFontAtlas GDefaultFontAtlas;
ImGuiIO::ImGuiIO() ImGuiIO::ImGuiIO()
{ {
// Most fields are initialized with zero
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
DisplaySize = ImVec2(-1.0f, -1.0f); DisplaySize = ImVec2(-1.0f, -1.0f);
DeltaTime = 1.0f/60.0f; DeltaTime = 1.0f/60.0f;
IniSavingRate = 5.0f; IniSavingRate = 5.0f;
@ -520,7 +530,6 @@ ImGuiIO::ImGuiIO()
LogFilename = "imgui_log.txt"; LogFilename = "imgui_log.txt";
Fonts = &GDefaultFontAtlas; Fonts = &GDefaultFontAtlas;
FontGlobalScale = 1.0f; FontGlobalScale = 1.0f;
FontAllowUserScaling = false;
MousePos = ImVec2(-1,-1); MousePos = ImVec2(-1,-1);
MousePosPrev = ImVec2(-1,-1); MousePosPrev = ImVec2(-1,-1);
MouseDoubleClickTime = 0.30f; MouseDoubleClickTime = 0.30f;
@ -700,7 +709,7 @@ static size_t ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_li
return (w == -1) ? buf_size : (size_t)w; return (w == -1) ? buf_size : (size_t)w;
} }
static ImU32 ImConvertColorFloat4ToU32(const ImVec4& in) ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in)
{ {
ImU32 out = ((ImU32)(ImSaturate(in.x)*255.f)); ImU32 out = ((ImU32)(ImSaturate(in.x)*255.f));
out |= ((ImU32)(ImSaturate(in.y)*255.f) << 8); out |= ((ImU32)(ImSaturate(in.y)*255.f) << 8);
@ -711,7 +720,7 @@ static ImU32 ImConvertColorFloat4ToU32(const ImVec4& in)
// Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592 // Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592
// Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv // Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
static void ImConvertColorRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v) void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
{ {
float K = 0.f; float K = 0.f;
if (g < b) if (g < b)
@ -733,7 +742,7 @@ static void ImConvertColorRGBtoHSV(float r, float g, float b, float& out_h, floa
// Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593 // Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593
// also http://en.wikipedia.org/wiki/HSL_and_HSV // also http://en.wikipedia.org/wiki/HSL_and_HSV
static void ImConvertColorHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b) void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
{ {
if (s == 0.0f) if (s == 0.0f)
{ {
@ -1084,8 +1093,8 @@ public:
float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0 : FontSize() + GImGui.Style.FramePadding.y * 2.0f; } float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0 : FontSize() + GImGui.Style.FramePadding.y * 2.0f; }
ImGuiAabb TitleBarAabb() const { return ImGuiAabb(Pos, Pos + ImVec2(SizeFull.x, TitleBarHeight())); } ImGuiAabb TitleBarAabb() const { return ImGuiAabb(Pos, Pos + ImVec2(SizeFull.x, TitleBarHeight())); }
ImVec2 WindowPadding() const { return ((Flags & ImGuiWindowFlags_ChildWindow) && !(Flags & ImGuiWindowFlags_ShowBorders)) ? ImVec2(1,1) : GImGui.Style.WindowPadding; } ImVec2 WindowPadding() const { return ((Flags & ImGuiWindowFlags_ChildWindow) && !(Flags & ImGuiWindowFlags_ShowBorders)) ? ImVec2(1,1) : 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 ImConvertColorFloat4ToU32(c); } 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 ImConvertColorFloat4ToU32(c); } ImU32 Color(const ImVec4& col) const { ImVec4 c = col; c.w *= GImGui.Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); }
}; };
static ImGuiWindow* GetCurrentWindow() static ImGuiWindow* GetCurrentWindow()
@ -1095,6 +1104,11 @@ static ImGuiWindow* GetCurrentWindow()
return GImGui.CurrentWindow; return GImGui.CurrentWindow;
} }
static void SetActiveId(ImGuiID id)
{
GImGui.ActiveId = id;
}
static void RegisterAliveId(const ImGuiID& id) static void RegisterAliveId(const ImGuiID& id)
{ {
if (GImGui.ActiveId == id) if (GImGui.ActiveId == id)
@ -1148,7 +1162,16 @@ float ImGuiStorage::GetFloat(ImU32 key, float default_val) const
return it->val_f; return it->val_f;
} }
int* ImGuiStorage::GetIntPtr(ImGuiID key, int default_val) void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
{
ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
if (it == Data.end() || it->key != key)
return NULL;
return it->val_p;
}
// 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); ImVector<Pair>::iterator it = LowerBound(Data, key);
if (it == Data.end() || it->key != key) if (it == Data.end() || it->key != key)
@ -1156,7 +1179,7 @@ int* ImGuiStorage::GetIntPtr(ImGuiID key, int default_val)
return &it->val_i; return &it->val_i;
} }
float* ImGuiStorage::GetFloatPtr(ImGuiID key, float default_val) float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
{ {
ImVector<Pair>::iterator it = LowerBound(Data, key); ImVector<Pair>::iterator it = LowerBound(Data, key);
if (it == Data.end() || it->key != key) if (it == Data.end() || it->key != key)
@ -1188,6 +1211,17 @@ void ImGuiStorage::SetFloat(ImU32 key, float val)
it->val_f = val; it->val_f = val;
} }
void ImGuiStorage::SetVoidPtr(ImU32 key, void* val)
{
ImVector<Pair>::iterator it = LowerBound(Data, key);
if (it == Data.end() || it->key != key)
{
Data.insert(it, Pair(key, val));
return;
}
it->val_p = val;
}
void ImGuiStorage::SetAllInt(int v) void ImGuiStorage::SetAllInt(int v)
{ {
for (size_t i = 0; i < Data.size(); i++) for (size_t i = 0; i < Data.size(); i++)
@ -1649,7 +1683,7 @@ void ImGui::NewFrame()
// Clear reference to active widget if the widget isn't alive anymore // Clear reference to active widget if the widget isn't alive anymore
g.HoveredId = 0; g.HoveredId = 0;
if (!g.ActiveIdIsAlive && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0) if (!g.ActiveIdIsAlive && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0)
g.ActiveId = 0; SetActiveId(0);
g.ActiveIdPreviousFrame = g.ActiveId; g.ActiveIdPreviousFrame = g.ActiveId;
g.ActiveIdIsAlive = false; g.ActiveIdIsAlive = false;
@ -1835,7 +1869,7 @@ void ImGui::Render()
// Select window for move/focus when we're done with all our widgets (we only consider non-childs windows here) // Select window for move/focus when we're done with all our widgets (we only consider non-childs windows here)
if (g.ActiveId == 0 && g.HoveredId == 0 && g.HoveredRootWindow != NULL && g.IO.MouseClicked[0]) if (g.ActiveId == 0 && g.HoveredId == 0 && g.HoveredRootWindow != NULL && g.IO.MouseClicked[0])
g.ActiveId = g.HoveredRootWindow->GetID("#MOVE"); SetActiveId(g.HoveredRootWindow->GetID("#MOVE"));
// Sort the window list so that all child windows are after their parent // 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 // We cannot do that on FocusWindow() because childs may not exist yet
@ -1885,6 +1919,21 @@ void ImGui::Render()
window->AddToRenderList(); window->AddToRenderList();
} }
if (g.IO.MouseDrawCursor)
{
const ImVec2 pos = g.IO.MousePos;
const ImVec2 size = TEX_ATLAS_SIZE_MOUSE_CURSOR;
const ImTextureID tex_id = g.IO.Fonts->TexID;
const ImVec2 tex_uv_scale(1.0f/g.IO.Fonts->TexWidth, 1.0f/g.IO.Fonts->TexHeight);
static ImDrawList draw_list;
draw_list.Clear();
draw_list.AddImage(tex_id, pos+ImVec2(1,0), pos+ImVec2(1,0) + size, TEX_ATLAS_POS_MOUSE_CURSOR_BLACK * tex_uv_scale, (TEX_ATLAS_POS_MOUSE_CURSOR_BLACK + size) * tex_uv_scale, 0x30000000); // Shadow
draw_list.AddImage(tex_id, pos+ImVec2(2,0), pos+ImVec2(2,0) + size, TEX_ATLAS_POS_MOUSE_CURSOR_BLACK * tex_uv_scale, (TEX_ATLAS_POS_MOUSE_CURSOR_BLACK + size) * tex_uv_scale, 0x30000000); // Shadow
draw_list.AddImage(tex_id, pos, pos + size, TEX_ATLAS_POS_MOUSE_CURSOR_BLACK * tex_uv_scale, (TEX_ATLAS_POS_MOUSE_CURSOR_BLACK + size) * tex_uv_scale, 0xFF000000); // Black border
draw_list.AddImage(tex_id, pos, pos + size, TEX_ATLAS_POS_MOUSE_CURSOR_WHITE * tex_uv_scale, (TEX_ATLAS_POS_MOUSE_CURSOR_WHITE + size) * tex_uv_scale, 0xFFFFFFFF); // White fill
g.RenderDrawLists.push_back(&draw_list);
}
// Render // Render
if (!g.RenderDrawLists.empty()) if (!g.RenderDrawLists.empty())
g.IO.RenderDrawListsFn(&g.RenderDrawLists[0], (int)g.RenderDrawLists.size()); g.IO.RenderDrawListsFn(&g.RenderDrawLists[0], (int)g.RenderDrawLists.size());
@ -2431,6 +2480,9 @@ bool ImGui::Begin(const char* name, bool* p_opened, ImVec2 size, float fill_alph
g.SetNextWindowCollapsedCond = 0; g.SetNextWindowCollapsedCond = 0;
} }
// Find parent
ImGuiWindow* parent_window = (flags & ImGuiWindowFlags_ChildWindow) != 0 ? g.CurrentWindowStack[g.CurrentWindowStack.size()-2] : NULL;
// Find root (if we are a child window) // Find root (if we are a child window)
size_t root_idx = g.CurrentWindowStack.size() - 1; size_t root_idx = g.CurrentWindowStack.size() - 1;
while (root_idx > 0) while (root_idx > 0)
@ -2451,7 +2503,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, ImVec2 size, float fill_alph
if (first_begin_of_the_frame) if (first_begin_of_the_frame)
{ {
window->DrawList->Clear(); window->DrawList->Clear();
window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
window->Visible = true; window->Visible = true;
// New windows appears in front // New windows appears in front
@ -2463,18 +2514,26 @@ bool ImGui::Begin(const char* name, bool* p_opened, ImVec2 size, float fill_alph
if (flags & ImGuiWindowFlags_ChildWindow) if (flags & ImGuiWindowFlags_ChildWindow)
{ {
ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.size()-2];
parent_window->DC.ChildWindows.push_back(window); parent_window->DC.ChildWindows.push_back(window);
window->Pos = window->PosFloat = parent_window->DC.CursorPos; window->Pos = window->PosFloat = parent_window->DC.CursorPos;
window->SizeFull = size; window->SizeFull = size;
} }
}
// Outer clipping rectangle // Setup texture
window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
// Setup outer clipping rectangle
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ComboBox)) if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ComboBox))
PushClipRect(g.CurrentWindowStack[g.CurrentWindowStack.size()-2]->ClipRectStack.back()); PushClipRect(parent_window->ClipRectStack.back());
else if (g.IO.DisplayVisibleMin.x != g.IO.DisplayVisibleMax.x && g.IO.DisplayVisibleMin.y != g.IO.DisplayVisibleMax.y)
PushClipRect(ImVec4(g.IO.DisplayVisibleMin.x, g.IO.DisplayVisibleMin.y, g.IO.DisplayVisibleMax.x, g.IO.DisplayVisibleMax.y));
else else
PushClipRect(ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y)); PushClipRect(ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y));
// Setup and draw window
if (first_begin_of_the_frame)
{
// Seed ID stack with our window pointer // Seed ID stack with our window pointer
window->IDStack.resize(0); window->IDStack.resize(0);
ImGui::PushID(window); ImGui::PushID(window);
@ -2496,7 +2555,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, ImVec2 size, float fill_alph
} }
else else
{ {
g.ActiveId = 0; SetActiveId(0);
} }
} }
@ -2509,11 +2568,14 @@ bool ImGui::Begin(const char* name, bool* p_opened, ImVec2 size, float fill_alph
// Clamp into view // Clamp into view
if (!(window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Tooltip)) if (!(window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Tooltip))
{ {
// FIXME: Parameterize padding.
const ImVec2 pad = ImVec2(window->FontSize()*2.0f, window->FontSize()*2.0f); // FIXME: Parametrize of clarify this behavior. const ImVec2 pad = ImVec2(window->FontSize()*2.0f, window->FontSize()*2.0f); // FIXME: Parametrize of clarify this behavior.
if (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 (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.
{ {
window->PosFloat = ImMax(window->PosFloat + window->Size, pad) - window->Size; ImVec2 clip_min = pad;
window->PosFloat = ImMin(window->PosFloat, ImVec2(g.IO.DisplaySize.x, g.IO.DisplaySize.y) - pad); ImVec2 clip_max = g.IO.DisplaySize - pad;
window->PosFloat = ImMax(window->PosFloat + window->Size, clip_min) - window->Size;
window->PosFloat = ImMin(window->PosFloat, clip_max);
} }
window->SizeFull = ImMax(window->SizeFull, style.WindowMinSize); window->SizeFull = ImMax(window->SizeFull, style.WindowMinSize);
} }
@ -2761,22 +2823,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, ImVec2 size, float fill_alph
PopClipRect(); PopClipRect();
} }
} }
else
{
// Short path when we do multiple Begin in the same frame.
window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
// Outer clipping rectangle
if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ComboBox))
{
ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.size()-2];
PushClipRect(parent_window->ClipRectStack.back());
}
else
{
PushClipRect(ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y));
}
}
// Inner clipping rectangle // Inner clipping rectangle
// We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame
@ -3522,7 +3568,7 @@ static bool ButtonBehaviour(const ImGuiAabb& bb, const ImGuiID& id, bool* out_ho
{ {
if (g.IO.MouseClicked[0]) if (g.IO.MouseClicked[0])
{ {
g.ActiveId = id; SetActiveId(id);
FocusWindow(window); FocusWindow(window);
} }
else if (repeat && g.ActiveId && ImGui::IsMouseClicked(0, true)) else if (repeat && g.ActiveId && ImGui::IsMouseClicked(0, true))
@ -3543,7 +3589,7 @@ static bool ButtonBehaviour(const ImGuiAabb& bb, const ImGuiID& id, bool* out_ho
{ {
if (hovered) if (hovered)
pressed = true; pressed = true;
g.ActiveId = 0; SetActiveId(0);
} }
} }
@ -3666,30 +3712,70 @@ static bool CloseWindowButton(bool* p_opened)
return pressed; return pressed;
} }
void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, ImU32 tint_col, ImU32 border_col) void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems) if (window->SkipItems)
return; return;
ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + size); ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + size);
if (border_col != 0) if (border_col.w > 0.0f)
bb.Max += ImVec2(2,2); bb.Max += ImVec2(2,2);
ItemSize(bb.GetSize(), &bb.Min); ItemSize(bb);
if (!ItemAdd(bb, NULL)) if (!ItemAdd(bb, NULL))
return; return;
if (border_col != 0) if (border_col.w > 0.0f)
{ {
window->DrawList->AddRect(bb.Min, bb.Max, border_col, 0.0f); window->DrawList->AddRect(bb.Min, bb.Max, window->Color(border_col), 0.0f);
window->DrawList->AddImage(user_texture_id, bb.Min+ImVec2(1,1), bb.Max-ImVec2(1,1), uv0, uv1, tint_col); window->DrawList->AddImage(user_texture_id, bb.Min+ImVec2(1,1), bb.Max-ImVec2(1,1), uv0, uv1, window->Color(tint_col));
} }
else else
{ {
window->DrawList->AddImage(user_texture_id, bb.Min, bb.Max, uv0, uv1, tint_col); window->DrawList->AddImage(user_texture_id, bb.Min, bb.Max, uv0, uv1, window->Color(tint_col));
} }
} }
// frame_padding < 0: uses FramePadding from style (default)
// frame_padding = 0: no framing
// frame_padding > 0: set framing size
// The color used are the button colors.
bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col)
{
ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
const ImGuiStyle& style = g.Style;
// Default to using texture ID as ID. User can still push string/integer prefixes.
// We could hash the size/uv to create a unique ID but that would prevent the user from animating buttons.
ImGui::PushID((void *)user_texture_id);
const ImGuiID id = window->GetID("#image");
ImGui::PopID();
const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding;
const ImGuiAabb bb(window->DC.CursorPos, window->DC.CursorPos + size + padding*2);
const ImGuiAabb image_bb(window->DC.CursorPos + padding, window->DC.CursorPos + padding + size);
ItemSize(bb);
if (!ItemAdd(bb, &id))
return false;
bool hovered, held;
bool pressed = ButtonBehaviour(bb, id, &hovered, &held, true);
// Render
const ImU32 col = window->Color((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
if (padding.x > 0.0f || padding.y > 0.0f)
RenderFrame(bb.Min, bb.Max, col);
if (bg_col.w > 0.0f)
window->DrawList->AddRectFilled(image_bb.Min, image_bb.Max, window->Color(bg_col));
window->DrawList->AddImage(user_texture_id, image_bb.Min, image_bb.Max, uv0, uv1);
return pressed;
}
// Start logging ImGui output to TTY // Start logging ImGui output to TTY
void ImGui::LogToTTY(int max_depth) void ImGui::LogToTTY(int max_depth)
{ {
@ -4159,7 +4245,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c
bool start_text_input = false; bool start_text_input = false;
if (tab_focus_requested || (hovered && g.IO.MouseClicked[0])) if (tab_focus_requested || (hovered && g.IO.MouseClicked[0]))
{ {
g.ActiveId = id; SetActiveId(id);
FocusWindow(window); FocusWindow(window);
const bool is_ctrl_down = g.IO.KeyCtrl; const bool is_ctrl_down = g.IO.KeyCtrl;
@ -4177,7 +4263,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c
char text_buf[64]; char text_buf[64];
ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%.*f", decimal_precision, *v); ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%.*f", decimal_precision, *v);
g.ActiveId = g.SliderAsInputTextId; SetActiveId(g.SliderAsInputTextId);
g.HoveredId = 0; g.HoveredId = 0;
window->FocusItemUnregister(); // Our replacement slider will override the focus ID (registered previously to allow for a TAB focus to happen) window->FocusItemUnregister(); // Our replacement slider will override the focus ID (registered previously to allow for a TAB focus to happen)
value_changed = ImGui::InputText(label, text_buf, IM_ARRAYSIZE(text_buf), ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_AutoSelectAll); value_changed = ImGui::InputText(label, text_buf, IM_ARRAYSIZE(text_buf), ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_AutoSelectAll);
@ -4186,15 +4272,18 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c
// First frame // First frame
IM_ASSERT(g.ActiveId == id); // InputText ID should match the Slider ID (else we'd need to store them both which is also possible) IM_ASSERT(g.ActiveId == id); // InputText ID should match the Slider ID (else we'd need to store them both which is also possible)
g.SliderAsInputTextId = g.ActiveId; g.SliderAsInputTextId = g.ActiveId;
g.ActiveId = id; SetActiveId(id);
g.HoveredId = id; g.HoveredId = id;
} }
else else
{ {
if (g.ActiveId == g.SliderAsInputTextId) if (g.ActiveId == g.SliderAsInputTextId)
g.ActiveId = id; SetActiveId(id);
else else
g.ActiveId = g.SliderAsInputTextId = 0; {
SetActiveId(0);
g.SliderAsInputTextId = 0;
}
} }
if (value_changed) if (value_changed)
{ {
@ -4258,7 +4347,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c
} }
else else
{ {
g.ActiveId = 0; SetActiveId(0);
} }
} }
@ -4740,7 +4829,7 @@ namespace IMGUI_STB_NAMESPACE
{ {
#endif #endif
#define STB_TEXTEDIT_IMPLEMENTATION #define STB_TEXTEDIT_IMPLEMENTATION
#include <stb/stb_textedit.h> #include "stb_textedit.h"
#ifdef IMGUI_STB_NAMESPACE #ifdef IMGUI_STB_NAMESPACE
} }
#endif #endif
@ -4999,7 +5088,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
if (tab_focus_requested || is_ctrl_down) if (tab_focus_requested || is_ctrl_down)
select_all = true; select_all = true;
} }
g.ActiveId = id; SetActiveId(id);
FocusWindow(window); FocusWindow(window);
} }
else if (io.MouseClicked[0]) else if (io.MouseClicked[0])
@ -5007,7 +5096,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
// Release focus when we click outside // Release focus when we click outside
if (g.ActiveId == id) if (g.ActiveId == id)
{ {
g.ActiveId = 0; SetActiveId(0);
} }
} }
@ -5045,6 +5134,25 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
if (edit_state.SelectedAllMouseLock && !io.MouseDown[0]) if (edit_state.SelectedAllMouseLock && !io.MouseDown[0])
edit_state.SelectedAllMouseLock = false; edit_state.SelectedAllMouseLock = false;
if (g.IO.InputCharacters[0])
{
// Process text input (before we check for Return because using some IME will effectively send a Return?)
for (int n = 0; n < IM_ARRAYSIZE(g.IO.InputCharacters) && g.IO.InputCharacters[n]; n++)
{
const ImWchar c = g.IO.InputCharacters[n];
if (c)
{
// Insert character if they pass filtering
if (InputTextFilterCharacter(c, flags))
continue;
edit_state.OnKeyPressed(c);
}
}
// Consume characters
memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
}
const int k_mask = (is_shift_down ? STB_TEXTEDIT_K_SHIFT : 0); const int k_mask = (is_shift_down ? STB_TEXTEDIT_K_SHIFT : 0);
if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_WORDLEFT | k_mask : STB_TEXTEDIT_K_LEFT | k_mask); } if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_WORDLEFT | k_mask : STB_TEXTEDIT_K_LEFT | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_WORDRIGHT | k_mask : STB_TEXTEDIT_K_RIGHT | k_mask); } else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_WORDRIGHT | k_mask : STB_TEXTEDIT_K_RIGHT | k_mask); }
@ -5052,8 +5160,8 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_Delete)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Delete)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_Backspace)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Backspace)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_Enter)) { g.ActiveId = 0; enter_pressed = true; } else if (IsKeyPressedMap(ImGuiKey_Enter)) { SetActiveId(0); enter_pressed = true; }
else if (IsKeyPressedMap(ImGuiKey_Escape)) { g.ActiveId = 0; cancel_edit = true; } else if (IsKeyPressedMap(ImGuiKey_Escape)) { SetActiveId(0); cancel_edit = true; }
else if (is_ctrl_down && IsKeyPressedMap(ImGuiKey_Z)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); } else if (is_ctrl_down && IsKeyPressedMap(ImGuiKey_Z)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); }
else if (is_ctrl_down && IsKeyPressedMap(ImGuiKey_Y)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); } else if (is_ctrl_down && IsKeyPressedMap(ImGuiKey_Y)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); }
else if (is_ctrl_down && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); } else if (is_ctrl_down && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); }
@ -5106,24 +5214,6 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
} }
} }
} }
else if (g.IO.InputCharacters[0])
{
// Text input
for (int n = 0; n < IM_ARRAYSIZE(g.IO.InputCharacters) && g.IO.InputCharacters[n]; n++)
{
const ImWchar c = g.IO.InputCharacters[n];
if (c)
{
// Insert character if they pass filtering
if (InputTextFilterCharacter(c, flags))
continue;
edit_state.OnKeyPressed(c);
}
}
// Consume characters
memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
}
edit_state.CursorAnim += g.IO.DeltaTime; edit_state.CursorAnim += g.IO.DeltaTime;
edit_state.UpdateScrollOffset(); edit_state.UpdateScrollOffset();
@ -5442,7 +5532,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
} }
if (item_pressed) if (item_pressed)
{ {
g.ActiveId = 0; SetActiveId(0);
g.ActiveComboID = 0; g.ActiveComboID = 0;
value_changed = true; value_changed = true;
*current_item = item_idx; *current_item = item_idx;
@ -5533,7 +5623,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha)
const ImVec4 col_display(fx, fy, fz, 1.0f); const ImVec4 col_display(fx, fy, fz, 1.0f);
if (edit_mode == ImGuiColorEditMode_HSV) if (edit_mode == ImGuiColorEditMode_HSV)
ImConvertColorRGBtoHSV(fx, fy, fz, fx, fy, fz); ImGui::ColorConvertRGBtoHSV(fx, fy, fz, fx, fy, fz);
int ix = (int)(fx * 255.0f + 0.5f); int ix = (int)(fx * 255.0f + 0.5f);
int iy = (int)(fy * 255.0f + 0.5f); int iy = (int)(fy * 255.0f + 0.5f);
@ -5635,7 +5725,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha)
fz = iz / 255.0f; fz = iz / 255.0f;
fw = iw / 255.0f; fw = iw / 255.0f;
if (edit_mode == 1) if (edit_mode == 1)
ImConvertColorHSVtoRGB(fx, fy, fz, fx, fy, fz); ImGui::ColorConvertHSVtoRGB(fx, fy, fz, fx, fy, fz);
if (value_changed) if (value_changed)
{ {
@ -5693,7 +5783,7 @@ void ImGui::Spacing()
} }
// Advance cursor given item size. // Advance cursor given item size.
static void ItemSize(ImVec2 size, ImVec2* adjust_start_offset) static void ItemSize(ImVec2 size, ImVec2* adjust_vertical_offset)
{ {
ImGuiState& g = GImGui; ImGuiState& g = GImGui;
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
@ -5701,8 +5791,8 @@ static void ItemSize(ImVec2 size, ImVec2* adjust_start_offset)
return; return;
const float line_height = ImMax(window->DC.CurrentLineHeight, size.y); const float line_height = ImMax(window->DC.CurrentLineHeight, size.y);
if (adjust_start_offset) if (adjust_vertical_offset)
adjust_start_offset->y = adjust_start_offset->y + (line_height - size.y) * 0.5f; adjust_vertical_offset->y = adjust_vertical_offset->y + (line_height - size.y) * 0.5f;
// Always align ourselves on pixel boundaries // Always align ourselves on pixel boundaries
window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y); window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y);
@ -6021,68 +6111,84 @@ void ImDrawList::Clear()
texture_id_stack.resize(0); texture_id_stack.resize(0);
} }
void ImDrawList::SetClipRect(const ImVec4& clip_rect) void ImDrawList::AddDrawCmd()
{
ImDrawCmd* current_cmd = commands.empty() ? NULL : &commands.back();
if (current_cmd && current_cmd->vtx_count == 0)
{
// Reuse existing command (high-level clipping may have discarded vertices submitted earlier)
// FIXME-OPT: Possibly even reuse previous command.
current_cmd->clip_rect = clip_rect;
}
else
{ {
ImDrawCmd draw_cmd; ImDrawCmd draw_cmd;
draw_cmd.vtx_count = 0; draw_cmd.vtx_count = 0;
draw_cmd.clip_rect = clip_rect; draw_cmd.clip_rect = clip_rect_stack.empty() ? GNullClipRect : clip_rect_stack.back();
draw_cmd.texture_id = texture_id_stack.back(); draw_cmd.texture_id = texture_id_stack.empty() ? NULL : texture_id_stack.back();
draw_cmd.user_callback = NULL;
draw_cmd.user_callback_data = NULL;
commands.push_back(draw_cmd); commands.push_back(draw_cmd);
} }
void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
{
ImDrawCmd* current_cmd = commands.empty() ? NULL : &commands.back();
if (!current_cmd || current_cmd->vtx_count != 0 || current_cmd->user_callback != NULL)
{
AddDrawCmd();
current_cmd = &commands.back();
}
current_cmd->user_callback = callback;
current_cmd->user_callback_data = callback_data;
// Force a new command after us
// We function this way so that the most common calls (AddLine, AddRect..) always have a command to add to without doing any check.
AddDrawCmd();
}
void ImDrawList::UpdateClipRect()
{
ImDrawCmd* current_cmd = commands.empty() ? NULL : &commands.back();
if (!current_cmd || (current_cmd->vtx_count != 0) || current_cmd->user_callback != NULL)
{
AddDrawCmd();
}
else
{
current_cmd->clip_rect = clip_rect_stack.empty() ? GNullClipRect : clip_rect_stack.back();
}
} }
void ImDrawList::PushClipRect(const ImVec4& clip_rect) void ImDrawList::PushClipRect(const ImVec4& clip_rect)
{ {
SetClipRect(clip_rect);
clip_rect_stack.push_back(clip_rect); clip_rect_stack.push_back(clip_rect);
UpdateClipRect();
} }
void ImDrawList::PopClipRect() void ImDrawList::PopClipRect()
{ {
IM_ASSERT(clip_rect_stack.size() > 0);
clip_rect_stack.pop_back(); clip_rect_stack.pop_back();
const ImVec4 clip_rect = clip_rect_stack.empty() ? GNullClipRect : clip_rect_stack.back(); UpdateClipRect();
SetClipRect(clip_rect);
} }
void ImDrawList::SetTextureID(const ImTextureID& texture_id) void ImDrawList::UpdateTextureID()
{ {
ImDrawCmd* current_cmd = commands.empty() ? NULL : &commands.back(); ImDrawCmd* current_cmd = commands.empty() ? NULL : &commands.back();
if (current_cmd && (current_cmd->vtx_count == 0 || current_cmd->texture_id == texture_id)) const ImTextureID texture_id = texture_id_stack.empty() ? NULL : texture_id_stack.back();
if (!current_cmd || (current_cmd->vtx_count != 0 && current_cmd->texture_id != texture_id) || current_cmd->user_callback != NULL)
{ {
// Reuse existing command AddDrawCmd();
// FIXME-OPT: Possibly even reuse previous command.
current_cmd->texture_id = texture_id;
} }
else else
{ {
ImDrawCmd draw_cmd; current_cmd->texture_id = texture_id;
draw_cmd.vtx_count = 0;
draw_cmd.clip_rect = clip_rect_stack.empty() ? GNullClipRect: clip_rect_stack.back();
draw_cmd.texture_id = texture_id;
commands.push_back(draw_cmd);
} }
} }
void ImDrawList::PushTextureID(const ImTextureID& texture_id) void ImDrawList::PushTextureID(const ImTextureID& texture_id)
{ {
SetTextureID(texture_id);
texture_id_stack.push_back(texture_id); texture_id_stack.push_back(texture_id);
UpdateTextureID();
} }
void ImDrawList::PopTextureID() void ImDrawList::PopTextureID()
{ {
IM_ASSERT(texture_id_stack.size() > 0);
texture_id_stack.pop_back(); texture_id_stack.pop_back();
const ImTextureID texture_id = texture_id_stack.empty() ? NULL : texture_id_stack.back(); UpdateTextureID();
SetTextureID(texture_id);
} }
void ImDrawList::ReserveVertices(unsigned int vtx_count) void ImDrawList::ReserveVertices(unsigned int vtx_count)
@ -6112,6 +6218,7 @@ void ImDrawList::AddVtxUV(const ImVec2& pos, ImU32 col, const ImVec2& uv)
vtx_write++; vtx_write++;
} }
// NB: memory should be reserved for 6 vertices by the caller.
void ImDrawList::AddVtxLine(const ImVec2& a, const ImVec2& b, ImU32 col) void ImDrawList::AddVtxLine(const ImVec2& a, const ImVec2& b, ImU32 col)
{ {
const float length = sqrtf(ImLengthSqr(b - a)); const float length = sqrtf(ImLengthSqr(b - a));
@ -6335,7 +6442,7 @@ void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const Im
if ((col >> 24) == 0) if ((col >> 24) == 0)
return; return;
const bool push_texture_id = user_texture_id != texture_id_stack.back(); const bool push_texture_id = texture_id_stack.empty() || user_texture_id != texture_id_stack.back();
if (push_texture_id) if (push_texture_id)
PushTextureID(user_texture_id); PushTextureID(user_texture_id);
@ -6571,8 +6678,8 @@ bool ImFontAtlas::Build()
// Pack our extra data rectangle first, so it will be on the upper-left corner of our texture (UV will have small values). // Pack our extra data rectangle first, so it will be on the upper-left corner of our texture (UV will have small values).
stbrp_rect extra_rect; stbrp_rect extra_rect;
extra_rect.w = 16; extra_rect.w = (int)TEX_ATLAS_SIZE.x;
extra_rect.h = 16; extra_rect.h = (int)TEX_ATLAS_SIZE.y;
stbrp_pack_rects((stbrp_context*)spc.pack_info, &extra_rect, 1); stbrp_pack_rects((stbrp_context*)spc.pack_info, &extra_rect, 1);
TexExtraDataPos = ImVec2(extra_rect.x, extra_rect.y); TexExtraDataPos = ImVec2(extra_rect.x, extra_rect.y);
@ -6582,6 +6689,7 @@ bool ImFontAtlas::Build()
stbrp_rect* buf_rects = (stbrp_rect*)ImGui::MemAlloc(total_glyph_count * sizeof(stbrp_rect)); stbrp_rect* buf_rects = (stbrp_rect*)ImGui::MemAlloc(total_glyph_count * sizeof(stbrp_rect));
stbtt_pack_range* buf_ranges = (stbtt_pack_range*)ImGui::MemAlloc(total_glyph_range_count * sizeof(stbtt_pack_range)); stbtt_pack_range* buf_ranges = (stbtt_pack_range*)ImGui::MemAlloc(total_glyph_range_count * sizeof(stbtt_pack_range));
memset(buf_packedchars, 0, total_glyph_count * sizeof(stbtt_packedchar)); memset(buf_packedchars, 0, total_glyph_count * sizeof(stbtt_packedchar));
memset(buf_rects, 0, total_glyph_count * sizeof(stbrp_rect)); // Unnessary but let's clear this for the sake of sanity.
memset(buf_ranges, 0, total_glyph_range_count * sizeof(stbtt_pack_range)); memset(buf_ranges, 0, total_glyph_range_count * sizeof(stbtt_pack_range));
// First pass: pack all glyphs (no rendering at this point, we are working with glyph sizes only) // First pass: pack all glyphs (no rendering at this point, we are working with glyph sizes only)
@ -6696,11 +6804,51 @@ bool ImFontAtlas::Build()
buf_ranges = NULL; buf_ranges = NULL;
ClearInputData(); ClearInputData();
// Render into our custom data block
RenderCustomTexData();
return true;
}
void ImFontAtlas::RenderCustomTexData()
{
IM_ASSERT(TexExtraDataPos.x == 0.0f && TexExtraDataPos.y == 0.0f);
// Draw white pixel into texture and make UV points to it // Draw white pixel into texture and make UV points to it
TexPixelsAlpha8[0] = TexPixelsAlpha8[1] = TexPixelsAlpha8[TexWidth+0] = TexPixelsAlpha8[TexWidth+1] = 0xFF; TexPixelsAlpha8[0] = TexPixelsAlpha8[1] = TexPixelsAlpha8[TexWidth+0] = TexPixelsAlpha8[TexWidth+1] = 0xFF;
TexUvWhitePixel = ImVec2((TexExtraDataPos.x + 0.5f) / TexWidth, (TexExtraDataPos.y + 0.5f) / TexHeight); TexUvWhitePixel = ImVec2((TexExtraDataPos.x + 0.5f) / TexWidth, (TexExtraDataPos.y + 0.5f) / TexHeight);
return true; // Draw a mouse cursor into texture
// Because our font uses an alpha texture, we have to spread the cursor in 2 parts (black/white) which will be rendered separately.
const char cursor_pixels[] =
{
"X "
"XX "
"X.X "
"X..X "
"X...X "
"X....X "
"X.....X "
"X......X "
"X.......X "
"X........X "
"X.........X "
"X..........X"
"X......XXXXX"
"X...X..X "
"X..X X..X "
"X.X X..X "
"XX X..X "
" X..X "
" XX "
};
IM_ASSERT(sizeof(cursor_pixels)-1 == (int)TEX_ATLAS_SIZE_MOUSE_CURSOR.x * (int)TEX_ATLAS_SIZE_MOUSE_CURSOR.y);
for (int y = 0, n = 0; y < 19; y++)
for (int x = 0; x < 12; x++, n++)
{
TexPixelsAlpha8[((int)TEX_ATLAS_POS_MOUSE_CURSOR_BLACK.x + x) + ((int)TEX_ATLAS_POS_MOUSE_CURSOR_BLACK.y + y) * TexWidth] = (cursor_pixels[n] == 'X') ? 0xFF : 0x00;
TexPixelsAlpha8[((int)TEX_ATLAS_POS_MOUSE_CURSOR_WHITE.x + x) + ((int)TEX_ATLAS_POS_MOUSE_CURSOR_WHITE.y + y) * TexWidth] = (cursor_pixels[n] == '.') ? 0xFF : 0x00;
}
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -7542,7 +7690,12 @@ void ImGui::ShowTestWindow(bool* opened)
static float fill_alpha = 0.65f; static float fill_alpha = 0.65f;
const ImGuiWindowFlags layout_flags = (no_titlebar ? ImGuiWindowFlags_NoTitleBar : 0) | (no_border ? 0 : ImGuiWindowFlags_ShowBorders) | (no_resize ? ImGuiWindowFlags_NoResize : 0) | (no_move ? ImGuiWindowFlags_NoMove : 0) | (no_scrollbar ? ImGuiWindowFlags_NoScrollbar : 0); const ImGuiWindowFlags layout_flags = (no_titlebar ? ImGuiWindowFlags_NoTitleBar : 0) | (no_border ? 0 : ImGuiWindowFlags_ShowBorders) | (no_resize ? ImGuiWindowFlags_NoResize : 0) | (no_move ? ImGuiWindowFlags_NoMove : 0) | (no_scrollbar ? ImGuiWindowFlags_NoScrollbar : 0);
ImGui::Begin("ImGui Test", opened, ImVec2(550,680), fill_alpha, layout_flags); if (!ImGui::Begin("ImGui Test", opened, ImVec2(550,680), fill_alpha, layout_flags))
{
// Early out if the window is collapsed, as an optimization.
ImGui::End();
return;
}
ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f); ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f);
ImGui::Text("ImGui says hello."); ImGui::Text("ImGui says hello.");
@ -7679,7 +7832,8 @@ void ImGui::ShowTestWindow(bool* opened)
// Most compiler appears to support UTF-8 in source code (with Visual Studio you need to save your file as 'UTF-8 without signature') // Most compiler appears to support UTF-8 in source code (with Visual Studio you need to save your file as 'UTF-8 without signature')
// However for the sake for maximum portability here we are *not* including raw UTF-8 character in this source file, instead we encode the string with hexadecimal constants. // However for the sake for maximum portability here we are *not* including raw UTF-8 character in this source file, instead we encode the string with hexadecimal constants.
// In your own application be reasonable and use UTF-8 in source or retrieve the data from file system! // In your own application be reasonable and use UTF-8 in source or retrieve the data from file system!
ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->LoadFromFileTTF() manually to specify extra character ranges. Note that characters values are preserved even if the font cannot be displayed, so you can safely copy & paste garbled characters into another application."); // Note that characters values are preserved even if the font cannot be displayed, so you can safely copy & paste garbled characters into another application.
ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->LoadFromFileTTF() manually to load extra character ranges.");
ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)");
ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)"); ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
@ -7694,7 +7848,7 @@ void ImGui::ShowTestWindow(bool* opened)
float tex_w = (float)ImGui::GetIO().Fonts->TexWidth; float tex_w = (float)ImGui::GetIO().Fonts->TexWidth;
float tex_h = (float)ImGui::GetIO().Fonts->TexHeight; float tex_h = (float)ImGui::GetIO().Fonts->TexHeight;
ImTextureID tex_id = ImGui::GetIO().Fonts->TexID; ImTextureID tex_id = ImGui::GetIO().Fonts->TexID;
ImGui::Image(tex_id, ImVec2(tex_w, tex_h), ImVec2(0,0), ImVec2(1,1), 0xFFFFFFFF, 0x999999FF); ImGui::Image(tex_id, ImVec2(tex_w, tex_h), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128));
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
{ {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
@ -7705,9 +7859,22 @@ void ImGui::ShowTestWindow(bool* opened)
ImGui::Text("Max: (%.2f, %.2f)", focus_x + focus_sz, focus_y + focus_sz); ImGui::Text("Max: (%.2f, %.2f)", focus_x + focus_sz, focus_y + focus_sz);
ImVec2 uv0 = ImVec2((focus_x) / tex_w, (focus_y) / tex_h); ImVec2 uv0 = ImVec2((focus_x) / tex_w, (focus_y) / tex_h);
ImVec2 uv1 = ImVec2((focus_x + focus_sz) / tex_w, (focus_y + focus_sz) / tex_h); ImVec2 uv1 = ImVec2((focus_x + focus_sz) / tex_w, (focus_y + focus_sz) / tex_h);
ImGui::Image(tex_id, ImVec2(128,128), uv0, uv1, 0xFFFFFFFF, 0x999999FF); ImGui::Image(tex_id, ImVec2(128,128), uv0, uv1, ImColor(255,255,255,255), ImColor(255,255,255,128));
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
ImGui::TextWrapped("And now some textured buttons..");
static int pressed_count = 0;
for (int i = 0; i < 8; i++)
{
if (i > 0)
ImGui::SameLine();
ImGui::PushID(i);
int frame_padding = -1 + i; // -1 padding uses default padding
if (ImGui::ImageButton(tex_id, ImVec2(32,32), ImVec2(0,0), ImVec2(32.0f/tex_w,32/tex_h), frame_padding))
pressed_count += 1;
ImGui::PopID();
}
ImGui::Text("Pressed %d times.", pressed_count);
ImGui::TreePop(); ImGui::TreePop();
} }
@ -7719,7 +7886,20 @@ void ImGui::ShowTestWindow(bool* opened)
ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
ImGui::RadioButton("radio c", &e, 2); ImGui::RadioButton("radio c", &e, 2);
ImGui::Text("Hover me"); // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
for (int i = 0; i < 7; i++)
{
if (i > 0) ImGui::SameLine();
ImGui::PushID(i);
ImGui::PushStyleColor(ImGuiCol_Button, ImColor::HSV(i/7.0f, 0.6f, 0.6f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImColor::HSV(i/7.0f, 0.7f, 0.7f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImColor::HSV(i/7.0f, 0.8f, 0.8f));
ImGui::Button("Click");
ImGui::PopStyleColor(3);
ImGui::PopID();
}
ImGui::Text("Hover over me");
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
ImGui::SetTooltip("I am a tooltip"); ImGui::SetTooltip("I am a tooltip");
@ -7891,10 +8071,11 @@ void ImGui::ShowTestWindow(bool* opened)
ImGui::Columns(2); ImGui::Columns(2);
for (int i = 0; i < 100; i++) for (int i = 0; i < 100; i++)
{ {
if (i == 50)
ImGui::NextColumn();
char buf[32]; char buf[32];
ImFormatString(buf, IM_ARRAYSIZE(buf), "%08x", i*5731); ImFormatString(buf, IM_ARRAYSIZE(buf), "%08x", i*5731);
ImGui::Button(buf); ImGui::Button(buf);
ImGui::NextColumn();
} }
ImGui::EndChild(); ImGui::EndChild();
} }
@ -8154,7 +8335,7 @@ static void ShowExampleAppCustomRendering(bool* opened)
// However you can draw directly and poll mouse/keyboard by yourself. You can manipulate the cursor using GetCursorPos() and SetCursorPos(). // However you can draw directly and poll mouse/keyboard by yourself. You can manipulate the cursor using GetCursorPos() and SetCursorPos().
// If you only use the ImDrawList API, you can notify the owner window of its extends by using SetCursorPos(max) followed by an empty Text("") statement. // If you only use the ImDrawList API, you can notify the owner window of its extends by using SetCursorPos(max) followed by an empty Text("") statement.
ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates! ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); // ImDrawList API uses screen coordinates!
ImVec2 canvas_size = ImVec2(ImMin(50.0f,ImGui::GetWindowContentRegionMax().x-ImGui::GetCursorPos().x), ImMin(50.0f,ImGui::GetWindowContentRegionMax().y-ImGui::GetCursorPos().y)); // Resize canvas what's available ImVec2 canvas_size = ImVec2(ImMax(50.0f,ImGui::GetWindowContentRegionMax().x-ImGui::GetCursorPos().x), ImMax(50.0f,ImGui::GetWindowContentRegionMax().y-ImGui::GetCursorPos().y)); // Resize canvas what's available
draw_list->AddRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), 0xFFFFFFFF); draw_list->AddRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), 0xFFFFFFFF);
bool adding_preview = false; bool adding_preview = false;
ImGui::InvisibleButton("canvas", canvas_size); ImGui::InvisibleButton("canvas", canvas_size);
@ -8583,7 +8764,7 @@ static unsigned int stb_decompress(unsigned char *output, unsigned char *i, unsi
i += 16; i += 16;
stb__dout = output; stb__dout = output;
for (;;) { while (1) {
unsigned char *old_i = i; unsigned char *old_i = i;
i = stb_decompress_token(i); i = stb_decompress_token(i);
if (i == old_i) { if (i == old_i) {

View file

@ -1,4 +1,4 @@
// ImGui library v1.30 wip // ImGui library v1.30
// See .cpp file for commentary. // See .cpp file for commentary.
// See ImGui::ShowTestWindow() for sample code. // See ImGui::ShowTestWindow() for sample code.
// Read 'Programmer guide' in .cpp for notes on how to setup ImGui in your codebase. // Read 'Programmer guide' in .cpp for notes on how to setup ImGui in your codebase.
@ -6,6 +6,7 @@
#pragma once #pragma once
struct ImDrawCmd;
struct ImDrawList; struct ImDrawList;
struct ImFont; struct ImFont;
struct ImFontAtlas; struct ImFontAtlas;
@ -244,7 +245,8 @@ namespace ImGui
IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0,0), bool repeat_when_held = false); IMGUI_API bool Button(const char* label, const ImVec2& size = ImVec2(0,0), bool repeat_when_held = false);
IMGUI_API bool SmallButton(const char* label); IMGUI_API bool SmallButton(const char* label);
IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size); IMGUI_API bool InvisibleButton(const char* str_id, const ImVec2& size);
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), ImU32 tint_col = 0xFFFFFFFF, ImU32 border_col = 0x00000000); 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)); // <0 frame_padding uses default frame padding settings. 0 for no paddnig.
IMGUI_API bool CollapsingHeader(const char* label, const char* str_id = NULL, const bool display_frame = true, const bool default_open = false); IMGUI_API bool CollapsingHeader(const char* label, const char* str_id = NULL, const bool display_frame = true, const bool default_open = false);
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 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 SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f);
@ -321,6 +323,10 @@ namespace ImGui
IMGUI_API const char* GetStyleColName(ImGuiCol idx); IMGUI_API const char* GetStyleColName(ImGuiCol idx);
IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f); IMGUI_API ImVec2 CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f);
IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4& in);
IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v);
IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b);
// Obsolete (will be removed) // Obsolete (will be removed)
IMGUI_API void GetDefaultFontData(const void** fnt_data, unsigned int* fnt_size, const void** png_data, unsigned int* png_size); IMGUI_API void GetDefaultFontData(const void** fnt_data, unsigned int* fnt_size, const void** png_data, unsigned int* png_size);
@ -501,6 +507,8 @@ struct ImGuiIO
ImFontAtlas* Fonts; // <auto> // Load and assemble one or more fonts into a single tightly packed texture. Output to Fonts array. ImFontAtlas* Fonts; // <auto> // Load and assemble one or more fonts into a single tightly packed texture. Output to Fonts array.
float FontGlobalScale; // = 1.0f // Global scale all fonts float FontGlobalScale; // = 1.0f // Global scale all fonts
bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel. bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel.
ImVec2 DisplayVisibleMin; // <unset> (0.0f,0.0f) // If you use DisplaySize as a virtual space larger than your screen, set DisplayVisibleMin/Max to the visible area.
ImVec2 DisplayVisibleMax; // <unset> (0.0f,0.0f) // If the values are the same, we defaults to Min=(0.0f) and Max=DisplaySize
//------------------------------------------------------------------ //------------------------------------------------------------------
// User Functions // User Functions
@ -530,6 +538,7 @@ struct ImGuiIO
ImVec2 MousePos; // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.) ImVec2 MousePos; // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
bool MouseDown[5]; // Mouse buttons. ImGui itself only uses button 0 (left button) but you can use others as storage for convenience. bool MouseDown[5]; // Mouse buttons. ImGui itself only uses button 0 (left button) but you can use others as storage for convenience.
float MouseWheel; // Mouse wheel: 1 unit scrolls about 5 lines text. float MouseWheel; // Mouse wheel: 1 unit scrolls about 5 lines text.
bool MouseDrawCursor; // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor).
bool KeyCtrl; // Keyboard modifier pressed: Control bool KeyCtrl; // Keyboard modifier pressed: Control
bool KeyShift; // Keyboard modifier pressed: Shift bool KeyShift; // Keyboard modifier pressed: Shift
bool KeysDown[512]; // Keyboard keys that are pressed (in whatever order user naturally has access to keyboard data) bool KeysDown[512]; // Keyboard keys that are pressed (in whatever order user naturally has access to keyboard data)
@ -641,26 +650,34 @@ struct ImGuiStorage
struct Pair struct Pair
{ {
ImGuiID key; ImGuiID key;
union { int val_i; float val_f; }; union { int val_i; float val_f; void* val_p; };
Pair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; } Pair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; }
Pair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; } Pair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; }
Pair(ImGuiID _key, void* _val_p) { key = _key; val_p = _val_p; }
}; };
ImVector<Pair> Data; ImVector<Pair> Data;
// - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N) // - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N)
// - Set***() functions find pair, insertion on demand if missing. // - Set***() functions find pair, insertion on demand if missing.
// - Get***Ptr() functions find pair, insertion on demand if missing, return pointer. Useful if you intend to do Get+Set.
// A typical use case where this is very convenient:
// float* pvar = ImGui::GetIntPtr(key); ImGui::SliderInt("var", pvar, 0, 100); some_var += *pvar;
// - Sorted insertion is costly but should amortize. A typical frame shouldn't need to insert any new pair. // - Sorted insertion is costly but should amortize. A typical frame shouldn't need to insert any new pair.
IMGUI_API void Clear(); IMGUI_API void Clear();
IMGUI_API int GetInt(ImGuiID key, int default_val = 0) const; IMGUI_API int GetInt(ImGuiID key, int default_val = 0) const;
IMGUI_API void SetInt(ImGuiID key, int val); IMGUI_API void SetInt(ImGuiID key, int val);
IMGUI_API int* GetIntPtr(ImGuiID key, int default_val = 0);
IMGUI_API float GetFloat(ImGuiID key, float default_val = 0.0f) const; IMGUI_API float GetFloat(ImGuiID key, float default_val = 0.0f) const;
IMGUI_API void SetFloat(ImGuiID key, float val); IMGUI_API void SetFloat(ImGuiID key, float val);
IMGUI_API float* GetFloatPtr(ImGuiID key, float default_val = 0); IMGUI_API void* GetVoidPtr(ImGuiID key) const; // default_val is NULL
IMGUI_API void SetAllInt(int val); // Use on your own storage if you know only integer are being stored. IMGUI_API void SetVoidPtr(ImGuiID key, void* val);
// - Get***Ref() functions finds pair, insert on demand if missing, return pointer. Useful if you intend to do Get+Set.
// - 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.
// - A typical use case where this is convenient:
// float* pvar = ImGui::GetFloatRef(key); ImGui::SliderFloat("var", pvar, 0, 100.0f); some_var += *pvar;
// - You can also use this to quickly create temporary editable values during a session of using Edit&Continue, without restarting your application.
IMGUI_API int* GetIntRef(ImGuiID key, int default_val = 0);
IMGUI_API float* GetFloatRef(ImGuiID key, float default_val = 0);
// Use on your own storage if you know only integer are being stored (open/close all tree nodes)
IMGUI_API void SetAllInt(int val);
}; };
// Shared state of InputText(), passed to callback when a ImGuiInputTextFlags_Callback* flag is used. // Shared state of InputText(), passed to callback when a ImGuiInputTextFlags_Callback* flag is used.
@ -681,20 +698,50 @@ struct ImGuiTextEditCallbackData
void InsertChars(int pos, const char* text, const char* text_end = NULL); void InsertChars(int pos, const char* text, const char* text_end = NULL);
}; };
//----------------------------------------------------------------------------- // ImColor() is just a helper that implicity converts to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float)
// Draw List // None of the ImGui API are using ImColor directly but you can use it as a convenience to pass colors in either formats.
// Hold a series of drawing commands. The user provides a renderer for ImDrawList struct ImColor
//-----------------------------------------------------------------------------
struct ImDrawCmd
{ {
unsigned int vtx_count; ImVec4 Value;
ImVec4 clip_rect;
ImTextureID texture_id; // Copy of user-provided 'TexID' from ImFont or passed to Image*() functions. Ignore if not using images or multiple fonts. ImColor(int r, int g, int b, int a = 255) { Value.x = r / 255.0f; Value.y = g / 255.0f; Value.z = b / 255.0f; Value.w = a / 255.0f; }
ImColor(float r, float g, float b, float a = 1.0f) { Value.x = r; Value.y = g; Value.z = b; Value.w = a; }
ImColor(const ImVec4& col) { Value = col; }
operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); }
operator ImVec4() const { return Value; }
static ImColor HSV(float h, float s, float v, float a = 1.0f) { float r,g,b; ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); return ImColor(r,g,b,a); }
}; };
//-----------------------------------------------------------------------------
// Draw List
// Hold a series of drawing commands. The user provides a renderer for ImDrawList.
//-----------------------------------------------------------------------------
// Draw callbacks for advanced uses.
// NB- You most likely DO NOT need to care about draw callbacks just to create your own widget or customized UI rendering (you can poke into the draw list for that)
// Draw callback are useful for example if you want to render a complex 3D scene inside a UI element.
// The expected behavior from your rendering loop is:
// if (cmd.user_callback != NULL)
// cmd.user_callback(parent_list, cmd);
// else
// RenderTriangles()
// It is up to you to decide if your rendering loop or the callback should be responsible for backup/restoring rendering state.
typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd);
// Typically, 1 command = 1 gpu draw call
struct ImDrawCmd
{
unsigned int vtx_count; // Number of vertices (multiple of 3) to be drawn as triangles. The vertices are stored in the callee ImDrawList's vtx_buffer[] array.
ImVec4 clip_rect; // Clipping rectangle (x1, y1, x2, y2)
ImTextureID texture_id; // 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 user_callback; // If != NULL, call the function instead of rendering the vertices. vtx_count will be 0. clip_rect and texture_id will be set normally.
void* user_callback_data; // The draw callback code can access this.
};
// Vertex layout
#ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT #ifndef IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT
// Default vertex layout
struct ImDrawVert struct ImDrawVert
{ {
ImVec2 pos; ImVec2 pos;
@ -709,35 +756,28 @@ IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT;
#endif #endif
// Draw command list // Draw command list
// This is the low-level list of polygon that ImGui:: functions are creating. At the end of the frame, all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering. // 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. // 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. // 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. // You can interleave normal ImGui:: calls and adding primitives to the current draw list.
// 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 // 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 struct ImDrawList
{ {
// This is what you have to render // This is what you have to render
ImVector<ImDrawCmd> commands; // commands ImVector<ImDrawCmd> commands; // Commands. Typically 1 command = 1 gpu draw call.
ImVector<ImDrawVert> vtx_buffer; // each command consume ImDrawCmd::vtx_count of those ImVector<ImDrawVert> vtx_buffer; // Vertex buffer. Each command consume ImDrawCmd::vtx_count of those
// [Internal to ImGui] // [Internal to ImGui]
ImVector<ImVec4> clip_rect_stack; // [internal] ImVector<ImVec4> clip_rect_stack; // [Internal]
ImVector<ImTextureID> texture_id_stack; // [internal] ImVector<ImTextureID> texture_id_stack; // [Internal]
ImDrawVert* vtx_write; // [internal] point within vtx_buffer after each add command (to avoid using the ImVector<> operators too much) ImDrawVert* vtx_write; // [Internal] point within vtx_buffer after each add command (to avoid using the ImVector<> operators too much)
ImDrawList() { Clear(); } ImDrawList() { Clear(); }
IMGUI_API void Clear(); IMGUI_API void Clear();
IMGUI_API void SetClipRect(const ImVec4& clip_rect);
IMGUI_API void PushClipRect(const ImVec4& clip_rect); IMGUI_API void PushClipRect(const ImVec4& clip_rect);
IMGUI_API void PopClipRect(); IMGUI_API void PopClipRect();
IMGUI_API void SetTextureID(const ImTextureID& texture_id);
IMGUI_API void PushTextureID(const ImTextureID& texture_id); IMGUI_API void PushTextureID(const ImTextureID& texture_id);
IMGUI_API void PopTextureID(); IMGUI_API void PopTextureID();
IMGUI_API void ReserveVertices(unsigned int vtx_count);
IMGUI_API void AddVtx(const ImVec2& pos, ImU32 col);
IMGUI_API void AddVtxUV(const ImVec2& pos, ImU32 col, const ImVec2& uv);
IMGUI_API void AddVtxLine(const ImVec2& a, const ImVec2& b, ImU32 col);
// Primitives // Primitives
IMGUI_API void AddLine(const ImVec2& a, const ImVec2& b, ImU32 col); IMGUI_API void AddLine(const ImVec2& a, const ImVec2& b, ImU32 col);
@ -748,7 +788,19 @@ struct ImDrawList
IMGUI_API void AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12); IMGUI_API void AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12);
IMGUI_API void AddArc(const ImVec2& center, float rad, ImU32 col, int a_min, int a_max, bool tris = false, const ImVec2& third_point_offset = ImVec2(0,0)); IMGUI_API void AddArc(const ImVec2& center, float rad, ImU32 col, int a_min, int a_max, bool tris = false, const ImVec2& third_point_offset = ImVec2(0,0));
IMGUI_API void AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f); IMGUI_API void AddText(ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f);
IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv0, const ImVec2& uv1, ImU32 col); IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv0, const ImVec2& uv1, ImU32 col = 0xFFFFFFFF);
// Advanced
IMGUI_API void AddCallback(ImDrawCallback callback, void* callback_data); // Your rendering function must check for 'user_callback' in ImDrawCmd and call the function instead of rendering triangles.
IMGUI_API void AddDrawCmd(); // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible
// Internal helpers
IMGUI_API void ReserveVertices(unsigned int vtx_count);
IMGUI_API void AddVtx(const ImVec2& pos, ImU32 col);
IMGUI_API void AddVtxUV(const ImVec2& pos, ImU32 col, const ImVec2& uv);
IMGUI_API void AddVtxLine(const ImVec2& a, const ImVec2& b, ImU32 col);
IMGUI_API void UpdateClipRect();
IMGUI_API void UpdateTextureID();
}; };
// Load and rasterize multiple TTF fonts into a same texture. // Load and rasterize multiple TTF fonts into a same texture.
@ -800,6 +852,7 @@ struct ImFontAtlas
ImVector<ImFontAtlasData*> InputData; // Internal data ImVector<ImFontAtlasData*> InputData; // Internal data
IMGUI_API bool Build(); // Build pixels data. This is automatically for you by the GetTexData*** functions. IMGUI_API bool Build(); // Build pixels data. This is automatically for you by the GetTexData*** functions.
IMGUI_API void ClearInputData(); // Clear the input TTF data. IMGUI_API void ClearInputData(); // Clear the input TTF data.
IMGUI_API void RenderCustomTexData();
}; };
// TTF font loading and rendering // TTF font loading and rendering

View file

@ -0,0 +1 @@
#include <stb/stb_rect_pack.h>

1
3rdparty/ocornut-imgui/stb_textedit.h vendored Normal file
View file

@ -0,0 +1 @@
#include <stb/stb_textedit.h>

1
3rdparty/ocornut-imgui/stb_truetype.h vendored Normal file
View file

@ -0,0 +1 @@
#include <stb/stb_truetype.h>

View file

@ -139,6 +139,9 @@ struct OcornutImguiContext
, bgfx::copy(data, width*height*4) , bgfx::copy(data, width*height*4)
); );
ImGuiStyle& style = ImGui::GetStyle();
style.FrameRounding = 4.0f;
io.RenderDrawListsFn = imguiRender; io.RenderDrawListsFn = imguiRender;
} }
@ -160,6 +163,8 @@ struct OcornutImguiContext
io.MouseDown[0] = 0 != (_button & IMGUI_MBUT_LEFT); io.MouseDown[0] = 0 != (_button & IMGUI_MBUT_LEFT);
ImGui::NewFrame(); ImGui::NewFrame();
ImGui::ShowTestWindow();
} }
void endFrame() void endFrame()