Merge remote-tracking branch 'origin' into 2015-04-indexed-rendering

Conflicts:
	examples/directx11_example/imgui_impl_dx11.cpp
This commit is contained in:
ocornut 2015-05-21 22:57:29 +01:00
commit e3f2ad728a
4 changed files with 151 additions and 126 deletions

View File

@ -27,7 +27,8 @@ static ID3D10Blob * g_pPixelShaderBlob = NULL;
static ID3D11PixelShader* g_pPixelShader = NULL; static ID3D11PixelShader* g_pPixelShader = NULL;
static ID3D11SamplerState* g_pFontSampler = NULL; static ID3D11SamplerState* g_pFontSampler = NULL;
static ID3D11ShaderResourceView*g_pFontTextureView = NULL; static ID3D11ShaderResourceView*g_pFontTextureView = NULL;
static ID3D11BlendState* g_blendState = NULL; static ID3D11RasterizerState* g_pRasterizerState = NULL;
static ID3D11BlendState* g_pBlendState = NULL;
static int VERTEX_BUFFER_SIZE = 30000; // TODO: Make buffers smaller and grow dynamically as needed. static int VERTEX_BUFFER_SIZE = 30000; // TODO: Make buffers smaller and grow dynamically as needed.
static int INDEX_BUFFER_SIZE = 30000; // TODO: Make buffers smaller and grow dynamically as needed. static int INDEX_BUFFER_SIZE = 30000; // TODO: Make buffers smaller and grow dynamically as needed.
@ -109,7 +110,8 @@ static void ImGui_ImplDX11_RenderDrawLists(ImDrawList** const cmd_lists, int cmd
// Setup render state // Setup render state
const float blendFactor[4] = { 0.f, 0.f, 0.f, 0.f }; const float blendFactor[4] = { 0.f, 0.f, 0.f, 0.f };
g_pd3dDeviceContext->OMSetBlendState(g_blendState, blendFactor, 0xffffffff); g_pd3dDeviceContext->OMSetBlendState(g_pBlendState, blendFactor, 0xffffffff);
g_pd3dDeviceContext->RSSetState(g_pRasterizerState);
// Render command lists // Render command lists
int vtx_offset = 0; int vtx_offset = 0;
@ -350,18 +352,30 @@ bool ImGui_ImplDX11_CreateDeviceObjects()
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
g_pd3dDevice->CreateBlendState(&desc, &g_blendState); g_pd3dDevice->CreateBlendState(&desc, &g_pBlendState);
}
// Create the rasterizer state
{
D3D11_RASTERIZER_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = D3D11_CULL_NONE;
desc.ScissorEnable = true;
desc.DepthClipEnable = true;
g_pd3dDevice->CreateRasterizerState(&desc, &g_pRasterizerState);
} }
// Create the vertex buffer // Create the vertex buffer
{ {
D3D11_BUFFER_DESC bufferDesc; D3D11_BUFFER_DESC desc;
memset(&bufferDesc, 0, sizeof(D3D11_BUFFER_DESC)); memset(&desc, 0, sizeof(D3D11_BUFFER_DESC));
bufferDesc.Usage = D3D11_USAGE_DYNAMIC; desc.Usage = D3D11_USAGE_DYNAMIC;
bufferDesc.ByteWidth = VERTEX_BUFFER_SIZE * sizeof(ImDrawVert); desc.ByteWidth = VERTEX_BUFFER_SIZE * sizeof(ImDrawVert);
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
if (g_pd3dDevice->CreateBuffer(&bufferDesc, NULL, &g_pVB) < 0) desc.MiscFlags = 0;
if (g_pd3dDevice->CreateBuffer(&desc, NULL, &g_pVB) < 0)
return false; return false;
} }
@ -392,7 +406,8 @@ void ImGui_ImplDX11_InvalidateDeviceObjects()
if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } if (g_pIB) { g_pIB->Release(); g_pIB = NULL; }
if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } if (g_pVB) { g_pVB->Release(); g_pVB = NULL; }
if (g_blendState) { g_blendState->Release(); g_blendState = NULL; } if (g_pBlendState) { g_pBlendState->Release(); g_pBlendState = NULL; }
if (g_pRasterizerState) { g_pRasterizerState->Release(); g_pRasterizerState = NULL; }
if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; } if (g_pPixelShader) { g_pPixelShader->Release(); g_pPixelShader = NULL; }
if (g_pPixelShaderBlob) { g_pPixelShaderBlob->Release(); g_pPixelShaderBlob = NULL; } if (g_pPixelShaderBlob) { g_pPixelShaderBlob->Release(); g_pPixelShaderBlob = NULL; }
if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; } if (g_pVertexConstantBuffer) { g_pVertexConstantBuffer->Release(); g_pVertexConstantBuffer = NULL; }

View File

@ -20,6 +20,9 @@ int main(int, char**)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#if __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui OpenGL3 example", NULL, NULL); GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui OpenGL3 example", NULL, NULL);
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
gl3wInit(); gl3wInit();

View File

@ -13,7 +13,7 @@
- API BREAKING CHANGES (read me when you update!) - API BREAKING CHANGES (read me when you update!)
- FREQUENTLY ASKED QUESTIONS (FAQ), TIPS - FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
- How do I update to a newer version of ImGui? - How do I update to a newer version of ImGui?
- Can I have multiple widgets with the same label? (Yes) - Can I have multiple widgets with the same label? Can I have widget without a label? (Yes)
- Why is my text output blurry? - Why is my text output blurry?
- How can I load a different font than the default? - How can I load a different font than the default?
- How can I load multiple fonts? - How can I load multiple fonts?
@ -196,17 +196,17 @@
Check the "API BREAKING CHANGES" sections for a list of occasional API breaking changes. If you have a problem with a function, search for its name Check the "API BREAKING CHANGES" sections for a list of occasional API breaking changes. If you have a problem with a function, search for its name
in the code, there will likely be a comment about it. Please report any issue to the GitHub page! in the code, there will likely be a comment about it. Please report any issue to the GitHub page!
Q: Can I have multiple widgets with the same label? Q: Can I have multiple widgets with the same label? Can I have widget without a label? (Yes)
A: Yes. A primer on the use of labels/IDs in ImGui.. A: Yes. A primer on the use of labels/IDs in ImGui..
- Elements that are not clickable, such as Text() items don't need an ID.
- Interactive widgets require state to be carried over multiple frames (most typically ImGui often needs to remember what is the "active" widget). - Interactive widgets require state to be carried over multiple frames (most typically ImGui often needs to remember what is the "active" widget).
to do so they need an unique ID. unique ID are typically derived from a string label, an integer index or a pointer. to do so they need an unique ID. unique ID are typically derived from a string label, an integer index or a pointer.
Button("OK"); // Label = "OK", ID = hash of "OK" Button("OK"); // Label = "OK", ID = hash of "OK"
Button("Cancel"); // Label = "Cancel", ID = hash of "Cancel" Button("Cancel"); // Label = "Cancel", ID = hash of "Cancel"
- Elements that are not clickable, such as Text() items don't need an ID.
- ID are uniquely scoped within windows, tree nodes, etc. so no conflict can happen if you have two buttons called "OK" in two different windows - ID are uniquely scoped within windows, tree nodes, etc. so no conflict can happen if you have two buttons called "OK" in two different windows
or in two different locations of a tree. or in two different locations of a tree.
@ -223,6 +223,10 @@
Button("Play##0"); // Label = "Play", ID = hash of "Play##0" Button("Play##0"); // Label = "Play", ID = hash of "Play##0"
Button("Play##1"); // Label = "Play", ID = hash of "Play##1" (different from above) Button("Play##1"); // Label = "Play", ID = hash of "Play##1" (different from above)
- so if you want to hide the label but need an ID:
Checkbox("##On", &b); // Label = "", ID = hash of "##On"
- occasionally (rarely) you might want change a label while preserving a constant ID. This allows you to animate labels. - occasionally (rarely) you might want change a label while preserving a constant ID. This allows you to animate labels.
use "###" to pass a label that isn't part of ID: use "###" to pass a label that isn't part of ID:
@ -495,8 +499,9 @@ struct ImGuiTextEditState;
struct ImGuiIniData; struct ImGuiIniData;
struct ImGuiState; struct ImGuiState;
struct ImGuiWindow; struct ImGuiWindow;
typedef int ImGuiButtonFlags; // enum ImGuiButtonFlags_
static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat = false, bool pressed_on_click = false); static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, ImGuiButtonFlags flags = 0);
static void LogText(const ImVec2& ref_pos, const char* text, const char* text_end = NULL); static void LogText(const ImVec2& ref_pos, const char* text, const char* text_end = NULL);
static void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true); static void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true);
@ -700,6 +705,7 @@ static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs)
static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; } static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; }
static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; } static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; }
//static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; } //static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; }
static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x-rhs.x, lhs.y-rhs.y, lhs.z-rhs.z, lhs.w-lhs.w); }
static inline int ImMin(int lhs, int rhs) { return lhs < rhs ? lhs : rhs; } static inline int ImMin(int lhs, int rhs) { return lhs < rhs ? lhs : rhs; }
static inline int ImMax(int lhs, int rhs) { return lhs >= rhs ? lhs : rhs; } static inline int ImMax(int lhs, int rhs) { return lhs >= rhs ? lhs : rhs; }
@ -714,6 +720,7 @@ static inline float ImSaturate(float f)
static inline float ImLerp(float a, float b, float t) { return a + (b - a) * t; } static inline float ImLerp(float a, float b, float t) { return a + (b - a) * t; }
static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); } static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); }
static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; } static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; }
static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; }
static int ImStricmp(const char* str1, const char* str2) static int ImStricmp(const char* str1, const char* str2)
{ {
@ -932,6 +939,13 @@ static bool ImLoadFileToMemory(const char* filename, const char* file_open_mode,
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
enum ImGuiButtonFlags_
{
ImGuiButtonFlags_Repeat = (1 << 0),
ImGuiButtonFlags_PressedOnClick = (1 << 1),
ImGuiButtonFlags_FlattenChilds = (1 << 2)
};
struct ImGuiColMod // Color modifier, backup of modified data so we can restore it struct ImGuiColMod // Color modifier, backup of modified data so we can restore it
{ {
ImGuiCol Col; ImGuiCol Col;
@ -1277,6 +1291,7 @@ struct ImGuiWindow
bool Accessed; // Set to true when any widget access the current window bool Accessed; // Set to true when any widget access the current window
bool Collapsed; // Set when collapsing window to become only title-bar bool Collapsed; // Set when collapsing window to become only title-bar
bool SkipItems; // == Visible && !Collapsed bool SkipItems; // == Visible && !Collapsed
int BeginCount; // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs)
int AutoFitFrames; int AutoFitFrames;
bool AutoFitOnlyGrows; bool AutoFitOnlyGrows;
int AutoPosLastDirection; int AutoPosLastDirection;
@ -1636,6 +1651,7 @@ ImGuiWindow::ImGuiWindow(const char* name)
Accessed = false; Accessed = false;
Collapsed = false; Collapsed = false;
SkipItems = false; SkipItems = false;
BeginCount = 0;
AutoFitFrames = -1; AutoFitFrames = -1;
AutoFitOnlyGrows = false; AutoFitOnlyGrows = false;
AutoPosLastDirection = -1; AutoPosLastDirection = -1;
@ -1868,7 +1884,6 @@ static void SaveSettings()
static void MarkSettingsDirty() static void MarkSettingsDirty()
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
if (g.SettingsDirtyTimer <= 0.0f) if (g.SettingsDirtyTimer <= 0.0f)
g.SettingsDirtyTimer = g.IO.IniSavingRate; g.SettingsDirtyTimer = g.IO.IniSavingRate;
} }
@ -2981,7 +2996,7 @@ void ImGui::EndChild()
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow);
if (window->Flags & ImGuiWindowFlags_ComboBox) if ((window->Flags & ImGuiWindowFlags_ComboBox) || window->BeginCount > 1)
{ {
ImGui::End(); ImGui::End();
} }
@ -3218,11 +3233,11 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
if (first_begin_of_the_frame) if (first_begin_of_the_frame)
{ {
window->Active = true; window->Active = true;
window->BeginCount = 0;
window->DrawList->Clear(); window->DrawList->Clear();
window->ClipRectStack.resize(0); window->ClipRectStack.resize(0);
window->LastFrameDrawn = current_frame; window->LastFrameDrawn = current_frame;
window->IDStack.resize(1); window->IDStack.resize(1);
}
// Setup texture, outer clipping rectangle // Setup texture, outer clipping rectangle
window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
@ -3231,8 +3246,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
else else
PushClipRect(GetVisibleRect()); PushClipRect(GetVisibleRect());
if (first_begin_of_the_frame)
{
// New windows appears in front // New windows appears in front
if (!window_was_visible) if (!window_was_visible)
{ {
@ -3431,7 +3444,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
const ImRect resize_rect(window->Rect().GetBR()-ImVec2(14,14), window->Rect().GetBR()); const ImRect resize_rect(window->Rect().GetBR()-ImVec2(14,14), window->Rect().GetBR());
const ImGuiID resize_id = window->GetID("#RESIZE"); const ImGuiID resize_id = window->GetID("#RESIZE");
bool hovered, held; bool hovered, held;
ButtonBehavior(resize_rect, resize_id, &hovered, &held, true); ButtonBehavior(resize_rect, resize_id, &hovered, &held, true, ImGuiButtonFlags_FlattenChilds);
resize_col = window->Color(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); resize_col = window->Color(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
if (hovered || held) if (hovered || held)
@ -3584,6 +3597,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_
ImGui::LogToClipboard(); ImGui::LogToClipboard();
*/ */
} }
window->BeginCount++;
// 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
@ -3628,8 +3642,6 @@ void ImGui::End()
ImGui::Columns(1, "#CloseColumns"); ImGui::Columns(1, "#CloseColumns");
PopClipRect(); // inner window clip rectangle PopClipRect(); // inner window clip rectangle
PopClipRect(); // outer window clip rectangle
window->DrawList->PopTextureID();
// Stop logging // Stop logging
if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging
@ -3782,7 +3794,6 @@ float ImGui::CalcItemWidth()
static void SetFont(ImFont* font) static void SetFont(ImFont* font)
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
IM_ASSERT(font && font->IsLoaded()); IM_ASSERT(font && font->IsLoaded());
IM_ASSERT(font->Scale > 0.0f); IM_ASSERT(font->Scale > 0.0f);
g.Font = font; g.Font = font;
@ -3794,10 +3805,8 @@ static void SetFont(ImFont* font)
void ImGui::PushFont(ImFont* font) void ImGui::PushFont(ImFont* font)
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
if (!font) if (!font)
font = g.IO.Fonts->Fonts[0]; font = g.IO.Fonts->Fonts[0];
SetFont(font); SetFont(font);
g.FontStack.push_back(font); g.FontStack.push_back(font);
g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID); g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID);
@ -3806,7 +3815,6 @@ void ImGui::PushFont(ImFont* font)
void ImGui::PopFont() void ImGui::PopFont()
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
g.CurrentWindow->DrawList->PopTextureID(); g.CurrentWindow->DrawList->PopTextureID();
g.FontStack.pop_back(); g.FontStack.pop_back();
SetFont(g.FontStack.empty() ? g.IO.Fonts->Fonts[0] : g.FontStack.back()); SetFont(g.FontStack.empty() ? g.IO.Fonts->Fonts[0] : g.FontStack.back());
@ -3839,7 +3847,6 @@ void ImGui::PopTextWrapPos()
void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col) void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col)
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
ImGuiColMod backup; ImGuiColMod backup;
backup.Col = idx; backup.Col = idx;
backup.PreviousValue = g.Style.Colors[idx]; backup.PreviousValue = g.Style.Colors[idx];
@ -3850,7 +3857,6 @@ void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col)
void ImGui::PopStyleColor(int count) void ImGui::PopStyleColor(int count)
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
while (count > 0) while (count > 0)
{ {
ImGuiColMod& backup = g.ColorModifiers.back(); ImGuiColMod& backup = g.ColorModifiers.back();
@ -3891,7 +3897,6 @@ static ImVec2* GetStyleVarVec2Addr(ImGuiStyleVar idx)
void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) void ImGui::PushStyleVar(ImGuiStyleVar idx, float val)
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
float* pvar = GetStyleVarFloatAddr(idx); float* pvar = GetStyleVarFloatAddr(idx);
IM_ASSERT(pvar != NULL); // Called function with wrong-type? Variable is not a float. IM_ASSERT(pvar != NULL); // Called function with wrong-type? Variable is not a float.
ImGuiStyleMod backup; ImGuiStyleMod backup;
@ -3905,7 +3910,6 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, float val)
void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
ImVec2* pvar = GetStyleVarVec2Addr(idx); ImVec2* pvar = GetStyleVarVec2Addr(idx);
IM_ASSERT(pvar != NULL); // Called function with wrong-type? Variable is not a ImVec2. IM_ASSERT(pvar != NULL); // Called function with wrong-type? Variable is not a ImVec2.
ImGuiStyleMod backup; ImGuiStyleMod backup;
@ -3918,7 +3922,6 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)
void ImGui::PopStyleVar(int count) void ImGui::PopStyleVar(int count)
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
while (count > 0) while (count > 0)
{ {
ImGuiStyleMod& backup = g.StyleModifiers.back(); ImGuiStyleMod& backup = g.StyleModifiers.back();
@ -4521,9 +4524,8 @@ void ImGui::LabelText(const char* label, const char* fmt, ...)
static inline bool IsWindowContentHoverable(ImGuiWindow* window) static inline bool IsWindowContentHoverable(ImGuiWindow* window)
{ {
ImGuiState& g = *GImGui;
// An active popup disable hovering on other windows (apart from its own children) // An active popup disable hovering on other windows (apart from its own children)
ImGuiState& g = *GImGui;
if (ImGuiWindow* focused_window = g.FocusedWindow) if (ImGuiWindow* focused_window = g.FocusedWindow)
if (ImGuiWindow* focused_root_window = focused_window->RootWindow) if (ImGuiWindow* focused_root_window = focused_window->RootWindow)
if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) != 0 && focused_root_window->WasActive && focused_root_window != window->RootWindow) if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) != 0 && focused_root_window->WasActive && focused_root_window != window->RootWindow)
@ -4532,13 +4534,13 @@ static inline bool IsWindowContentHoverable(ImGuiWindow* window)
return true; return true;
} }
static bool IsHovered(const ImRect& bb, ImGuiID id) static bool IsHovered(const ImRect& bb, ImGuiID id, bool flatten_childs = false)
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
if (g.HoveredId == 0) if (g.HoveredId == 0)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
if (g.HoveredRootWindow == window->RootWindow) if (g.HoveredWindow == window || (flatten_childs && g.HoveredRootWindow == window->RootWindow))
if ((g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdIsFocusedOnly) && IsMouseHoveringRect(bb)) if ((g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdIsFocusedOnly) && IsMouseHoveringRect(bb))
if (IsWindowContentHoverable(g.HoveredRootWindow)) if (IsWindowContentHoverable(g.HoveredRootWindow))
return true; return true;
@ -4546,13 +4548,13 @@ static bool IsHovered(const ImRect& bb, ImGuiID id)
return false; return false;
} }
static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, bool repeat, bool pressed_on_click) static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, bool allow_key_modifiers, ImGuiButtonFlags flags)
{ {
ImGuiState& g = *GImGui; ImGuiState& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
const bool hovered = IsHovered(bb, id);
bool pressed = false; bool pressed = false;
const bool hovered = IsHovered(bb, id, (flags & ImGuiButtonFlags_FlattenChilds) != 0);
if (hovered) if (hovered)
{ {
g.HoveredId = id; g.HoveredId = id;
@ -4560,7 +4562,7 @@ static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
{ {
if (g.IO.MouseClicked[0]) if (g.IO.MouseClicked[0])
{ {
if (pressed_on_click) if (flags & ImGuiButtonFlags_PressedOnClick)
{ {
pressed = true; pressed = true;
SetActiveId(0); SetActiveId(0);
@ -4571,7 +4573,7 @@ static bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
} }
FocusWindow(window); FocusWindow(window);
} }
else if (repeat && g.ActiveId && ImGui::IsMouseClicked(0, true)) else if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && ImGui::IsMouseClicked(0, true))
{ {
pressed = true; pressed = true;
} }
@ -4617,7 +4619,7 @@ bool ImGui::Button(const char* label, const ImVec2& size_arg, bool repeat_when_h
return false; return false;
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, true, repeat_when_held); bool pressed = ButtonBehavior(bb, id, &hovered, &held, true, repeat_when_held ? ImGuiButtonFlags_Repeat : 0);
// Render // Render
const ImU32 col = window->Color((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); const ImU32 col = window->Color((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
@ -6801,7 +6803,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT
// Draw blinking cursor // Draw blinking cursor
if (g.InputTextState.CursorIsVisible()) if (g.InputTextState.CursorIsVisible())
window->DrawList->AddRect(cursor_pos - font_off_up + ImVec2(0,2), cursor_pos + font_off_dn - ImVec2(0,3), window->Color(ImGuiCol_Text)); window->DrawList->AddLine(cursor_pos - font_off_up + ImVec2(0,2), cursor_pos + font_off_dn - ImVec2(0,3), window->Color(ImGuiCol_Text));
// Notify OS of text input position for advanced IME // Notify OS of text input position for advanced IME
if (io.ImeSetInputScreenPosFn && ImLengthSqr(edit_state.InputCursorScreenPos - cursor_pos) > 0.0001f) if (io.ImeSetInputScreenPosFn && ImLengthSqr(edit_state.InputCursorScreenPos - cursor_pos) > 0.0001f)
@ -7093,7 +7095,7 @@ bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg)
return false; return false;
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true, false, false); bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, true);
// Render // Render
if (hovered || selected) if (hovered || selected)
@ -8005,7 +8007,11 @@ void ImDrawList::UpdateClipRect()
} }
else else
{ {
current_cmd->clip_rect = clip_rect_stack.empty() ? GNullClipRect : clip_rect_stack.back(); ImVec4 current_clip_rect = clip_rect_stack.empty() ? GNullClipRect : clip_rect_stack.back();
if (commands.size() > 2 && ImLengthSqr(commands[commands.size()-2].clip_rect - current_clip_rect) < 0.00001f)
commands.pop_back();
else
current_cmd->clip_rect = current_clip_rect;
} }
} }

137
imgui.h
View File

@ -36,7 +36,7 @@ struct ImGuiStorage;
struct ImGuiStyle; struct ImGuiStyle;
typedef unsigned int ImU32; typedef unsigned int ImU32;
typedef unsigned short ImWchar; // character for display typedef unsigned short ImWchar; // character for keyboard input/display
typedef void* ImTextureID; // user data to refer to a texture (e.g. store your texture handle/id) typedef void* ImTextureID; // user data to refer to a texture (e.g. store your texture handle/id)
typedef ImU32 ImGuiID; // unique ID used by widgets (typically hashed from a stack of string) typedef ImU32 ImGuiID; // unique ID used by widgets (typically hashed from a stack of string)
typedef int ImGuiCol; // enum ImGuiCol_ typedef int ImGuiCol; // enum ImGuiCol_
@ -73,79 +73,17 @@ struct ImVec4
#endif #endif
}; };
namespace ImGui
{
// Proxy functions to access the MemAllocFn/MemFreeFn pointers in ImGui::GetIO(). The only reason they exist here is to allow ImVector<> to compile inline.
IMGUI_API void* MemAlloc(size_t sz);
IMGUI_API void MemFree(void* ptr);
}
// std::vector<> like class to avoid dragging dependencies (also: windows implementation of STL with debug enabled is absurdly slow, so let's bypass it so our code runs fast in debug).
// Use '#define ImVector std::vector' if you want to use the STL type or your own type.
// Our implementation does NOT call c++ constructors! because the data types we use don't need them (but that could be added as well). Only provide the minimum functionalities we need.
#ifndef ImVector
template<typename T>
class ImVector
{
protected:
size_t Size;
size_t Capacity;
T* Data;
public:
typedef T value_type;
typedef value_type* iterator;
typedef const value_type* const_iterator;
ImVector() { Size = Capacity = 0; Data = NULL; }
~ImVector() { if (Data) ImGui::MemFree(Data); }
inline bool empty() const { return Size == 0; }
inline size_t size() const { return Size; }
inline size_t capacity() const { return Capacity; }
inline value_type& at(size_t i) { IM_ASSERT(i < Size); return Data[i]; }
inline const value_type& at(size_t i) const { IM_ASSERT(i < Size); return Data[i]; }
inline value_type& operator[](size_t i) { IM_ASSERT(i < Size); return Data[i]; }
inline const value_type& operator[](size_t i) const { IM_ASSERT(i < Size); return Data[i]; }
inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } }
inline iterator begin() { return Data; }
inline const_iterator begin() const { return Data; }
inline iterator end() { return Data + Size; }
inline const_iterator end() const { return Data + Size; }
inline value_type& front() { IM_ASSERT(Size > 0); return Data[0]; }
inline const value_type& front() const { IM_ASSERT(Size > 0); return Data[0]; }
inline value_type& back() { IM_ASSERT(Size > 0); return Data[Size-1]; }
inline const value_type& back() const { IM_ASSERT(Size > 0); return Data[Size-1]; }
inline void swap(ImVector<T>& rhs) { const size_t rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; const size_t rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; }
inline void resize(size_t new_size) { if (new_size > Capacity) reserve(new_size); Size = new_size; }
inline void reserve(size_t new_capacity)
{
if (new_capacity <= Capacity) return;
T* new_data = (value_type*)ImGui::MemAlloc(new_capacity * sizeof(value_type));
memcpy(new_data, Data, Size * sizeof(value_type));
ImGui::MemFree(Data);
Data = new_data;
Capacity = new_capacity;
}
inline void push_back(const value_type& v) { if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); Data[Size++] = v; }
inline void pop_back() { IM_ASSERT(Size > 0); Size--; }
inline iterator erase(const_iterator it) { IM_ASSERT(it >= begin() && it < end()); const ptrdiff_t off = it - begin(); memmove(Data + off, Data + off + 1, (Size - (size_t)off - 1) * sizeof(value_type)); Size--; return Data + off; }
inline iterator insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= begin() && it <= end()); const ptrdiff_t off = it - begin(); if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); if (off < (int)Size) memmove(Data + off + 1, Data + off, (Size - (size_t)off) * sizeof(value_type)); Data[off] = v; Size++; return Data + off; }
};
#endif // #ifndef ImVector
// Helpers at bottom of the file: // Helpers at bottom of the file:
// - class ImVector<> // Lightweight std::vector like class. Use '#define ImVector std::vector' if you want to use the STL type or your own type.
// - IMGUI_ONCE_UPON_A_FRAME // Execute a block of code once per frame only (convenient for creating UI within deep-nested code that runs multiple times) // - IMGUI_ONCE_UPON_A_FRAME // Execute a block of code once per frame only (convenient for creating UI within deep-nested code that runs multiple times)
// - struct ImGuiTextFilter // Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]" // - struct ImGuiTextFilter // Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
// - struct ImGuiTextBuffer // Text buffer for logging/accumulating text // - struct ImGuiTextBuffer // Text buffer for logging/accumulating text
// - struct ImGuiStorage // Custom key value storage (if you need to alter open/close states manually) // - struct ImGuiStorage // Custom key value storage (if you need to alter open/close states manually)
// - struct ImGuiTextEditCallbackData // Shared state of ImGui::InputText() when using custom callbacks
// - struct ImColor // Helper functions to created packed 32-bit RGBA color values
// - struct ImDrawList // Draw command list // - struct ImDrawList // Draw command list
// - struct ImFont // TTF font loader, bake glyphs into bitmap // - struct ImFontAtlas // Bake multiple fonts into a single texture, TTF font loader, bake glyphs into bitmap
// - struct ImFont // Single font
// ImGui end-user API // ImGui end-user API
// In a namespace so that user can add extra functions in a separate file (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)
@ -421,6 +359,10 @@ namespace ImGui
IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v); 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); IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b);
// Proxy functions to access the MemAllocFn/MemFreeFn pointers in ImGui::GetIO()
IMGUI_API void* MemAlloc(size_t sz);
IMGUI_API void MemFree(void* ptr);
// Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself // Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself
IMGUI_API const char* GetVersion(); IMGUI_API const char* GetVersion();
IMGUI_API void* GetInternalState(); IMGUI_API void* GetInternalState();
@ -725,6 +667,65 @@ struct ImGuiIO
// Helpers // Helpers
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Lightweight std::vector<> like class to avoid dragging dependencies (also: windows implementation of STL with debug enabled is absurdly slow, so let's bypass it so our code runs fast in debug).
// Use '#define ImVector std::vector' if you want to use the STL type or your own type.
// Our implementation does NOT call c++ constructors because we don't use them in ImGui. Don't use this class as a straight std::vector replacement in your code!
#ifndef ImVector
template<typename T>
class ImVector
{
protected:
size_t Size;
size_t Capacity;
T* Data;
public:
typedef T value_type;
typedef value_type* iterator;
typedef const value_type* const_iterator;
ImVector() { Size = Capacity = 0; Data = NULL; }
~ImVector() { if (Data) ImGui::MemFree(Data); }
inline bool empty() const { return Size == 0; }
inline size_t size() const { return Size; }
inline size_t capacity() const { return Capacity; }
inline value_type& at(size_t i) { IM_ASSERT(i < Size); return Data[i]; }
inline const value_type& at(size_t i) const { IM_ASSERT(i < Size); return Data[i]; }
inline value_type& operator[](size_t i) { IM_ASSERT(i < Size); return Data[i]; }
inline const value_type& operator[](size_t i) const { IM_ASSERT(i < Size); return Data[i]; }
inline void clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } }
inline iterator begin() { return Data; }
inline const_iterator begin() const { return Data; }
inline iterator end() { return Data + Size; }
inline const_iterator end() const { return Data + Size; }
inline value_type& front() { IM_ASSERT(Size > 0); return Data[0]; }
inline const value_type& front() const { IM_ASSERT(Size > 0); return Data[0]; }
inline value_type& back() { IM_ASSERT(Size > 0); return Data[Size-1]; }
inline const value_type& back() const { IM_ASSERT(Size > 0); return Data[Size-1]; }
inline void swap(ImVector<T>& rhs) { const size_t rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; const size_t rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; }
inline void resize(size_t new_size) { if (new_size > Capacity) reserve(new_size); Size = new_size; }
inline void reserve(size_t new_capacity)
{
if (new_capacity <= Capacity) return;
T* new_data = (value_type*)ImGui::MemAlloc(new_capacity * sizeof(value_type));
memcpy(new_data, Data, Size * sizeof(value_type));
ImGui::MemFree(Data);
Data = new_data;
Capacity = new_capacity;
}
inline void push_back(const value_type& v) { if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); Data[Size++] = v; }
inline void pop_back() { IM_ASSERT(Size > 0); Size--; }
inline iterator erase(const_iterator it) { IM_ASSERT(it >= begin() && it < end()); const ptrdiff_t off = it - begin(); memmove(Data + off, Data + off + 1, (Size - (size_t)off - 1) * sizeof(value_type)); Size--; return Data + off; }
inline iterator insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= begin() && it <= end()); const ptrdiff_t off = it - begin(); if (Size == Capacity) reserve(Capacity ? Capacity * 2 : 4); if (off < (int)Size) memmove(Data + off + 1, Data + off, (Size - (size_t)off) * sizeof(value_type)); Data[off] = v; Size++; return Data + off; }
};
#endif // #ifndef ImVector
// Helper: execute a block of code once a frame only // Helper: execute a block of code once a frame only
// Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame. // Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame.
// Usage: // Usage: