From 810fcd8bcb8cf8e24df80a633337fc25781d1fc8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 21 Mar 2015 13:59:19 +0000 Subject: [PATCH 01/42] Added mouse cursor types handling + embed mouse cursor data #155 --- imgui.cpp | 309 ++++++++++++++++++++++++++++++++++++++++++++---------- imgui.h | 19 +++- 2 files changed, 273 insertions(+), 55 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e90dc2e9..1db689e8 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -484,17 +484,6 @@ static const char* GetClipboardTextFn_DefaultImpl(); static void SetClipboardTextFn_DefaultImpl(const char* text); static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); -//----------------------------------------------------------------------------- -// 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 //----------------------------------------------------------------------------- @@ -1038,6 +1027,15 @@ struct ImGuiIniData ~ImGuiIniData() { if (Name) { ImGui::MemFree(Name); Name = NULL; } } }; +struct ImGuiMouseCursorData +{ + ImGuiMouseCursor Type; + ImVec2 Offset; + ImVec2 Size; + ImVec2 TexUvMin[2]; + ImVec2 TexUvMax[2]; +}; + // Main state for ImGui struct ImGuiState { @@ -1082,7 +1080,11 @@ struct ImGuiState // Render ImVector RenderDrawLists; ImVector RenderSortedWindows; - ImDrawList CursorDrawList; + + // Mouse cursor + ImGuiMouseCursor MouseCursor; + ImDrawList MouseCursorDrawList; // Optional software render of mouse cursors, if io.MouseDrawCursor is set + ImGuiMouseCursorData MouseCursorData[ImGuiMouseCursor_Count_]; // Widget state ImGuiTextEditState InputTextState; @@ -1901,6 +1903,7 @@ void ImGui::NewFrame() bool mouse_owned_by_application = mouse_earliest_button_down != -1 && !g.IO.MouseDownOwned[mouse_earliest_button_down]; g.IO.WantCaptureMouse = (!mouse_owned_by_application && g.HoveredWindow != NULL) || (g.ActiveId != 0); g.IO.WantCaptureKeyboard = (g.ActiveId != 0); + g.MouseCursor = ImGuiMouseCursor_Arrow; // If mouse was first clicked outside of ImGui bounds we also cancel out hovering. if (mouse_owned_by_application) @@ -1990,7 +1993,7 @@ void ImGui::Shutdown() g.FontStack.clear(); g.RenderDrawLists.clear(); g.RenderSortedWindows.clear(); - g.CursorDrawList.ClearFreeMemory(); + g.MouseCursorDrawList.ClearFreeMemory(); g.ColorEditModeStorage.Clear(); if (g.PrivateClipboard) { @@ -2140,18 +2143,18 @@ void ImGui::Render() if (g.IO.MouseDrawCursor) { - const ImVec2 pos = g.IO.MousePos; - const ImVec2 size = TEX_ATLAS_SIZE_MOUSE_CURSOR; + const ImGuiMouseCursorData& cursor_data = g.MouseCursorData[g.MouseCursor]; + const ImVec2 pos = g.IO.MousePos - cursor_data.Offset; + const ImVec2 size = cursor_data.Size; 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); - g.CursorDrawList.Clear(); - g.CursorDrawList.PushTextureID(tex_id); - g.CursorDrawList.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 - g.CursorDrawList.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 - g.CursorDrawList.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 - g.CursorDrawList.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.CursorDrawList.PopTextureID(); - AddDrawListToRenderList(&g.CursorDrawList); + g.MouseCursorDrawList.Clear(); + g.MouseCursorDrawList.PushTextureID(tex_id); + g.MouseCursorDrawList.AddImage(tex_id, pos+ImVec2(1,0), pos+ImVec2(1,0) + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], 0x30000000); // Shadow + g.MouseCursorDrawList.AddImage(tex_id, pos+ImVec2(2,0), pos+ImVec2(2,0) + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], 0x30000000); // Shadow + g.MouseCursorDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], 0xFF000000); // Black border + g.MouseCursorDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0xFFFFFFFF); // White fill + g.MouseCursorDrawList.PopTextureID(); + AddDrawListToRenderList(&g.MouseCursorDrawList); } // Render @@ -2580,6 +2583,16 @@ ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold) return ImVec2(0.0f, 0.0f); } +ImGuiMouseCursor ImGui::GetMouseCursor() +{ + return GImGui->MouseCursor; +} + +void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) +{ + GImGui->MouseCursor = cursor_type; +} + bool ImGui::IsItemHovered() { ImGuiWindow* window = GetCurrentWindow(); @@ -3065,12 +3078,15 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg else if (!(window->Flags & ImGuiWindowFlags_NoResize)) { // Manual resize grip - const ImRect resize_rect(window->Rect().GetBR()-ImVec2(18,18), window->Rect().GetBR()); + const ImRect resize_rect(window->Rect().GetBR()-ImVec2(14,14), window->Rect().GetBR()); const ImGuiID resize_id = window->GetID("#RESIZE"); bool hovered, held; ButtonBehavior(resize_rect, resize_id, &hovered, &held, true); resize_col = window->Color(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); + if (hovered || held) + g.MouseCursor = ImGuiMouseCursor_ResizeNWSE; + if (g.HoveredWindow == window && held && g.IO.MouseDoubleClicked[0]) { // Manual auto-fit when double-clicking @@ -5858,7 +5874,10 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT const bool hovered = IsHovered(frame_bb, id); if (hovered) + { g.HoveredId = id; + g.MouseCursor = ImGuiMouseCursor_TextInput; + } const bool user_clicked = hovered && io.MouseClicked[0]; bool select_all = (g.ActiveId != id) && (flags & ImGuiInputTextFlags_AutoSelectAll) != 0; @@ -5948,7 +5967,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT edit_state.CursorAnimReset(); } if (edit_state.SelectedAllMouseLock && !io.MouseDown[0]) - edit_state.SelectedAllMouseLock = false; + edit_state.SelectedAllMouseLock = false; if (g.IO.InputCharacters[0]) { @@ -7644,7 +7663,7 @@ ImFontAtlas::ImFontAtlas() TexPixelsAlpha8 = NULL; TexPixelsRGBA32 = NULL; TexWidth = TexHeight = 0; - TexExtraDataPos = TexUvWhitePixel = ImVec2(0, 0); + TexUvWhitePixel = ImVec2(0, 0); } ImFontAtlas::~ImFontAtlas() @@ -7802,7 +7821,7 @@ bool ImFontAtlas::Build() TexID = NULL; TexWidth = TexHeight = 0; - TexExtraDataPos = TexUvWhitePixel = ImVec2(0, 0); + TexUvWhitePixel = ImVec2(0, 0); ClearTexData(); // Initialize font information early (so we can error without any cleanup) + count glyphs @@ -7835,12 +7854,14 @@ bool ImFontAtlas::Build() IM_ASSERT(ret); stbtt_PackSetOversampling(&spc, 1, 1); - // 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; - extra_rect.w = (stbrp_coord)TEX_ATLAS_SIZE.x; - extra_rect.h = (stbrp_coord)TEX_ATLAS_SIZE.y; - stbrp_pack_rects((stbrp_context*)spc.pack_info, &extra_rect, 1); - TexExtraDataPos = ImVec2(extra_rect.x, extra_rect.y); + // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values). + ImVector extra_rects; + RenderCustomTexData(0, &extra_rects); + stbrp_pack_rects((stbrp_context*)spc.pack_info, &extra_rects[0], (int)extra_rects.size()); + int tex_height = 0; + for (size_t i = 0; i < extra_rects.size(); i++) + if (extra_rects[i].was_packed) + tex_height = ImMax(tex_height, extra_rects[i].y + extra_rects[i].h); // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0) int buf_packedchars_n = 0, buf_rects_n = 0, buf_ranges_n = 0; @@ -7848,11 +7869,10 @@ bool ImFontAtlas::Build() 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)); 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_rects, 0, total_glyph_count * sizeof(stbrp_rect)); // Unnecessary but let's clear this for the sake of sanity. 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) - int tex_height = extra_rect.y + extra_rect.h; + // First font pass: pack all glyphs (no rendering at this point, we are working with glyph sizes only) for (size_t input_i = 0; input_i < InputData.size(); input_i++) { ImFontAtlasData& data = *InputData[input_i]; @@ -7964,22 +7984,67 @@ bool ImFontAtlas::Build() ClearInputData(); // Render into our custom data block - RenderCustomTexData(); + RenderCustomTexData(1, &extra_rects); return true; } -void ImFontAtlas::RenderCustomTexData() +static void AddMouseCursor(int pass, ImVector& rects, int& rect_i, ImGuiMouseCursor type, const ImVec2& offset, const ImVec2& size, const char* in_char_pixels, unsigned char* tex_pixels, const ImVec2& tex_uv_scale, int tex_pitch) { - IM_ASSERT(TexExtraDataPos.x == 0.0f && TexExtraDataPos.y == 0.0f); + if (pass == 0) + { + stbrp_rect r; + r.w = (unsigned short)((size.x*2)+1); + r.h = (unsigned short)(size.y); + rects.push_back(r); + } + else if (pass == 1) + { + ImGuiMouseCursorData& cursor_data = GImGui->MouseCursorData[type]; + cursor_data.Type = type; + cursor_data.Size = size; + cursor_data.Offset = offset; + const stbrp_rect& r = rects[rect_i++]; + ImVec2 pos((float)r.x, (float)r.y); + for (int layer = 0; layer < 2; layer++) + { + // Draw a mouse cursor into texture + // Because our font uses a single color channel, we have to spread the cursor in 2 layers (black/white) which will be rendered separately. + const char layer_char = layer ? '.' : 'X'; + cursor_data.TexUvMin[layer] = (pos) * tex_uv_scale; + cursor_data.TexUvMax[layer] = (pos + size) * tex_uv_scale; + for (int y = 0, n = 0; y < (int)size.y; y++) + for (int x = 0; x < (int)size.x; x++, n++) + tex_pixels[((int)pos.x + x) + ((int)pos.y + y) * tex_pitch] = (in_char_pixels[n] == layer_char) ? 0xFF : 0x00; + pos.x += size.x + 1; + } + } +} + +void ImFontAtlas::RenderCustomTexData(int pass, void* rects_opaque) +{ + ImVector& rects = *(ImVector*)rects_opaque; + int rect_i = 0; // Draw white pixel into texture and make UV points to it - TexPixelsAlpha8[0] = TexPixelsAlpha8[1] = TexPixelsAlpha8[TexWidth+0] = TexPixelsAlpha8[TexWidth+1] = 0xFF; - TexUvWhitePixel = ImVec2((TexExtraDataPos.x + 0.5f) / TexWidth, (TexExtraDataPos.y + 0.5f) / TexHeight); + const ImVec2 uv_scale(1.0f / TexWidth, 1.0f / TexHeight); + if (pass == 0) + { + // Measure + stbrp_rect r; + r.w = r.h = 3; + rects.push_back(r); + } + else if (pass == 1) + { + // Render + const stbrp_rect& r = rects[rect_i++]; + const int offset = (int)r.x + (int)r.y * TexWidth; + TexPixelsAlpha8[offset] = TexPixelsAlpha8[offset+1] = TexPixelsAlpha8[TexWidth] = TexPixelsAlpha8[TexWidth+1] = 0xFF; + TexUvWhitePixel = ImVec2(r.x + 0.5f, r.y + 0.5f) * uv_scale; + } - // Draw a mouse cursor into texture - // Because our font uses a single color channel, we have to spread the cursor in 2 layers (black/white) which will be rendered separately. - const char cursor_pixels[] = + const char cursor_arrow[12*19+1] = { "X " "XX " @@ -8001,13 +8066,136 @@ void ImFontAtlas::RenderCustomTexData() " 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; - } + const char cursor_text_input[7*16+1] = + { + "XXXXXXX" + "X.....X" + "XXX.XXX" + " X.X " + " X.X " + " X.X " + " X.X " + " X.X " + " X.X " + " X.X " + " X.X " + " X.X " + " X.X " + "XXX.XXX" + "X.....X" + "XXXXXXX" + }; + const char cursor_move[23*23+1] = + { + " X " + " X.X " + " X...X " + " X.....X " + " X.......X " + " XXXX.XXXX " + " X.X " + " XX X.X XX " + " X.X X.X X.X " + " X..X X.X X..X " + " X...XXXXXX.XXXXXX...X " + "X.....................X" + " X...XXXXXX.XXXXXX...X " + " X..X X.X X..X " + " X.X X.X X.X " + " XX X.X XX " + " X.X " + " XXXX.XXXX " + " X.......X " + " X.....X " + " X...X " + " X.X " + " X " + }; + const char cursor_resize_ns[9*23+1] = + { + " X " + " X.X " + " X...X " + " X.....X " + "X.......X" + "XXXX.XXXX" + " X.X " + " X.X " + " X.X " + " X.X " + " X.X " + " X.X " + " X.X " + " X.X " + " X.X " + " X.X " + " X.X " + "XXXX.XXXX" + "X.......X" + " X.....X " + " X...X " + " X.X " + " X " + }; + const char cursor_resize_ew[23*9+1] = + { + " XX XX " + " X.X X.X " + " X..X X..X " + " X...XXXXXXXXXXXXX...X " + "X.....................X" + " X...XXXXXXXXXXXXX...X " + " X..X X..X " + " X.X X.X " + " XX XX " + }; + const char cursor_resize_nwse[17*17+1] = + { + "XXXXXXX " + "X.....X " + "X....X " + "X...X " + "X..X.X " + "X.X X.X " + "XX X.X " + " X.X " + " X.X " + " X.X " + " X.X XX" + " X.X X.X" + " X.X..X" + " X...X" + " X....X" + " X.....X" + " XXXXXXX" + }; + const char cursor_resize_nesw[17*17+1] = + { + " XXXXXXX" + " X.....X" + " X....X" + " X...X" + " X.X..X" + " X.X X.X" + " X.X XX" + " X.X " + " X.X " + " X.X " + "XX X.X " + "X.X X.X " + "X..X.X " + "X...X " + "X....X " + "X.....X " + "XXXXXXX " + }; + AddMouseCursor(pass, rects, rect_i, ImGuiMouseCursor_Arrow, ImVec2(0,0), ImVec2(12,19), cursor_arrow, TexPixelsAlpha8, uv_scale, TexWidth); + AddMouseCursor(pass, rects, rect_i, ImGuiMouseCursor_TextInput, ImVec2(4,9), ImVec2(7,16), cursor_text_input, TexPixelsAlpha8, uv_scale, TexWidth); + AddMouseCursor(pass, rects, rect_i, ImGuiMouseCursor_Move, ImVec2(11,11), ImVec2(23,23), cursor_move, TexPixelsAlpha8, uv_scale, TexWidth); + AddMouseCursor(pass, rects, rect_i, ImGuiMouseCursor_ResizeNS, ImVec2(5,11), ImVec2(9,23), cursor_resize_ns, TexPixelsAlpha8, uv_scale, TexWidth); + AddMouseCursor(pass, rects, rect_i, ImGuiMouseCursor_ResizeEW, ImVec2(11,5), ImVec2(23,9), cursor_resize_ew, TexPixelsAlpha8, uv_scale, TexWidth); + AddMouseCursor(pass, rects, rect_i, ImGuiMouseCursor_ResizeNESW,ImVec2(9,9), ImVec2(17,17), cursor_resize_nesw, TexPixelsAlpha8, uv_scale, TexWidth); + AddMouseCursor(pass, rects, rect_i, ImGuiMouseCursor_ResizeNWSE,ImVec2(9,9), ImVec2(17,17), cursor_resize_nwse, TexPixelsAlpha8, uv_scale, TexWidth); } //----------------------------------------------------------------------------- @@ -9862,7 +10050,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::BulletText("%s", lines[i]); } - if (ImGui::CollapsingHeader("Keyboard & Focus")) + if (ImGui::CollapsingHeader("Keyboard, Mouse & Focus")) { if (ImGui::TreeNode("Tabbing")) { @@ -9907,6 +10095,21 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::TextWrapped("Cursor & selection are preserved when refocusing last used item in code."); ImGui::TreePop(); } + + if (ImGui::TreeNode("Mouse cursors")) + { + ImGui::TextWrapped("(Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. You can also set io.MouseDrawCursor to ask ImGui to render the cursor for you in software)"); + ImGui::Checkbox("io.MouseDrawCursor", &ImGui::GetIO().MouseDrawCursor); + ImGui::Text("Hover to see mouse cursors:"); + for (int i = 0; i < ImGuiMouseCursor_Count_; i++) + { + char label[32]; + sprintf(label, "Mouse cursor %d", i); + ImGui::Bullet(); ImGui::Selectable(label, false); + if (ImGui::IsItemHovered()) + ImGui::SetMouseCursor(i); + } + } } if (ImGui::CollapsingHeader("App Examples")) diff --git a/imgui.h b/imgui.h index e07ad465..dfb95d9e 100644 --- a/imgui.h +++ b/imgui.h @@ -43,6 +43,7 @@ typedef int ImGuiCol; // enum ImGuiCol_ typedef int ImGuiStyleVar; // enum ImGuiStyleVar_ typedef int ImGuiKey; // enum ImGuiKey_ typedef int ImGuiColorEditMode; // enum ImGuiColorEditMode_ +typedef int ImGuiMouseCursor; // enum ImGuiMouseCursor_ typedef int ImGuiWindowFlags; // enum ImGuiWindowFlags_ typedef int ImGuiSetCond; // enum ImGuiSetCondition_ typedef int ImGuiInputTextFlags; // enum ImGuiInputTextFlags_ @@ -372,6 +373,8 @@ namespace ImGui IMGUI_API bool IsPosHoveringAnyWindow(const ImVec2& pos); // is given position hovering any active imgui window IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls IMGUI_API ImVec2 GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f); // dragging amount, also see: GetItemActiveDragDelta(). if lock_threshold < -1.0f uses io.MouseDraggingThreshold. + IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you. + IMGUI_API void SetMouseCursor(ImGuiMouseCursor type); // set desired cursor type IMGUI_API float GetTime(); IMGUI_API int GetFrameCount(); IMGUI_API const char* GetStyleColName(ImGuiCol idx); @@ -533,6 +536,19 @@ enum ImGuiColorEditMode_ ImGuiColorEditMode_HEX = 2 }; +// Enumeration for io.MouseCursor +enum ImGuiMouseCursor_ +{ + ImGuiMouseCursor_Arrow = 0, + ImGuiMouseCursor_TextInput, + ImGuiMouseCursor_Move, // Unused by ImGui + ImGuiMouseCursor_ResizeNS, // Unused by ImGui + ImGuiMouseCursor_ResizeEW, // Unused by ImGui + ImGuiMouseCursor_ResizeNESW, // Unused by ImGui + ImGuiMouseCursor_ResizeNWSE, + ImGuiMouseCursor_Count_ +}; + // Condition flags for ImGui::SetWindow***(), SetNextWindow***(), SetNextTreeNode***() functions // All those functions treat 0 as a shortcut to ImGuiSetCond_Always enum ImGuiSetCond_ @@ -936,7 +952,6 @@ struct ImFontAtlas unsigned int* TexPixelsRGBA32; // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4 int TexWidth; int TexHeight; - ImVec2 TexExtraDataPos; // Position of our rectangle where we draw non-font graphics ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel (part of the TexExtraData block) ImVector Fonts; @@ -945,7 +960,7 @@ struct ImFontAtlas ImVector InputData; // Internal data 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 RenderCustomTexData(); + IMGUI_API void RenderCustomTexData(int pass, void* rects); }; // TTF font loading and rendering From 9363e6c154d2472af76659c23b813beaa26a054b Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 21 Mar 2015 15:09:01 +0000 Subject: [PATCH 02/42] Prepacking mouse cursors to save on source code size, generally simpler #155 --- imgui.cpp | 286 ++++++++++++++++-------------------------------------- 1 file changed, 82 insertions(+), 204 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1db689e8..d7b4359d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2149,10 +2149,10 @@ void ImGui::Render() const ImTextureID tex_id = g.IO.Fonts->TexID; g.MouseCursorDrawList.Clear(); g.MouseCursorDrawList.PushTextureID(tex_id); - g.MouseCursorDrawList.AddImage(tex_id, pos+ImVec2(1,0), pos+ImVec2(1,0) + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], 0x30000000); // Shadow - g.MouseCursorDrawList.AddImage(tex_id, pos+ImVec2(2,0), pos+ImVec2(2,0) + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], 0x30000000); // Shadow - g.MouseCursorDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], 0xFF000000); // Black border - g.MouseCursorDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0xFFFFFFFF); // White fill + g.MouseCursorDrawList.AddImage(tex_id, pos+ImVec2(1,0), pos+ImVec2(1,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0x30000000); // Shadow + g.MouseCursorDrawList.AddImage(tex_id, pos+ImVec2(2,0), pos+ImVec2(2,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0x30000000); // Shadow + g.MouseCursorDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0xFF000000); // Black border + g.MouseCursorDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], 0xFFFFFFFF); // White fill g.MouseCursorDrawList.PopTextureID(); AddDrawListToRenderList(&g.MouseCursorDrawList); } @@ -7858,10 +7858,9 @@ bool ImFontAtlas::Build() ImVector extra_rects; RenderCustomTexData(0, &extra_rects); stbrp_pack_rects((stbrp_context*)spc.pack_info, &extra_rects[0], (int)extra_rects.size()); - int tex_height = 0; for (size_t i = 0; i < extra_rects.size(); i++) if (extra_rects[i].was_packed) - tex_height = ImMax(tex_height, extra_rects[i].y + extra_rects[i].h); + TexHeight = ImMax(TexHeight, extra_rects[i].y + extra_rects[i].h); // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0) int buf_packedchars_n = 0, buf_rects_n = 0, buf_ranges_n = 0; @@ -7908,14 +7907,14 @@ bool ImFontAtlas::Build() // Extend texture height for (int i = 0; i < n; i++) if (data.Rects[i].was_packed) - tex_height = ImMax(tex_height, data.Rects[i].y + data.Rects[i].h); + TexHeight = ImMax(TexHeight, data.Rects[i].y + data.Rects[i].h); } IM_ASSERT(buf_rects_n == total_glyph_count); IM_ASSERT(buf_packedchars_n == total_glyph_count); IM_ASSERT(buf_ranges_n == total_glyph_range_count); // Create texture - TexHeight = ImUpperPowerOfTwo(tex_height); + TexHeight = ImUpperPowerOfTwo(TexHeight); TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(TexWidth * TexHeight); memset(TexPixelsAlpha8, 0, TexWidth * TexHeight); spc.pixels = TexPixelsAlpha8; @@ -7989,215 +7988,94 @@ bool ImFontAtlas::Build() return true; } -static void AddMouseCursor(int pass, ImVector& rects, int& rect_i, ImGuiMouseCursor type, const ImVec2& offset, const ImVec2& size, const char* in_char_pixels, unsigned char* tex_pixels, const ImVec2& tex_uv_scale, int tex_pitch) +void ImFontAtlas::RenderCustomTexData(int pass, void* p_rects) { + // . = white layer, X = black layer, others are blank + const int TEX_DATA_W = 90; + const int TEX_DATA_H = 27; + const char texture_data[TEX_DATA_W*TEX_DATA_H+1] = + { + "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX" + "..- -X.....X- X.X - X.X -X.....X - X.....X" + "--- -XXX.XXX- X...X - X...X -X....X - X....X" + "X - X.X - X.....X - X.....X -X...X - X...X" + "XX - X.X -X.......X- X.......X -X..X.X - X.X..X" + "X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X" + "X..X - X.X - X.X - X.X -XX X.X - X.X XX" + "X...X - X.X - X.X - XX X.X XX - X.X - X.X " + "X....X - X.X - X.X - X.X X.X X.X - X.X - X.X " + "X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X " + "X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X " + "X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X " + "X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X " + "X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X " + "X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X " + "X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X " + "X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX " + "X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------" + "X.X X..X - -X.......X- X.......X - XX XX - " + "XX X..X - - X.....X - X.....X - X.X X.X - " + " X..X - X...X - X...X - X..X X..X - " + " XX - X.X - X.X - X...XXXXXXXXXXXXX...X - " + "------------ - X - X -X.....................X- " + " ----------------------------------- X...XXXXXXXXXXXXX...X - " + " - X..X X..X - " + " - X.X X.X - " + " - XX XX - " + }; + + ImVector& rects = *(ImVector*)p_rects; if (pass == 0) { stbrp_rect r; - r.w = (unsigned short)((size.x*2)+1); - r.h = (unsigned short)(size.y); + r.w = (TEX_DATA_W*2)+1; + r.h = TEX_DATA_H+1; rects.push_back(r); } else if (pass == 1) { - ImGuiMouseCursorData& cursor_data = GImGui->MouseCursorData[type]; - cursor_data.Type = type; - cursor_data.Size = size; - cursor_data.Offset = offset; - const stbrp_rect& r = rects[rect_i++]; - ImVec2 pos((float)r.x, (float)r.y); - for (int layer = 0; layer < 2; layer++) + // Copy pixels + const stbrp_rect& r = rects[0]; + for (int y = 0, n = 0; y < TEX_DATA_H; y++) + for (int x = 0; x < TEX_DATA_W; x++, n++) + { + const int offset0 = (int)(r.x + x) + (int)(r.y + y) * TexWidth; + const int offset1 = offset0 + 1 + TEX_DATA_W; + TexPixelsAlpha8[offset0] = texture_data[n] == '.' ? 0xFF : 0x00; + TexPixelsAlpha8[offset1] = texture_data[n] == 'X' ? 0xFF : 0x00; + } + const ImVec2 tex_uv_scale(1.0f / TexWidth, 1.0f / TexHeight); + TexUvWhitePixel = ImVec2(r.x + 0.5f, r.y + 0.5f) * tex_uv_scale; + + const ImVec2 cursor_datas[ImGuiMouseCursor_Count_][3] = { - // Draw a mouse cursor into texture - // Because our font uses a single color channel, we have to spread the cursor in 2 layers (black/white) which will be rendered separately. - const char layer_char = layer ? '.' : 'X'; - cursor_data.TexUvMin[layer] = (pos) * tex_uv_scale; - cursor_data.TexUvMax[layer] = (pos + size) * tex_uv_scale; - for (int y = 0, n = 0; y < (int)size.y; y++) - for (int x = 0; x < (int)size.x; x++, n++) - tex_pixels[((int)pos.x + x) + ((int)pos.y + y) * tex_pitch] = (in_char_pixels[n] == layer_char) ? 0xFF : 0x00; - pos.x += size.x + 1; + // Pos ........ Size ......... Offset ...... + { ImVec2(0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow + { ImVec2(13,0), ImVec2(7,16), ImVec2( 4, 9) }, // ImGuiMouseCursor_TextInput + { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_Move + { ImVec2(21,0), ImVec2( 9,23), ImVec2( 5,11) }, // ImGuiMouseCursor_ResizeNS + { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 5) }, // ImGuiMouseCursor_ResizeEW + { ImVec2(73,0), ImVec2(17,17), ImVec2( 9, 9) }, // ImGuiMouseCursor_ResizeNESW + { ImVec2(55,0), ImVec2(17,17), ImVec2( 9, 9) }, // ImGuiMouseCursor_ResizeNWSE + }; + + for (int type = 0; type < ImGuiMouseCursor_Count_; type++) + { + ImGuiMouseCursorData& cursor_data = GImGui->MouseCursorData[type]; + ImVec2 pos = cursor_datas[type][0] + ImVec2((float)r.x, (float)r.y); + const ImVec2 size = cursor_datas[type][1]; + cursor_data.Type = type; + cursor_data.Size = size; + cursor_data.Offset = cursor_datas[type][2]; + cursor_data.TexUvMin[0] = (pos) * tex_uv_scale; + cursor_data.TexUvMax[0] = (pos + size) * tex_uv_scale; + pos.x += TEX_DATA_W+1; + cursor_data.TexUvMin[1] = (pos) * tex_uv_scale; + cursor_data.TexUvMax[1] = (pos + size) * tex_uv_scale; } } } -void ImFontAtlas::RenderCustomTexData(int pass, void* rects_opaque) -{ - ImVector& rects = *(ImVector*)rects_opaque; - int rect_i = 0; - - // Draw white pixel into texture and make UV points to it - const ImVec2 uv_scale(1.0f / TexWidth, 1.0f / TexHeight); - if (pass == 0) - { - // Measure - stbrp_rect r; - r.w = r.h = 3; - rects.push_back(r); - } - else if (pass == 1) - { - // Render - const stbrp_rect& r = rects[rect_i++]; - const int offset = (int)r.x + (int)r.y * TexWidth; - TexPixelsAlpha8[offset] = TexPixelsAlpha8[offset+1] = TexPixelsAlpha8[TexWidth] = TexPixelsAlpha8[TexWidth+1] = 0xFF; - TexUvWhitePixel = ImVec2(r.x + 0.5f, r.y + 0.5f) * uv_scale; - } - - const char cursor_arrow[12*19+1] = - { - "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 " - }; - const char cursor_text_input[7*16+1] = - { - "XXXXXXX" - "X.....X" - "XXX.XXX" - " X.X " - " X.X " - " X.X " - " X.X " - " X.X " - " X.X " - " X.X " - " X.X " - " X.X " - " X.X " - "XXX.XXX" - "X.....X" - "XXXXXXX" - }; - const char cursor_move[23*23+1] = - { - " X " - " X.X " - " X...X " - " X.....X " - " X.......X " - " XXXX.XXXX " - " X.X " - " XX X.X XX " - " X.X X.X X.X " - " X..X X.X X..X " - " X...XXXXXX.XXXXXX...X " - "X.....................X" - " X...XXXXXX.XXXXXX...X " - " X..X X.X X..X " - " X.X X.X X.X " - " XX X.X XX " - " X.X " - " XXXX.XXXX " - " X.......X " - " X.....X " - " X...X " - " X.X " - " X " - }; - const char cursor_resize_ns[9*23+1] = - { - " X " - " X.X " - " X...X " - " X.....X " - "X.......X" - "XXXX.XXXX" - " X.X " - " X.X " - " X.X " - " X.X " - " X.X " - " X.X " - " X.X " - " X.X " - " X.X " - " X.X " - " X.X " - "XXXX.XXXX" - "X.......X" - " X.....X " - " X...X " - " X.X " - " X " - }; - const char cursor_resize_ew[23*9+1] = - { - " XX XX " - " X.X X.X " - " X..X X..X " - " X...XXXXXXXXXXXXX...X " - "X.....................X" - " X...XXXXXXXXXXXXX...X " - " X..X X..X " - " X.X X.X " - " XX XX " - }; - const char cursor_resize_nwse[17*17+1] = - { - "XXXXXXX " - "X.....X " - "X....X " - "X...X " - "X..X.X " - "X.X X.X " - "XX X.X " - " X.X " - " X.X " - " X.X " - " X.X XX" - " X.X X.X" - " X.X..X" - " X...X" - " X....X" - " X.....X" - " XXXXXXX" - }; - const char cursor_resize_nesw[17*17+1] = - { - " XXXXXXX" - " X.....X" - " X....X" - " X...X" - " X.X..X" - " X.X X.X" - " X.X XX" - " X.X " - " X.X " - " X.X " - "XX X.X " - "X.X X.X " - "X..X.X " - "X...X " - "X....X " - "X.....X " - "XXXXXXX " - }; - AddMouseCursor(pass, rects, rect_i, ImGuiMouseCursor_Arrow, ImVec2(0,0), ImVec2(12,19), cursor_arrow, TexPixelsAlpha8, uv_scale, TexWidth); - AddMouseCursor(pass, rects, rect_i, ImGuiMouseCursor_TextInput, ImVec2(4,9), ImVec2(7,16), cursor_text_input, TexPixelsAlpha8, uv_scale, TexWidth); - AddMouseCursor(pass, rects, rect_i, ImGuiMouseCursor_Move, ImVec2(11,11), ImVec2(23,23), cursor_move, TexPixelsAlpha8, uv_scale, TexWidth); - AddMouseCursor(pass, rects, rect_i, ImGuiMouseCursor_ResizeNS, ImVec2(5,11), ImVec2(9,23), cursor_resize_ns, TexPixelsAlpha8, uv_scale, TexWidth); - AddMouseCursor(pass, rects, rect_i, ImGuiMouseCursor_ResizeEW, ImVec2(11,5), ImVec2(23,9), cursor_resize_ew, TexPixelsAlpha8, uv_scale, TexWidth); - AddMouseCursor(pass, rects, rect_i, ImGuiMouseCursor_ResizeNESW,ImVec2(9,9), ImVec2(17,17), cursor_resize_nesw, TexPixelsAlpha8, uv_scale, TexWidth); - AddMouseCursor(pass, rects, rect_i, ImGuiMouseCursor_ResizeNWSE,ImVec2(9,9), ImVec2(17,17), cursor_resize_nwse, TexPixelsAlpha8, uv_scale, TexWidth); -} - //----------------------------------------------------------------------------- // ImFont //----------------------------------------------------------------------------- From dee2790133978470325f065f1dae7b2ac1c7cd69 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 21 Mar 2015 15:12:47 +0000 Subject: [PATCH 03/42] Mouse cursor offset tweak #155 --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index d7b4359d..3531ae70 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8051,7 +8051,7 @@ void ImFontAtlas::RenderCustomTexData(int pass, void* p_rects) { // Pos ........ Size ......... Offset ...... { ImVec2(0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow - { ImVec2(13,0), ImVec2(7,16), ImVec2( 4, 9) }, // ImGuiMouseCursor_TextInput + { ImVec2(13,0), ImVec2(7,16), ImVec2( 4, 8) }, // ImGuiMouseCursor_TextInput { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_Move { ImVec2(21,0), ImVec2( 9,23), ImVec2( 5,11) }, // ImGuiMouseCursor_ResizeNS { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 5) }, // ImGuiMouseCursor_ResizeEW From b024ff85f7645fb1977f60378aaaab520c5b413d Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 21 Mar 2015 15:15:16 +0000 Subject: [PATCH 04/42] Fixed comment --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index dfb95d9e..ffbf7fb7 100644 --- a/imgui.h +++ b/imgui.h @@ -536,7 +536,7 @@ enum ImGuiColorEditMode_ ImGuiColorEditMode_HEX = 2 }; -// Enumeration for io.MouseCursor +// Enumeration for GetMouseCursor() enum ImGuiMouseCursor_ { ImGuiMouseCursor_Arrow = 0, From 7c8946b9b78f2a7ab94df1add18a26b244ac4ca8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 21 Mar 2015 17:48:03 +0000 Subject: [PATCH 05/42] Hovering a column set the resize <> mouse cursor #155 --- imgui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 3531ae70..07115c54 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7111,6 +7111,8 @@ void ImGui::Columns(int columns_count, const char* id, bool border) bool hovered, held; ButtonBehavior(column_rect, column_id, &hovered, &held, true); + if (hovered || held) + g.MouseCursor = ImGuiMouseCursor_ResizeEW; // Draw before resize so our items positioning are in sync with the line being drawn const ImU32 col = window->Color(held ? ImGuiCol_ColumnActive : hovered ? ImGuiCol_ColumnHovered : ImGuiCol_Column); From 85f432dc8dcc027e968cbb2daf501113a34ccc17 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 21 Mar 2015 19:27:29 +0000 Subject: [PATCH 06/42] Commented standard library include with the functions we use. Using ImFormatString in place of sprintf (part of #172) --- imgui.cpp | 12 ++++++------ imgui.h | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 07115c54..12e25ca4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -339,10 +339,10 @@ #endif #include "imgui.h" -#include // toupper -#include // sqrtf +#include // toupper, isprint +#include // sqrtf, fabsf, fmodf, powf, cosf, sinf, floorf, ceilf #include // intptr_t -#include // vsnprintf +#include // vsnprintf, sscanf #include // new (ptr) #ifdef _MSC_VER @@ -6710,9 +6710,9 @@ bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha) const float w_slider_all = w_full - square_sz; char buf[64]; if (alpha) - sprintf(buf, "#%02X%02X%02X%02X", ix, iy, iz, iw); + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ix, iy, iz, iw); else - sprintf(buf, "#%02X%02X%02X", ix, iy, iz); + ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ix, iy, iz); ImGui::PushItemWidth(w_slider_all - style.ItemInnerSpacing.x); value_changed |= ImGui::InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal); ImGui::PopItemWidth(); @@ -7224,7 +7224,7 @@ void ImGui::Value(const char* prefix, float v, const char* float_format) if (float_format) { char fmt[64]; - sprintf(fmt, "%%s: %s", float_format); + ImFormatString(fmt, IM_ARRAYSIZE(fmt), "%%s: %s", float_format); ImGui::Text(fmt, prefix, v); } else diff --git a/imgui.h b/imgui.h index ffbf7fb7..4b4ea533 100644 --- a/imgui.h +++ b/imgui.h @@ -9,9 +9,9 @@ #include "imconfig.h" // User-editable configuration file #include // FLT_MAX #include // va_list -#include // ptrdiff_t -#include // NULL, malloc -#include // memset, memmove +#include // ptrdiff_t, NULL +#include // NULL, malloc, free, qsort, atoi +#include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp #define IMGUI_VERSION "1.37 WIP" From 072c57b0ca6523df27366c010c37934d7a0eede5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 21 Mar 2015 19:30:46 +0000 Subject: [PATCH 07/42] Setting io.LogFilename to NULL disable default LogToFile() (part of #175) --- imgui.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 12e25ca4..a97d0771 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4394,7 +4394,11 @@ void ImGui::LogToFile(int max_depth, const char* filename) if (g.LogEnabled) return; if (!filename) + { filename = g.IO.LogFilename; + if (!filename) + return; + } g.LogFile = fopen(filename, "ab"); if (!g.LogFile) From 99314dad734c618427622fc745086f7611c1106f Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 21 Mar 2015 23:14:21 +0000 Subject: [PATCH 08/42] Updated FAQ --- imgui.cpp | 103 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 74 insertions(+), 29 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a97d0771..28ddb91d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11,7 +11,12 @@ - END-USER GUIDE - PROGRAMMER GUIDE (read me!) - API BREAKING CHANGES (read me when you update!) - - FREQUENTLY ASKED QUESTIONS (FAQ) & TROUBLESHOOTING (read me!) + - FREQUENTLY ASKED QUESTIONS (FAQ), TIPS + - Can I have multiple widgets with the same label? (Yes) + - Why is my text output blurry? + - How can I load a different font than the default? + - How can I load multiple fonts? + - How can I display and input Chinese, Japanese, Korean characters? - ISSUES & TODO-LIST - CODE - SAMPLE CODE @@ -172,24 +177,29 @@ - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes - FREQUENTLY ASKED QUESTIONS (FAQ) & TROUBLESHOOTING - ================================================== + FREQUENTLY ASKED QUESTIONS (FAQ), TIPS + ====================================== - If text or lines are blurry when integrating ImGui in your engine: - - - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) - - A primer on the meaning and use of IDs in ImGui: + Q: Can I have multiple widgets with the same label? + A: Yes. A primer on the use of labels/IDs in ImGui.. - - 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. Button("OK"); // Label = "OK", ID = hash of "OK" Button("Cancel"); // Label = "Cancel", ID = hash of "Cancel" - - element that are not interactive, such as Text() items don't need an ID. + - Elements that are not clickable, such as Text() items don't need an ID. - - ID are uniquely scoped within Windows 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. + + - if you have a same ID twice in the same location, you'll have a conflict: + + Button("OK"); + Button("OK"); // ID collision! Both buttons will be treated as the same. + + Fear not! this is easy to solve and there are many ways to solve it! - when passing a label you can optionally specify extra unique ID information within string itself. This helps solving the simpler collision cases. use "##" to pass a complement to the ID that won't be visible to the end-user: @@ -197,41 +207,74 @@ Button("Play##0"); // Label = "Play", ID = hash of "Play##0" Button("Play##1"); // Label = "Play", ID = hash of "Play##1" (different from above) - use "###" to pass a label that isn't part of ID. You can use that to change labels while preserving a constant ID. + - 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: Button("Hello###ID"; // Label = "Hello", ID = hash of "ID" Button("World###ID"; // Label = "World", ID = hash of "ID" (same as above) - - use PushID() / PopID() to create scopes and avoid ID conflicts within the same Window: + - use PushID() / PopID() to create scopes and avoid ID conflicts within the same Window. + this is the most convenient way of distinguish ID if you are iterating and creating many UI elements. + you can push a pointer, a string or an integer value. remember that ID are formed from the addition of everything in the ID stack! + + for (int i = 0; i < 100; i++) + { + PushID(i); + Button("Click"); // Label = "Click", ID = hash of integer + "label" (unique) + PopID(); + } + + for (int i = 0; i < 100; i++) + { + MyObject* obj = Objects[i]; + PushID(obj); + Button("Click"); // Label = "Click", ID = hash of pointer + "label" (unique) + PopID(); + } + + for (int i = 0; i < 100; i++) + { + MyObject* obj = Objects[i]; + PushID(obj->Name); + Button("Click"); // Label = "Click", ID = hash of string + "label" (unique) + PopID(); + } + + - more example showing that you can stack multiple prefixes into the ID stack: Button("Click"); // Label = "Click", ID = hash of "Click" PushID("node"); Button("Click"); // Label = "Click", ID = hash of "node" + "Click" - for (int i = 0; i < 100; i++) - { - PushID(i); - Button("Click"); // Label = "Click", ID = hash of "node" + i + "label" - PopID(); - } + PushID(my_ptr); + Button("Click"); // Label = "Click", ID = hash of "node" + ptr + "Click" + PopID(); PopID(); - PushID(my_ptr); - Button("Click"); // Label = "Click", ID = hash of ptr + "Click" - PopID(); - - so if you have a loop creating multiple items, you can use PushID() / PopID() with the index of each item, or their pointer, etc. - some functions like TreeNode() implicitly creates a scope for you by calling PushID(). - - when working with trees, ID are used to preserve the opened/closed state of tree nodes. + - tree nodes implicitly creates a scope for you by calling PushID(). + + Button("Click"); // Label = "Click", ID = hash of "Click" + if (TreeNode("node")) + { + Button("Click"); // Label = "Click", ID = hash of "node" + "Click" + TreePop(); + } + + - when working with trees, ID are used to preserve the opened/closed state of each tree node. depending on your use cases you may want to use strings, indices or pointers as ID. e.g. when displaying a single object that may change over time (1-1 relationship), using a static string as ID will preserve your node open/closed state when the targeted object change. e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently. experiment and see what makes more sense! - If you want to load a different font than the default (ProggyClean.ttf, size 13) + Q: Why is my text output blurry? + A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) + + Q: How can I load a different font than the default? (default is an embedded version of ProggyClean.ttf, rendered at size 13) + A: Use the font atlas to load the TTF file you want: io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() - If you want to load multiple fonts, use the font atlas to pack them into a single texture! + Q: How can I load multiple fonts? + A: Use the font atlas to pack them into a single texture: ImFont* font0 = io.Fonts->AddFontDefault(); ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); @@ -240,7 +283,9 @@ // the first loaded font gets used by default // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime - If you want to display Chinese, Japanese, Korean characters, pass custom Unicode ranges when loading a font: + Q: How can I render and input Chinese, Japanese, Korean characters? + A: When loading a font, pass custom Unicode ranges to specify the glyphs to load. ImGui will support UTF-8 encoding across the board. + Character input depends on you passing the right character code to io.AddInputCharacter(). The example applications do that. io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, io.Fonts->GetGlyphRangesJapanese()); // Load Japanese characters io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() From dec73a8a8a17f59ba7bcb1b2bfa70febfa384e1a Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 21 Mar 2015 23:51:57 +0000 Subject: [PATCH 09/42] Update README.md - demo binaries --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index ac5ac169..63613683 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,13 @@ ImGui outputs vertex buffers and simple command-lists that you can render in you ImGui allows you create elaborate tools as well as very short-lived ones. On the extreme side of short-liveness: using the Edit&Continue feature of compilers you can add a few widgets to tweaks variables while your application is running, and remove the code a minute later! ImGui is not just for tweaking values. You can use it to trace a running algorithm by just emitting text commands. You can use it along with your own reflection data to browse your dataset live. You can use it to expose the internals of a subsystem in your engine, to create a logger, an inspection tool, a profiler, a debugger, etc. +Demo +---- + +You should be able to build the examples from sources (tested on Winodws/Mac/Linux). If you don't, let me know! If you want to have a quick look at the features of ImGui, you can download binaries of the demo app here. +- [imgui-demo-binaries-20150321.zip](http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20150321.zip) (Windows binaries, ImGui 1.37 WIP 2015/03/31, 4 executables, 391 KB) + + Gallery ------- From fde991fbbb6377b2ca72e71e571d80b6e574daea Mon Sep 17 00:00:00 2001 From: omar Date: Sat, 21 Mar 2015 23:56:23 +0000 Subject: [PATCH 10/42] Update README.md --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 63613683..4d2167bd 100644 --- a/README.md +++ b/README.md @@ -128,13 +128,10 @@ Inspiration, feedback, and testing for early versions: Casey Muratori, Atman Bin ImGui is financially supported on [**Patreon**](http://www.patreon.com/imgui). Special supporters -- Jetha Chan -- Pastagames -- Wild Sheep Studio +- Jetha Chan, Mārtiņš Možeiko, Alex Evans, Pastagames, Wild Sheep Studio And -- Dale Kim -- Michel Courtine +- Dale Kim, Michel Courtine, Paul Patrashcu, Rui Figueira And other supporters; thanks! From efd927e30095d4a38df6a13f9d1c962514f52a23 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 22 Mar 2015 00:00:49 +0000 Subject: [PATCH 11/42] ShowTestWindow: missing TreePop() call in Mouse Cursor section. --- imgui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/imgui.cpp b/imgui.cpp index 28ddb91d..46705bec 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -10038,6 +10038,7 @@ void ImGui::ShowTestWindow(bool* opened) if (ImGui::IsItemHovered()) ImGui::SetMouseCursor(i); } + ImGui::TreePop(); } } From c1766c95ed57c1deaaf4024f6a53d418420ce297 Mon Sep 17 00:00:00 2001 From: "Adam D. Moss" Date: Sun, 22 Mar 2015 13:49:36 +0000 Subject: [PATCH 12/42] OpenGL/GLFW: hide system cursor if imgui is soft-rendering cursor --- examples/opengl3_example/imgui_impl_glfw_gl3.cpp | 11 +++++++++++ examples/opengl_example/imgui_impl_glfw.cpp | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index cd43effc..53c13afe 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -351,6 +351,17 @@ void ImGui_ImplGlfwGL3_NewFrame() io.MouseWheel = g_MouseWheel; g_MouseWheel = 0.0f; + // Hide/show hardware mouse cursor + if (io.MouseDrawCursor) + { + // imgui draws cursor itself + glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + } + else + { + glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } + // Start the frame ImGui::NewFrame(); } diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index b7a4844c..9ea00a4d 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -255,6 +255,17 @@ void ImGui_ImplGlfw_NewFrame() io.MouseWheel = g_MouseWheel; g_MouseWheel = 0.0f; + // Hide/show hardware mouse cursor + if (io.MouseDrawCursor) + { + // imgui draws cursor itself + glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); + } + else + { + glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } + // Start the frame ImGui::NewFrame(); } From ed94edfd8ee0b5aab34ba6326c0e6c3ada3de281 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 22 Mar 2015 14:14:23 +0000 Subject: [PATCH 13/42] Examples: Terser code + added commented out glUseProgram(0( suggestion in OpenGL2 sample. --- examples/opengl3_example/imgui_impl_glfw_gl3.cpp | 10 +--------- examples/opengl_example/imgui_impl_glfw.cpp | 11 ++--------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index 53c13afe..1cd2faf0 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -352,15 +352,7 @@ void ImGui_ImplGlfwGL3_NewFrame() g_MouseWheel = 0.0f; // Hide/show hardware mouse cursor - if (io.MouseDrawCursor) - { - // imgui draws cursor itself - glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); - } - else - { - glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - } + glfwSetInputMode(g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL); // Start the frame ImGui::NewFrame(); diff --git a/examples/opengl_example/imgui_impl_glfw.cpp b/examples/opengl_example/imgui_impl_glfw.cpp index 9ea00a4d..8c9cb216 100644 --- a/examples/opengl_example/imgui_impl_glfw.cpp +++ b/examples/opengl_example/imgui_impl_glfw.cpp @@ -41,6 +41,7 @@ static void ImGui_ImplGlfw_RenderDrawLists(ImDrawList** const cmd_lists, int cmd glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glEnable(GL_TEXTURE_2D); + //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context // Setup orthographic projection matrix const float width = ImGui::GetIO().DisplaySize.x; @@ -256,15 +257,7 @@ void ImGui_ImplGlfw_NewFrame() g_MouseWheel = 0.0f; // Hide/show hardware mouse cursor - if (io.MouseDrawCursor) - { - // imgui draws cursor itself - glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); - } - else - { - glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - } + glfwSetInputMode(g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL); // Start the frame ImGui::NewFrame(); From 7e8f1f1062c5e61a7bca022df8a118f9fa640b62 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 22 Mar 2015 15:34:41 +0000 Subject: [PATCH 14/42] Collapsed windows run initial auto-fit to resize the title bar #175 Maybe have side-effects on window contents? Unsure at this point. --- imgui.cpp | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 46705bec..1337caab 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3081,9 +3081,29 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->Collapsed = false; } + // Calculate auto-fit size + ImVec2 size_auto_fit; + if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0) + { + // Tooltip always resize. We keep the spacing symmetric on both axises for aesthetic purpose. + size_auto_fit = window->SizeContents + style.WindowPadding - ImVec2(0.0f, style.ItemSpacing.y); + } + else + { + size_auto_fit = ImClamp(window->SizeContents + style.AutoFitPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - style.AutoFitPadding)); + } + const float window_rounding = (window->Flags & ImGuiWindowFlags_ChildWindow) ? style.ChildWindowRounding : style.WindowRounding; if (window->Collapsed) { + // We still process initial auto-fit on collapsed windows to get a window width + // But otherwise we don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed. + if (window->AutoFitFrames > 0) + { + window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; + title_bar_rect = window->TitleBarRect(); + } + // Draw title bar only window->Size = title_bar_rect.GetSize(); window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_TitleBgCollapsed), window_rounding); @@ -3098,13 +3118,10 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg ImU32 resize_col = 0; if ((window->Flags & ImGuiWindowFlags_Tooltip) != 0) { - // Tooltip always resize. We keep the spacing symmetric on both axises for aesthetic purpose. - const ImVec2 size_auto_fit = window->SizeContents + style.WindowPadding - ImVec2(0.0f, style.ItemSpacing.y); window->Size = window->SizeFull = size_auto_fit; } else { - const ImVec2 size_auto_fit = ImClamp(window->SizeContents + style.AutoFitPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - style.AutoFitPadding)); if ((window->Flags & ImGuiWindowFlags_AlwaysAutoResize) != 0) { // Don't continuously mark settings as dirty, the size of the window doesn't need to be stored. @@ -3113,10 +3130,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg else if (window->AutoFitFrames > 0) { // Auto-fit only grows during the first few frames - if (window->AutoFitOnlyGrows) - window->SizeFull = ImMax(window->SizeFull, size_auto_fit); - else - window->SizeFull = size_auto_fit; + window->SizeFull = window->AutoFitOnlyGrows ? ImMax(window->SizeFull, size_auto_fit) : size_auto_fit; if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings)) MarkSettingsDirty(); } @@ -3299,7 +3313,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->Visible = false; // Return false if we don't intend to display anything to allow user to perform an early out optimization - window->SkipItems = window->Collapsed || (!window->Visible && window->AutoFitFrames == 0); + window->SkipItems = (window->Collapsed || !window->Visible) && window->AutoFitFrames == 0; return !window->SkipItems; } From 5737a79c8dffb8c20f6b23f6f28b01318be08483 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 22 Mar 2015 15:58:44 +0000 Subject: [PATCH 15/42] Fixed new window from having an incorrect content size on their first frame (#175) --- imgui.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 1337caab..ced05423 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2898,9 +2898,13 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg IM_ASSERT(name != NULL); // Must pass a name // Find or create + bool window_is_new = false; ImGuiWindow* window = FindWindowByName(name); if (!window) + { window = CreateNewWindow(name, size, flags); + window_is_new = true; + } window->Flags = (ImGuiWindowFlags)flags; // Add to stack @@ -2967,7 +2971,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg window->ClipRectStack.resize(0); // Reset contents size for auto-fitting - window->SizeContents = window->DC.CursorMaxPos - window->Pos; + window->SizeContents = window_is_new ? ImVec2(0.0f, 0.0f) : window->DC.CursorMaxPos - window->Pos; window->SizeContents.y += window->ScrollY; if (flags & ImGuiWindowFlags_ChildWindow) From b578e86971c17c7ead521401355b9d4bf2f07048 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 22 Mar 2015 16:08:42 +0000 Subject: [PATCH 16/42] Fixed SetWindowPos/SetNextWindowPos affectiving size computation (#175) --- imgui.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ced05423..5dec4179 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2915,7 +2915,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg bool window_pos_set_by_api = false; if (g.SetNextWindowPosCond) { - const ImVec2 backup_cursor_pos = window->DC.CursorPos; + const ImVec2 backup_cursor_pos = window->DC.CursorPos; // FIXME: not sure of the exact reason of this anymore :( need to look into that. ImGui::SetWindowPos(g.SetNextWindowPosVal, g.SetNextWindowPosCond); window->DC.CursorPos = backup_cursor_pos; window_pos_set_by_api = true; @@ -3706,7 +3706,8 @@ static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiSetCond co const ImVec2 old_pos = window->Pos; window->PosFloat = pos; window->Pos = ImVec2((float)(int)window->PosFloat.x, (float)(int)window->PosFloat.y); - window->DC.CursorPos += (window->Pos - old_pos); // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor + window->DC.CursorPos += (window->Pos - old_pos); // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor + window->DC.CursorMaxPos += (window->Pos - old_pos); // And more importantly we need to adjust this so size calculation doesn't get affected. } void ImGui::SetWindowPos(const ImVec2& pos, ImGuiSetCond cond) From e176a8b93fb3ea7a7906110a951ce0509f8c1cda Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 22 Mar 2015 16:26:48 +0000 Subject: [PATCH 17/42] OCD normalising function comments not ending with a comma --- imgui.h | 76 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/imgui.h b/imgui.h index 4b4ea533..b2dc9405 100644 --- a/imgui.h +++ b/imgui.h @@ -170,33 +170,33 @@ namespace ImGui IMGUI_API ImVec2 GetContentRegionMax(); // window or current column boundaries, in windows coordinates IMGUI_API ImVec2 GetWindowContentRegionMin(); // window boundaries, in windows coordinates IMGUI_API ImVec2 GetWindowContentRegionMax(); - IMGUI_API ImDrawList* GetWindowDrawList(); // get rendering command-list if you want to append your own draw primitives. + IMGUI_API ImDrawList* GetWindowDrawList(); // get rendering command-list if you want to append your own draw primitives IMGUI_API ImFont* GetWindowFont(); IMGUI_API float GetWindowFontSize(); // size (also height in pixels) of current font with current scale applied - IMGUI_API void SetWindowFontScale(float scale); // per-window font scale. Adjust IO.FontGlobalScale if you want to scale all windows. - IMGUI_API ImVec2 GetWindowPos(); // you should rarely need/care about the window position, but it can be useful if you want to do your own drawing. - IMGUI_API ImVec2 GetWindowSize(); // get current window position. + IMGUI_API void SetWindowFontScale(float scale); // per-window font scale. Adjust IO.FontGlobalScale if you want to scale all windows + IMGUI_API ImVec2 GetWindowPos(); // you should rarely need/care about the window position, but it can be useful if you want to do your own drawing + IMGUI_API ImVec2 GetWindowSize(); // get current window position IMGUI_API float GetWindowWidth(); IMGUI_API bool GetWindowCollapsed(); - IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set next window position - call before Begin(). - IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiSetCond cond = 0); // set next window size. set to ImVec2(0,0) to force an auto-fit. - IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // set next window collapsed state. + IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set next window position - call before Begin() + IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiSetCond cond = 0); // set next window size. set to ImVec2(0,0) to force an auto-fit + IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // set next window collapsed state IMGUI_API void SetNextWindowFocus(); // set next window to be focused / front-most - IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set current window position - call within Begin()/End(). may incur tearing. - IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiSetCond cond = 0); // set current window size. set to ImVec2(0,0) to force an auto-fit. may incur tearing. - IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // set current window collapsed state. + IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiSetCond cond = 0); // set current window position - call within Begin()/End(). may incur tearing + IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiSetCond cond = 0); // set current window size. set to ImVec2(0,0) to force an auto-fit. may incur tearing + IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiSetCond cond = 0); // set current window collapsed state IMGUI_API void SetWindowFocus(); // set current window to be focused / front-most - IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiSetCond cond = 0); // set named window position - call within Begin()/End(). may incur tearing. - IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiSetCond cond = 0); // set named window size. set to ImVec2(0,0) to force an auto-fit. may incur tearing. - IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiSetCond cond = 0); // set named window collapsed state. + IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiSetCond cond = 0); // set named window position - call within Begin()/End(). may incur tearing + IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiSetCond cond = 0); // set named window size. set to ImVec2(0,0) to force an auto-fit. may incur tearing + IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiSetCond cond = 0); // set named window collapsed state IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / front-most - IMGUI_API float GetScrollPosY(); // get scrolling position (0..GetScrollMaxY()) + IMGUI_API float GetScrollPosY(); // get scrolling position [0..GetScrollMaxY()] IMGUI_API float GetScrollMaxY(); // get maximum scrolling position == ContentSize.Y - WindowSize.Y - IMGUI_API void SetScrollPosHere(); // adjust scrolling position to center into the current cursor position. - IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. - IMGUI_API void SetStateStorage(ImGuiStorage* tree); // replace tree state storage with our own (if you want to manipulate it yourself, typically clear subsection of it). + IMGUI_API void SetScrollPosHere(); // adjust scrolling position to center into the current cursor position + IMGUI_API void SetKeyboardFocusHere(int offset = 0); // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget + IMGUI_API void SetStateStorage(ImGuiStorage* tree); // replace tree state storage with our own (if you want to manipulate it yourself, typically clear subsection of it) IMGUI_API ImGuiStorage* GetStateStorage(); // Parameters stacks (shared) @@ -212,15 +212,15 @@ namespace ImGui IMGUI_API void PushItemWidth(float item_width); // width of items for the common item+label case, pixels. 0.0f = default to ~2/3 of windows width, >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -0.01f always align width to the right side) IMGUI_API void PopItemWidth(); IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position - IMGUI_API void PushAllowKeyboardFocus(bool v); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets. + IMGUI_API void PushAllowKeyboardFocus(bool v); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets IMGUI_API void PopAllowKeyboardFocus(); - IMGUI_API void PushTextWrapPos(float wrap_pos_x = 0.0f); // word-wrapping for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space. + IMGUI_API void PushTextWrapPos(float wrap_pos_x = 0.0f); // word-wrapping for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space IMGUI_API void PopTextWrapPos(); // Tooltip - IMGUI_API void SetTooltip(const char* fmt, ...); // set tooltip under mouse-cursor, typically use with ImGui::IsHovered(). last call wins. + IMGUI_API void SetTooltip(const char* fmt, ...); // set tooltip under mouse-cursor, typically use with ImGui::IsHovered(). last call wins IMGUI_API void SetTooltipV(const char* fmt, va_list args); - IMGUI_API void BeginTooltip(); // use to create full-featured tooltip windows that aren't just text. + IMGUI_API void BeginTooltip(); // use to create full-featured tooltip windows that aren't just text IMGUI_API void EndTooltip(); // Layout @@ -234,8 +234,8 @@ namespace ImGui IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border=true); // setup number of columns IMGUI_API void NextColumn(); // next column IMGUI_API int GetColumnIndex(); // get current column index - IMGUI_API float GetColumnOffset(int column_index = -1); // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetcolumnsCount() inclusive. column 0 is usually 0.0f and not resizable unless you call this. - IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column. + IMGUI_API float GetColumnOffset(int column_index = -1); // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetcolumnsCount() inclusive. column 0 is usually 0.0f and not resizable unless you call this + IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column IMGUI_API float GetColumnWidth(int column_index = -1); // column width (== GetColumnOffset(GetColumnIndex()+1) - GetColumnOffset(GetColumnOffset()) IMGUI_API int GetColumnsCount(); // number of columns (what was passed to Columns()) IMGUI_API ImVec2 GetCursorPos(); // cursor position is relative to window position @@ -244,20 +244,20 @@ namespace ImGui IMGUI_API void SetCursorPos(const ImVec2& pos); // " IMGUI_API void SetCursorPosX(float x); // " IMGUI_API void SetCursorPosY(float y); // " - IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute screen coordinates (0..io.DisplaySize) - IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute screen coordinates (0..io.DisplaySize) - IMGUI_API void AlignFirstTextHeightToWidgets(); // call once if the first item on the line is a Text() item and you want to vertically lower it to match subsequent (bigger) widgets. + IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute screen coordinates [0..io.DisplaySize] + IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute screen coordinates [0..io.DisplaySize] + IMGUI_API void AlignFirstTextHeightToWidgets(); // call once if the first item on the line is a Text() item and you want to vertically lower it to match subsequent (bigger) widgets IMGUI_API float GetTextLineHeight(); // height of font == GetWindowFontSize() IMGUI_API float GetTextLineHeightWithSpacing(); // spacing (in pixels) between 2 consecutive lines of text == GetWindowFontSize() + GetStyle().ItemSpacing.y // ID scopes - // If you are creating widgets in a loop you most likely want to push a unique identifier so ImGui can differentiate them. + // If you are creating widgets in a loop you most likely want to push a unique identifier so ImGui can differentiate them // You can also use "##extra" within your widget name to distinguish them from each others (see 'Programmer Guide') IMGUI_API void PushID(const char* str_id); // push identifier into the ID stack. IDs are hash of the *entire* stack! IMGUI_API void PushID(const void* ptr_id); IMGUI_API void PushID(const int int_id); IMGUI_API void PopID(); - IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). useful if you want to query into ImGuiStorage yourself. otherwise rarely needed. + IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). useful if you want to query into ImGuiStorage yourself. otherwise rarely needed IMGUI_API ImGuiID GetID(const void* ptr_id); // Widgets @@ -267,7 +267,7 @@ namespace ImGui IMGUI_API void TextColoredV(const ImVec4& col, const char* fmt, va_list args); IMGUI_API void TextWrapped(const char* fmt, ...); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos(); IMGUI_API void TextWrappedV(const char* fmt, va_list args); - IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // doesn't require null terminated string if 'text_end' is specified. no copy done to any bounded stack buffer, recommended for long chunks of text. + IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // doesn't require null terminated string if 'text_end' is specified. no copy done to any bounded stack buffer, recommended for long chunks of text IMGUI_API void LabelText(const char* label, const char* fmt, ...); // display text+label aligned the same way as value+label widgets IMGUI_API void LabelTextV(const char* label, const char* fmt, va_list args); IMGUI_API void Bullet(); @@ -277,9 +277,9 @@ namespace ImGui IMGUI_API bool SmallButton(const char* label); 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), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0)); - IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,1), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no paddnig. + IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0,0), const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,1), const ImVec4& tint_col = ImVec4(1,1,1,1)); // <0 frame_padding uses default frame padding settings. 0 for no padding IMGUI_API bool CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false); - IMGUI_API bool 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 SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* display_format = "%.3f", float power = 1.0f); @@ -353,7 +353,7 @@ namespace ImGui // Utilities IMGUI_API bool IsItemHovered(); // was the last item hovered by mouse? - IMGUI_API bool IsItemHoveredRectOnly(); // was the last item hovered by mouse? even if another item is active while we are hovering this. + IMGUI_API bool IsItemHoveredRectOnly(); // was the last item hovered by mouse? even if another item is active while we are hovering this IMGUI_API bool IsItemActive(); // was the last item active? (e.g. button being held, text field being edited- items that don't interact will always return false) IMGUI_API bool IsAnyItemActive(); // IMGUI_API ImVec2 GetItemRectMin(); // get bounding rect of last item @@ -369,20 +369,20 @@ namespace ImGui IMGUI_API bool IsMouseHoveringWindow(); // is mouse hovering current window ("window" in API names always refer to current window) IMGUI_API bool IsMouseHoveringAnyWindow(); // is mouse hovering any active imgui window IMGUI_API bool IsMouseHoveringRect(const ImVec2& rect_min, const ImVec2& rect_max);// is mouse hovering given bounding rect - IMGUI_API bool IsMouseDragging(int button = 0, float lock_threshold = -1.0f); // is mouse dragging. if lock_threshold < -1.0f uses io.MouseDraggingThreshold. + IMGUI_API bool IsMouseDragging(int button = 0, float lock_threshold = -1.0f); // is mouse dragging. if lock_threshold < -1.0f uses io.MouseDraggingThreshold IMGUI_API bool IsPosHoveringAnyWindow(const ImVec2& pos); // is given position hovering any active imgui window IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls - IMGUI_API ImVec2 GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f); // dragging amount, also see: GetItemActiveDragDelta(). if lock_threshold < -1.0f uses io.MouseDraggingThreshold. - IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you. + IMGUI_API ImVec2 GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f); // dragging amount, also see: GetItemActiveDragDelta(). if lock_threshold < -1.0f uses io.MouseDraggingThreshold + IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you IMGUI_API void SetMouseCursor(ImGuiMouseCursor type); // set desired cursor type IMGUI_API float GetTime(); IMGUI_API int GetFrameCount(); IMGUI_API const char* GetStyleColName(ImGuiCol idx); - IMGUI_API ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = +0.0f); // utility to find the closest point the last item bounding rectangle edge. useful to visually link items. + IMGUI_API ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = +0.0f); // utility to find the closest point the last item bounding rectangle edge. useful to visually link items 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 void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // helper to manually clip large list of items. see comments in implementation. + IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // helper to manually clip large list of items. see comments in implementation - IMGUI_API void BeginChildFrame(ImGuiID id, const ImVec2& size); // helper to create a child window / scrolling region that looks like a normal widget frame. + IMGUI_API void BeginChildFrame(ImGuiID id, const ImVec2& size); // helper to create a child window / scrolling region that looks like a normal widget frame IMGUI_API void EndChildFrame(); IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4& in); From c9430bb80735de46e8cc547abdd55b29de500d23 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 22 Mar 2015 17:22:39 +0000 Subject: [PATCH 18/42] Fixed new windows auto-fitting bigger than their .ini saved size --- imgui.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5dec4179..5eb205a6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1574,12 +1574,6 @@ ImGuiWindow::ImGuiWindow(const char* name) ItemWidthDefault = 0.0f; FontWindowScale = 1.0f; - if (ImLengthSqr(Size) < 0.00001f) - { - AutoFitFrames = 2; - AutoFitOnlyGrows = true; - } - DrawList = (ImDrawList*)ImGui::MemAlloc(sizeof(ImDrawList)); new(DrawList) ImDrawList(); RootWindow = NULL; @@ -2877,6 +2871,13 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl size = settings->Size; window->Size = window->SizeFull = size; } + + if (ImLengthSqr(window->Size) < 0.00001f) + { + window->AutoFitFrames = 2; + window->AutoFitOnlyGrows = true; + } + g.Windows.push_back(window); return window; } From 9d4ba2e27dbff62e0ff953a243b11f37dd10c8e2 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 23 Mar 2015 22:45:05 +0000 Subject: [PATCH 19/42] Using SetNextWindowSize() in examples to encourage its use --- imgui.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 5eb205a6..f91a9a48 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1999,7 +1999,8 @@ void ImGui::NewFrame() g.CurrentWindowStack.resize(0); // Create implicit window - we will only render it if the user has added something to it. - ImGui::Begin("Debug", NULL, ImVec2(400,400)); + ImGui::SetNextWindowSize(ImVec2(400,400), ImGuiSetCond_FirstUseEver); + ImGui::Begin("Debug"); } // NB: behavior of ImGui after Shutdown() is not tested/guaranteed at the moment. This function is merely here to free heap allocations. @@ -2891,7 +2892,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl // - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned. // - Passing 'bool* p_opened' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed. // - Passing non-zero 'size' is roughly equivalent to calling SetNextWindowSize(size, ImGuiSetCond_FirstUseEver) prior to calling Begin(). -bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg_alpha, ImGuiWindowFlags flags) +bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& initial_size, float bg_alpha, ImGuiWindowFlags flags) { ImGuiState& g = *GImGui; const ImGuiStyle& style = g.Style; @@ -2903,7 +2904,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg ImGuiWindow* window = FindWindowByName(name); if (!window) { - window = CreateNewWindow(name, size, flags); + window = CreateNewWindow(name, initial_size, flags); window_is_new = true; } window->Flags = (ImGuiWindowFlags)flags; @@ -2979,7 +2980,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size, float bg { parent_window->DC.ChildWindows.push_back(window); window->Pos = window->PosFloat = parent_window->DC.CursorPos; - window->SizeFull = size; + window->SizeFull = initial_size; } } @@ -10243,7 +10244,8 @@ struct ExampleAppConsole void Run(const char* title, bool* opened) { - if (!ImGui::Begin(title, opened, ImVec2(520,600))) + ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiSetCond_FirstUseEver); + if (!ImGui::Begin(title, opened)) { ImGui::End(); return; @@ -10462,7 +10464,8 @@ static void ShowExampleAppConsole(bool* opened) static void ShowExampleAppLongText(bool* opened) { - if (!ImGui::Begin("Example: Long text display", opened, ImVec2(520,600))) + ImGui::SetNextWindowSize(ImVec2(520,600), ImGuiSetCond_FirstUseEver); + if (!ImGui::Begin("Example: Long text display", opened)) { ImGui::End(); return; From b04ee7e040bbada26539469e678fc96c1d7c9f58 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 23 Mar 2015 22:50:17 +0000 Subject: [PATCH 20/42] Added a more convenient three parameters version of Begin() which Flags more accessible. --- imgui.cpp | 13 +++++++++---- imgui.h | 7 ++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f91a9a48..5b2d6bad 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2892,7 +2892,12 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl // - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned. // - Passing 'bool* p_opened' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed. // - Passing non-zero 'size' is roughly equivalent to calling SetNextWindowSize(size, ImGuiSetCond_FirstUseEver) prior to calling Begin(). -bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& initial_size, float bg_alpha, ImGuiWindowFlags flags) +bool ImGui::Begin(const char* name, bool* p_opened, ImGuiWindowFlags flags) +{ + return ImGui::Begin(name, p_opened, ImVec2(0.f, 0.f), -1.0f, flags); +} + +bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_use, float bg_alpha, ImGuiWindowFlags flags) { ImGuiState& g = *GImGui; const ImGuiStyle& style = g.Style; @@ -2904,7 +2909,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& initial_size, ImGuiWindow* window = FindWindowByName(name); if (!window) { - window = CreateNewWindow(name, initial_size, flags); + window = CreateNewWindow(name, size_on_first_use, flags); window_is_new = true; } window->Flags = (ImGuiWindowFlags)flags; @@ -2980,7 +2985,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& initial_size, { parent_window->DC.ChildWindows.push_back(window); window->Pos = window->PosFloat = parent_window->DC.CursorPos; - window->SizeFull = initial_size; + window->SizeFull = size_on_first_use; } } @@ -10078,7 +10083,7 @@ void ImGui::ShowTestWindow(bool* opened) static void ShowExampleAppAutoResize(bool* opened) { - if (!ImGui::Begin("Example: Auto-Resizing Window", opened, ImVec2(0,0), -1.0f, ImGuiWindowFlags_AlwaysAutoResize)) + if (!ImGui::Begin("Example: Auto-Resizing Window", opened, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::End(); return; diff --git a/imgui.h b/imgui.h index b2dc9405..60a67281 100644 --- a/imgui.h +++ b/imgui.h @@ -162,10 +162,11 @@ namespace ImGui // Window // See implementation in .cpp for details - IMGUI_API bool Begin(const char* name = "Debug", bool* p_opened = NULL, const ImVec2& initial_size = ImVec2(0,0), float bg_alpha = -1.0f, ImGuiWindowFlags flags = 0); // return false when window is collapsed, so you can early out in your code. passing 'bool* p_opened' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed. + IMGUI_API bool Begin(const char* name = "Debug", bool* p_opened = NULL, ImGuiWindowFlags flags = 0); // return false when window is collapsed, so you can early out in your code. 'bool* p_opened' creates a widget on the upper-right to close the window (which sets your bool to false). + IMGUI_API bool Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags = 0); // this is the older/longer API. call SetNextWindowSize() instead if you want to set a window size. For regular windows, 'size_on_first_use' only applies to the first time EVER the window is created and probably not what you want! maybe obsolete this API eventually. IMGUI_API void End(); - IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // size==0.0f: use remaining window size, size<0.0f: use remaining window size minus abs(size). on each axis. - IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // " + IMGUI_API bool BeginChild(const char* str_id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // size==0.0f: use remaining window size, size<0.0f: use remaining window size minus abs(size). on each axis. + IMGUI_API bool BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0,0), bool border = false, ImGuiWindowFlags extra_flags = 0); // " IMGUI_API void EndChild(); IMGUI_API ImVec2 GetContentRegionMax(); // window or current column boundaries, in windows coordinates IMGUI_API ImVec2 GetWindowContentRegionMin(); // window boundaries, in windows coordinates From 8b7668d24f8b2899b5df4f1593b7bee21425f3ff Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 16:03:30 +0000 Subject: [PATCH 21/42] Avoid negative clipping rectangle when collapsing windows, ImDrawList could still submit data #177 --- imgui.cpp | 6 ++++++ imgui.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 5b2d6bad..144ce895 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2098,6 +2098,7 @@ static void PushClipRect(const ImVec4& clip_rect, bool clipped = true) cr = ImVec4(ImMax(cr.x, cur_cr.x), ImMax(cr.y, cur_cr.y), ImMin(cr.z, cur_cr.z), ImMin(cr.w, cur_cr.w)); } + IM_ASSERT(cr.x <= cr.z && cr.y <= cr.w); window->ClipRectStack.push_back(cr); window->DrawList->PushClipRect(cr); } @@ -3295,10 +3296,13 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // Inner clipping rectangle // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame + // Note that if our window is collapsed we will end up with a null clipping rectangle which is the correct behavior. const ImRect title_bar_rect = window->TitleBarRect(); ImVec4 clip_rect(title_bar_rect.Min.x+0.5f+window->WindowPadding().x*0.5f, title_bar_rect.Max.y+0.5f, window->Rect().Max.x+0.5f-window->WindowPadding().x*0.5f, window->Rect().Max.y-1.5f); if (window->ScrollbarY) clip_rect.z -= style.ScrollbarWidth; + clip_rect.z = ImMax(clip_rect.x, clip_rect.z); + clip_rect.w = ImMax(clip_rect.y, clip_rect.w); PushClipRect(clip_rect); // Clear 'accessed' flag last thing @@ -7360,6 +7364,8 @@ void ImDrawList::AddDrawCmd() draw_cmd.texture_id = texture_id_stack.empty() ? NULL : texture_id_stack.back(); draw_cmd.user_callback = NULL; draw_cmd.user_callback_data = NULL; + + IM_ASSERT(draw_cmd.clip_rect.x <= draw_cmd.clip_rect.z && draw_cmd.clip_rect.y <= draw_cmd.clip_rect.w); commands.push_back(draw_cmd); } diff --git a/imgui.h b/imgui.h index 60a67281..0e09024f 100644 --- a/imgui.h +++ b/imgui.h @@ -45,7 +45,7 @@ typedef int ImGuiKey; // enum ImGuiKey_ typedef int ImGuiColorEditMode; // enum ImGuiColorEditMode_ typedef int ImGuiMouseCursor; // enum ImGuiMouseCursor_ typedef int ImGuiWindowFlags; // enum ImGuiWindowFlags_ -typedef int ImGuiSetCond; // enum ImGuiSetCondition_ +typedef int ImGuiSetCond; // enum ImGuiSetCond_ typedef int ImGuiInputTextFlags; // enum ImGuiInputTextFlags_ struct ImGuiTextEditCallbackData; // for advanced uses of InputText() typedef int (*ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data); From 743c81582122ca2bdef37b511529b8559a31d29b Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 16:18:01 +0000 Subject: [PATCH 22/42] Renamed IsItemHoveredRectOnly -> IsItemHoveredRect (introduced after previous release) --- imgui.cpp | 14 +++++++------- imgui.h | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 144ce895..f2668f7e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -982,7 +982,7 @@ struct ImGuiDrawContext ImGuiID LastItemID; ImRect LastItemRect; bool LastItemHoveredAndUsable; - bool LastItemHoveredRectOnly; + bool LastItemHoveredRect; ImVector ChildWindows; ImVector AllowKeyboardFocus; ImVector ItemWidth; // 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window @@ -1011,7 +1011,7 @@ struct ImGuiDrawContext TreeDepth = 0; LastItemID = 0; LastItemRect = ImRect(0.0f,0.0f,0.0f,0.0f); - LastItemHoveredAndUsable = LastItemHoveredRectOnly = false; + LastItemHoveredAndUsable = LastItemHoveredRect = false; StateStorage = NULL; ColumnsStartX = 0.0f; @@ -2640,10 +2640,10 @@ bool ImGui::IsItemHovered() return window->DC.LastItemHoveredAndUsable; } -bool ImGui::IsItemHoveredRectOnly() +bool ImGui::IsItemHoveredRect() { ImGuiWindow* window = GetCurrentWindow(); - return window->DC.LastItemHoveredRectOnly; + return window->DC.LastItemHoveredRect; } bool ImGui::IsItemActive() @@ -6956,7 +6956,7 @@ static bool ItemAdd(const ImRect& bb, const ImGuiID* id) window->DC.LastItemRect = bb; if (IsClipped(bb)) { - window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRectOnly = false; + window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRect = false; return false; } @@ -6966,7 +6966,7 @@ static bool ItemAdd(const ImRect& bb, const ImGuiID* id) { // Matching the behavior of IsHovered() but ignore if ActiveId==window->MoveID (we clicked on the window background) // So that clicking on items with no active id such as Text() still returns true with IsItemHovered() - window->DC.LastItemHoveredRectOnly = true; + window->DC.LastItemHoveredRect = true; if (g.ActiveId == 0 || (id && g.ActiveId == *id) || g.ActiveIdIsFocusedOnly || (g.ActiveId == window->MoveID)) window->DC.LastItemHoveredAndUsable = true; else @@ -6974,7 +6974,7 @@ static bool ItemAdd(const ImRect& bb, const ImGuiID* id) } else { - window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRectOnly = false; + window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRect = false; } return true; diff --git a/imgui.h b/imgui.h index 0e09024f..0a9cee54 100644 --- a/imgui.h +++ b/imgui.h @@ -354,7 +354,7 @@ namespace ImGui // Utilities IMGUI_API bool IsItemHovered(); // was the last item hovered by mouse? - IMGUI_API bool IsItemHoveredRectOnly(); // was the last item hovered by mouse? even if another item is active while we are hovering this + IMGUI_API bool IsItemHoveredRect(); // was the last item hovered by mouse? even if another item is active while we are hovering this IMGUI_API bool IsItemActive(); // was the last item active? (e.g. button being held, text field being edited- items that don't interact will always return false) IMGUI_API bool IsAnyItemActive(); // IMGUI_API ImVec2 GetItemRectMin(); // get bounding rect of last item @@ -373,7 +373,7 @@ namespace ImGui IMGUI_API bool IsMouseDragging(int button = 0, float lock_threshold = -1.0f); // is mouse dragging. if lock_threshold < -1.0f uses io.MouseDraggingThreshold IMGUI_API bool IsPosHoveringAnyWindow(const ImVec2& pos); // is given position hovering any active imgui window IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls - IMGUI_API ImVec2 GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f); // dragging amount, also see: GetItemActiveDragDelta(). if lock_threshold < -1.0f uses io.MouseDraggingThreshold + IMGUI_API ImVec2 GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f); // dragging amount since clicking, also see: GetItemActiveDragDelta(). if lock_threshold < -1.0f uses io.MouseDraggingThreshold IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired cursor type, reset in ImGui::NewFrame(), this updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you IMGUI_API void SetMouseCursor(ImGuiMouseCursor type); // set desired cursor type IMGUI_API float GetTime(); From 3268646180e9d38708c509fd4615c5edcc8d138d Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 16:28:41 +0000 Subject: [PATCH 23/42] Fixed clipping rectangle's own clipping #177 --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f2668f7e..1da4e33b 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2097,6 +2097,8 @@ static void PushClipRect(const ImVec4& clip_rect, bool clipped = true) const ImVec4 cur_cr = window->ClipRectStack.back(); cr = ImVec4(ImMax(cr.x, cur_cr.x), ImMax(cr.y, cur_cr.y), ImMin(cr.z, cur_cr.z), ImMin(cr.w, cur_cr.w)); } + cr.z = ImMax(cr.x, cr.z); + cr.w = ImMax(cr.y, cr.w); IM_ASSERT(cr.x <= cr.z && cr.y <= cr.w); window->ClipRectStack.push_back(cr); @@ -3301,8 +3303,6 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ ImVec4 clip_rect(title_bar_rect.Min.x+0.5f+window->WindowPadding().x*0.5f, title_bar_rect.Max.y+0.5f, window->Rect().Max.x+0.5f-window->WindowPadding().x*0.5f, window->Rect().Max.y-1.5f); if (window->ScrollbarY) clip_rect.z -= style.ScrollbarWidth; - clip_rect.z = ImMax(clip_rect.x, clip_rect.z); - clip_rect.w = ImMax(clip_rect.y, clip_rect.w); PushClipRect(clip_rect); // Clear 'accessed' flag last thing From 325e29242764c5341c732fa8e9600326609ca161 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 16:41:52 +0000 Subject: [PATCH 24/42] Selectable(): not specifying a width default to using max of label width and remaining width --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 1da4e33b..020fc51c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6527,7 +6527,7 @@ bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg) const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const float w = window->Pos.x + ImGui::GetContentRegionMax().x - window->DC.CursorPos.x; + const float w = ImMax(label_size.x, window->Pos.x + ImGui::GetContentRegionMax().x - window->DC.CursorPos.x); const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : w, size_arg.y != 0.0f ? size_arg.y : label_size.y); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); ItemSize(bb); From 7e334013a038d542a800e482d2c8f1c351cedf14 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 16:42:46 +0000 Subject: [PATCH 25/42] Selectable(const char*, bool) version has bool defaulting to false --- imgui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.h b/imgui.h index 0a9cee54..0daa88a5 100644 --- a/imgui.h +++ b/imgui.h @@ -328,7 +328,7 @@ namespace ImGui IMGUI_API void SetNextTreeNodeOpened(bool opened, ImGuiSetCond cond = 0); // set next tree node to be opened. // Selectable / Lists - IMGUI_API bool Selectable(const char* label, bool selected, const ImVec2& size = ImVec2(0,0)); + IMGUI_API bool Selectable(const char* label, bool selected = false, const ImVec2& size = ImVec2(0,0)); IMGUI_API bool Selectable(const char* label, bool* p_selected, const ImVec2& size = ImVec2(0,0)); IMGUI_API bool ListBox(const char* label, int* current_item, const char** items, int items_count, int height_in_items = -1); IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); From d3e8e15e41783f1b48d93b05866a63f07fb49e8f Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 16:45:44 +0000 Subject: [PATCH 26/42] Added popup demo code (commented out because I expect to make popup menu proper citizens by next version) --- imgui.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 020fc51c..c999d389 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9396,6 +9396,38 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::TreePop(); } + /* + if (ImGui::TreeNode("Popup Menu")) + { + static bool popup_open = false; + static int selected_fish = -1; + const char* fishes[] = { "Bream", "Mackerel", "Pollock", "Tilefish" }; + if (ImGui::Button("Select..")) + { + popup_open = true; + ImGui::SetNextWindowPos(ImGui::GetMousePos()); + } + ImGui::SameLine(); + ImGui::Text(selected_fish == -1 ? "" : fishes[selected_fish]); + if (popup_open) + { + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::Begin("##Popup", &popup_open, ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize); + if (!ImGui::IsWindowFocused()) + popup_open = false; + for (size_t i = 0; i < IM_ARRAYSIZE(fishes); i++) + if (ImGui::Selectable(fishes[i], false)) + { + selected_fish = i; + popup_open = false; + } + ImGui::End(); + ImGui::PopStyleVar(); + } + ImGui::TreePop(); + } + */ + if (ImGui::TreeNode("Filtered Text Input")) { static char buf1[64] = ""; ImGui::InputText("default", buf1, 64); From 91f8eb7b92c2e60e21698cc779c0a7d962087584 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 17:09:17 +0000 Subject: [PATCH 27/42] Added early version of BeginPopup/EndPopup() #126 --- imgui.cpp | 66 ++++++++++++++++++++++++++++++++++++++----------------- imgui.h | 7 +++++- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c999d389..a817a107 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2062,6 +2062,8 @@ static int ChildWindowComparer(const void* lhs, const void* rhs) { const ImGuiWindow* a = *(const ImGuiWindow**)lhs; const ImGuiWindow* b = *(const ImGuiWindow**)rhs; + if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup)) + return d; if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip)) return d; if (int d = (a->Flags & ImGuiWindowFlags_ComboBox) - (b->Flags & ImGuiWindowFlags_ComboBox)) @@ -2174,13 +2176,13 @@ void ImGui::Render() for (size_t i = 0; i != g.Windows.size(); i++) { ImGuiWindow* window = g.Windows[i]; - if (window->Visible && (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0) + if (window->Visible && (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) == 0) AddWindowToRenderList(window); } for (size_t i = 0; i != g.Windows.size(); i++) { ImGuiWindow* window = g.Windows[i]; - if (window->Visible && (window->Flags & ImGuiWindowFlags_Tooltip)) + if (window->Visible && (window->Flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup))) AddWindowToRenderList(window); } @@ -2719,7 +2721,7 @@ int ImGui::GetFrameCount() void ImGui::BeginTooltip() { ImGuiState& g = *GImGui; - ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_Tooltip; + ImGuiWindowFlags window_flags = ImGuiWindowFlags_Tooltip|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; ImGui::Begin("##Tooltip", NULL, ImVec2(0,0), g.Style.Colors[ImGuiCol_TooltipBg].w, window_flags); } @@ -2729,6 +2731,21 @@ void ImGui::EndTooltip() ImGui::End(); } +bool ImGui::BeginPopup(bool* p_opened) +{ + IM_ASSERT(p_opened != NULL); // Must provide a bool at the moment + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + bool ret = ImGui::Begin("##Popup", p_opened, ImGuiWindowFlags_Popup|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize); + return ret; +} + +void ImGui::EndPopup() +{ + IM_ASSERT(GetCurrentWindow()->Flags & ImGuiWindowFlags_Popup); + ImGui::End(); + ImGui::PopStyleVar(); +} + bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags) { ImGuiState& g = *GImGui; @@ -2975,8 +2992,17 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // New windows appears in front if (!(flags & ImGuiWindowFlags_ChildWindow)) if (window->LastFrameDrawn < current_frame - 1) + { FocusWindow(window); + // Popup position themselves when they first appear + if (flags & ImGuiWindowFlags_Popup) + { + if (!window_pos_set_by_api) + window->PosFloat = g.IO.MousePos; + } + } + window->LastFrameDrawn = current_frame; window->ClipRectStack.resize(0); @@ -3281,6 +3307,12 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ const ImVec2 text_max = window->Pos + ImVec2(window->Size.x - (p_opened ? (title_bar_rect.GetHeight()-3) : style.FramePadding.x), style.FramePadding.y*2 + text_size.y); RenderTextClipped(text_min, name, NULL, &text_size, text_max); } + if (window->Flags & ImGuiWindowFlags_Popup) + { + if (g.FocusedWindow != window) + if (p_opened) + *p_opened = false; + } // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() window->ClippedRect = window->Rect(); @@ -9396,37 +9428,31 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::TreePop(); } - /* if (ImGui::TreeNode("Popup Menu")) { static bool popup_open = false; static int selected_fish = -1; const char* fishes[] = { "Bream", "Mackerel", "Pollock", "Tilefish" }; if (ImGui::Button("Select..")) - { popup_open = true; - ImGui::SetNextWindowPos(ImGui::GetMousePos()); - } ImGui::SameLine(); ImGui::Text(selected_fish == -1 ? "" : fishes[selected_fish]); + if (popup_open) { - ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); - ImGui::Begin("##Popup", &popup_open, ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize); - if (!ImGui::IsWindowFocused()) - popup_open = false; - for (size_t i = 0; i < IM_ARRAYSIZE(fishes); i++) - if (ImGui::Selectable(fishes[i], false)) - { - selected_fish = i; - popup_open = false; - } - ImGui::End(); - ImGui::PopStyleVar(); + if (ImGui::BeginPopup(&popup_open)) + { + for (size_t i = 0; i < IM_ARRAYSIZE(fishes); i++) + if (ImGui::Selectable(fishes[i], false)) + { + selected_fish = i; + popup_open = false; + } + } + ImGui::EndPopup(); } ImGui::TreePop(); } - */ if (ImGui::TreeNode("Filtered Text Input")) { diff --git a/imgui.h b/imgui.h index 0daa88a5..74eb1333 100644 --- a/imgui.h +++ b/imgui.h @@ -224,6 +224,10 @@ namespace ImGui IMGUI_API void BeginTooltip(); // use to create full-featured tooltip windows that aren't just text IMGUI_API void EndTooltip(); + // Popup + IMGUI_API bool BeginPopup(bool* p_opened); + IMGUI_API void EndPopup(); + // Layout IMGUI_API void BeginGroup(); IMGUI_API void EndGroup(); @@ -424,7 +428,8 @@ enum ImGuiWindowFlags_ ImGuiWindowFlags_ChildWindowAutoFitX = 1 << 10, // For internal use by BeginChild() ImGuiWindowFlags_ChildWindowAutoFitY = 1 << 11, // For internal use by BeginChild() ImGuiWindowFlags_ComboBox = 1 << 12, // For internal use by ComboBox() - ImGuiWindowFlags_Tooltip = 1 << 13 // For internal use by BeginTooltip() + ImGuiWindowFlags_Tooltip = 1 << 13, // For internal use by BeginTooltip() + ImGuiWindowFlags_Popup = 1 << 14 // For internal use by BeginPopup() }; // Flags for ImGui::InputText() From de7552047b83584c9f9391b480fad5ceef294488 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 17:11:14 +0000 Subject: [PATCH 28/42] Simplified example --- imgui.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a817a107..64a24168 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9437,18 +9437,15 @@ void ImGui::ShowTestWindow(bool* opened) popup_open = true; ImGui::SameLine(); ImGui::Text(selected_fish == -1 ? "" : fishes[selected_fish]); - if (popup_open) { - if (ImGui::BeginPopup(&popup_open)) - { - for (size_t i = 0; i < IM_ARRAYSIZE(fishes); i++) - if (ImGui::Selectable(fishes[i], false)) - { - selected_fish = i; - popup_open = false; - } - } + ImGui::BeginPopup(&popup_open); + for (size_t i = 0; i < IM_ARRAYSIZE(fishes); i++) + if (ImGui::Selectable(fishes[i], false)) + { + selected_fish = i; + popup_open = false; + } ImGui::EndPopup(); } ImGui::TreePop(); From ac2da570f57d442d31d2555b14632ea7f732db49 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 17:17:42 +0000 Subject: [PATCH 29/42] When a popup window is open it inhibit hovering on other windows #126 --- imgui.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 64a24168..44248384 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4244,8 +4244,13 @@ static bool IsHovered(const ImRect& bb, ImGuiID id) ImGuiWindow* window = GetCurrentWindow(); if (g.HoveredRootWindow == window->RootWindow) { - bool hovered = (g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdIsFocusedOnly) && IsMouseHoveringRect(bb); - return hovered; + if ((g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdIsFocusedOnly) && IsMouseHoveringRect(bb)) + { + if (!(g.FocusedWindow->Flags & ImGuiWindowFlags_Popup) || g.FocusedWindow == g.HoveredRootWindow) + { + return true; + } + } } } return false; @@ -6999,10 +7004,10 @@ static bool ItemAdd(const ImRect& bb, const ImGuiID* id) // Matching the behavior of IsHovered() but ignore if ActiveId==window->MoveID (we clicked on the window background) // So that clicking on items with no active id such as Text() still returns true with IsItemHovered() window->DC.LastItemHoveredRect = true; + window->DC.LastItemHoveredAndUsable = false; if (g.ActiveId == 0 || (id && g.ActiveId == *id) || g.ActiveIdIsFocusedOnly || (g.ActiveId == window->MoveID)) - window->DC.LastItemHoveredAndUsable = true; - else - window->DC.LastItemHoveredAndUsable = false; + if (!(g.FocusedWindow->Flags & ImGuiWindowFlags_Popup) || g.FocusedWindow == window) + window->DC.LastItemHoveredAndUsable = true; } else { From 5fe4ae62cb3de58e7c8cef245170cd4a8abbf167 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 17:24:05 +0000 Subject: [PATCH 30/42] Popup: clicking on empty space also close popup #126 --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 44248384..8c56ede0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3309,7 +3309,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } if (window->Flags & ImGuiWindowFlags_Popup) { - if (g.FocusedWindow != window) + if ((g.IO.MouseClicked[0] && (!g.HoveredWindow || g.HoveredWindow->RootWindow != window)) || (!g.FocusedWindow || g.FocusedWindow->RootWindow != window)) if (p_opened) *p_opened = false; } From a4dc7753399e431c05160a28cf78e7a867f8e65b Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 17:35:52 +0000 Subject: [PATCH 31/42] Fixed hovering bug introduced in ac2da570 when popup is inactive #126 --- imgui.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8c56ede0..3308fc3f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1221,6 +1221,7 @@ struct ImGuiWindow float NextScrollY; bool ScrollbarY; bool Visible; // Set to true on Begin() + bool WasVisible; bool Accessed; // Set to true when any widget access the current window bool Collapsed; // Set when collapsing window to become only title-bar bool SkipItems; // == Visible && !Collapsed @@ -1562,7 +1563,7 @@ ImGuiWindow::ImGuiWindow(const char* name) ScrollY = 0.0f; NextScrollY = 0.0f; ScrollbarY = false; - Visible = false; + Visible = WasVisible = false; Accessed = false; Collapsed = false; SkipItems = false; @@ -1990,6 +1991,7 @@ void ImGui::NewFrame() for (size_t i = 0; i != g.Windows.size(); i++) { ImGuiWindow* window = g.Windows[i]; + window->WasVisible = window->Visible; window->Visible = false; window->Accessed = false; } @@ -4246,7 +4248,7 @@ static bool IsHovered(const ImRect& bb, ImGuiID id) { if ((g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdIsFocusedOnly) && IsMouseHoveringRect(bb)) { - if (!(g.FocusedWindow->Flags & ImGuiWindowFlags_Popup) || g.FocusedWindow == g.HoveredRootWindow) + if (g.FocusedWindow == g.HoveredRootWindow || !((g.FocusedWindow->Flags & ImGuiWindowFlags_Popup) != 0 && g.FocusedWindow->WasVisible)) { return true; } @@ -7006,7 +7008,7 @@ static bool ItemAdd(const ImRect& bb, const ImGuiID* id) window->DC.LastItemHoveredRect = true; window->DC.LastItemHoveredAndUsable = false; if (g.ActiveId == 0 || (id && g.ActiveId == *id) || g.ActiveIdIsFocusedOnly || (g.ActiveId == window->MoveID)) - if (!(g.FocusedWindow->Flags & ImGuiWindowFlags_Popup) || g.FocusedWindow == window) + if (g.FocusedWindow == window || !((g.FocusedWindow->Flags & ImGuiWindowFlags_Popup) != 0 && g.FocusedWindow->WasVisible)) window->DC.LastItemHoveredAndUsable = true; } else From fc25d71f843f60dbaa7a781d306bb3625081cc54 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 17:45:11 +0000 Subject: [PATCH 32/42] Refactored duplicated code into an inline function & made more readable --- imgui.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3308fc3f..a86fd722 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4238,6 +4238,17 @@ void ImGui::LabelText(const char* label, const char* fmt, ...) va_end(args); } +static inline bool IsWindowContentHoverable(ImGuiWindow* window) +{ + ImGuiState& g = *GImGui; + + ImGuiWindow* focused_window = g.FocusedWindow; + if (focused_window && (focused_window->Flags & ImGuiWindowFlags_Popup) != 0 && focused_window->WasVisible && focused_window != window) + return false; + + return true; +} + static bool IsHovered(const ImRect& bb, ImGuiID id) { ImGuiState& g = *GImGui; @@ -4247,12 +4258,8 @@ static bool IsHovered(const ImRect& bb, ImGuiID id) if (g.HoveredRootWindow == window->RootWindow) { if ((g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdIsFocusedOnly) && IsMouseHoveringRect(bb)) - { - if (g.FocusedWindow == g.HoveredRootWindow || !((g.FocusedWindow->Flags & ImGuiWindowFlags_Popup) != 0 && g.FocusedWindow->WasVisible)) - { + if (IsWindowContentHoverable(g.HoveredRootWindow)) return true; - } - } } } return false; @@ -7008,7 +7015,7 @@ static bool ItemAdd(const ImRect& bb, const ImGuiID* id) window->DC.LastItemHoveredRect = true; window->DC.LastItemHoveredAndUsable = false; if (g.ActiveId == 0 || (id && g.ActiveId == *id) || g.ActiveIdIsFocusedOnly || (g.ActiveId == window->MoveID)) - if (g.FocusedWindow == window || !((g.FocusedWindow->Flags & ImGuiWindowFlags_Popup) != 0 && g.FocusedWindow->WasVisible)) + if (IsWindowContentHoverable(window)) window->DC.LastItemHoveredAndUsable = true; } else From a3086f40fe66307e9b558059b1991661b2c5d25b Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 18:01:40 +0000 Subject: [PATCH 33/42] Renamed internal RenderSortedWindows -> WindowsSortBuffer + cleanup popup closing code --- imgui.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index a86fd722..cf3c9609 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1095,6 +1095,7 @@ struct ImGuiState int FrameCount; int FrameCountRendered; ImVector Windows; + ImVector WindowsSortBuffer; ImGuiWindow* CurrentWindow; // Being drawn into ImVector CurrentWindowStack; ImGuiWindow* FocusedWindow; // Will catch keyboard inputs @@ -1124,7 +1125,6 @@ struct ImGuiState // Render ImVector RenderDrawLists; - ImVector RenderSortedWindows; // Mouse cursor ImGuiMouseCursor MouseCursor; @@ -2034,7 +2034,7 @@ void ImGui::Shutdown() g.StyleModifiers.clear(); g.FontStack.clear(); g.RenderDrawLists.clear(); - g.RenderSortedWindows.clear(); + g.WindowsSortBuffer.clear(); g.MouseCursorDrawList.ClearFreeMemory(); g.ColorEditModeStorage.Clear(); if (g.PrivateClipboard) @@ -2142,18 +2142,18 @@ void ImGui::Render() // 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 - g.RenderSortedWindows.resize(0); - g.RenderSortedWindows.reserve(g.Windows.size()); + g.WindowsSortBuffer.resize(0); + g.WindowsSortBuffer.reserve(g.Windows.size()); for (size_t i = 0; i != g.Windows.size(); i++) { ImGuiWindow* window = g.Windows[i]; if (window->Flags & ImGuiWindowFlags_ChildWindow) // if a child is visible its parent will add it if (window->Visible) continue; - AddWindowToSortedBuffer(window, g.RenderSortedWindows); + AddWindowToSortedBuffer(window, g.WindowsSortBuffer); } - IM_ASSERT(g.Windows.size() == g.RenderSortedWindows.size()); // we done something wrong - g.Windows.swap(g.RenderSortedWindows); + IM_ASSERT(g.Windows.size() == g.WindowsSortBuffer.size()); // we done something wrong + g.Windows.swap(g.WindowsSortBuffer); // Clear data for next frame g.IO.MouseWheel = 0.0f; @@ -3311,9 +3311,15 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } if (window->Flags & ImGuiWindowFlags_Popup) { - if ((g.IO.MouseClicked[0] && (!g.HoveredWindow || g.HoveredWindow->RootWindow != window)) || (!g.FocusedWindow || g.FocusedWindow->RootWindow != window)) - if (p_opened) + if (p_opened) + { + if (g.IO.MouseClicked[0] && (!g.HoveredWindow || g.HoveredWindow->RootWindow != window)) *p_opened = false; + else if (!g.FocusedWindow) + *p_opened = false; + else if (g.FocusedWindow->RootWindow != window)// && !(g.FocusedWindow->RootWindow->Flags & ImGuiWindowFlags_Tooltip)) + *p_opened = false; + } } // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() From 93c9777165a81637f469965dc17a7e88377b1d3b Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 18:17:55 +0000 Subject: [PATCH 34/42] Fix for using tooltips within popup #126 - will need to rewrite the sorting/layering system shortly. --- imgui.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index cf3c9609..aa5dc04e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2174,6 +2174,7 @@ void ImGui::Render() } // Gather windows to render + // FIXME-OPT: Rework this in a more performance conscious way. g.RenderDrawLists.resize(0); for (size_t i = 0; i != g.Windows.size(); i++) { @@ -2184,7 +2185,13 @@ void ImGui::Render() for (size_t i = 0; i != g.Windows.size(); i++) { ImGuiWindow* window = g.Windows[i]; - if (window->Visible && (window->Flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup))) + if (window->Visible && (window->Flags & ImGuiWindowFlags_Popup) != 0) + AddWindowToRenderList(window); + } + for (size_t i = 0; i != g.Windows.size(); i++) + { + ImGuiWindow* window = g.Windows[i]; + if (window->Visible && (window->Flags & ImGuiWindowFlags_Tooltip) != 0) AddWindowToRenderList(window); } @@ -2992,7 +2999,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->Visible = true; // New windows appears in front - if (!(flags & ImGuiWindowFlags_ChildWindow)) + if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip)) + { if (window->LastFrameDrawn < current_frame - 1) { FocusWindow(window); @@ -3004,6 +3012,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->PosFloat = g.IO.MousePos; } } + } window->LastFrameDrawn = current_frame; window->ClipRectStack.resize(0); @@ -9461,11 +9470,13 @@ void ImGui::ShowTestWindow(bool* opened) { ImGui::BeginPopup(&popup_open); for (size_t i = 0; i < IM_ARRAYSIZE(fishes); i++) + { if (ImGui::Selectable(fishes[i], false)) { selected_fish = i; popup_open = false; } + } ImGui::EndPopup(); } ImGui::TreePop(); From f5ba64d8cd1209c01ba4ef47e9dd4a3c2584e23e Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 18:51:45 +0000 Subject: [PATCH 35/42] Sorting of windows for render doesn't do 3 pass stupidly. Made code a little closer to what it should become with a layering system --- imgui.cpp | 72 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index aa5dc04e..c8f998c9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1124,7 +1124,7 @@ struct ImGuiState ImGuiSetCond SetNextTreeNodeOpenedCond; // Render - ImVector RenderDrawLists; + ImVector RenderDrawLists[3]; // Mouse cursor ImGuiMouseCursor MouseCursor; @@ -1643,24 +1643,24 @@ void ImGuiWindow::FocusItemUnregister() FocusIdxTabCounter--; } -static inline void AddDrawListToRenderList(ImDrawList* draw_list) +static inline void AddDrawListToRenderList(ImVector& out_render_list, ImDrawList* draw_list) { if (!draw_list->commands.empty() && !draw_list->vtx_buffer.empty()) { if (draw_list->commands.back().vtx_count == 0) draw_list->commands.pop_back(); - GImGui->RenderDrawLists.push_back(draw_list); + out_render_list.push_back(draw_list); } } -static void AddWindowToRenderList(ImGuiWindow* window) +static void AddWindowToRenderList(ImVector& out_render_list, ImGuiWindow* window) { - AddDrawListToRenderList(window->DrawList); + AddDrawListToRenderList(out_render_list, window->DrawList); for (size_t i = 0; i < window->DC.ChildWindows.size(); i++) { ImGuiWindow* child = window->DC.ChildWindows[i]; if (child->Visible) // clipped children may have been marked not Visible - AddWindowToRenderList(child); + AddWindowToRenderList(out_render_list, child); } } @@ -2020,6 +2020,7 @@ void ImGui::Shutdown() ImGui::MemFree(g.Windows[i]); } g.Windows.clear(); + g.WindowsSortBuffer.clear(); g.CurrentWindowStack.clear(); g.FocusedWindow = NULL; g.HoveredWindow = NULL; @@ -2033,8 +2034,8 @@ void ImGui::Shutdown() g.ColorModifiers.clear(); g.StyleModifiers.clear(); g.FontStack.clear(); - g.RenderDrawLists.clear(); - g.WindowsSortBuffer.clear(); + for (size_t i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++) + g.RenderDrawLists[i].clear(); g.MouseCursorDrawList.ClearFreeMemory(); g.ColorEditModeStorage.Clear(); if (g.PrivateClipboard) @@ -2073,9 +2074,9 @@ static int ChildWindowComparer(const void* lhs, const void* rhs) return 0; } -static void AddWindowToSortedBuffer(ImGuiWindow* window, ImVector& sorted_windows) +static void AddWindowToSortedBuffer(ImVector& out_sorted_windows, ImGuiWindow* window) { - sorted_windows.push_back(window); + out_sorted_windows.push_back(window); if (window->Visible) { const size_t count = window->DC.ChildWindows.size(); @@ -2085,7 +2086,7 @@ static void AddWindowToSortedBuffer(ImGuiWindow* window, ImVector& { ImGuiWindow* child = window->DC.ChildWindows[i]; if (child->Visible) - AddWindowToSortedBuffer(child, sorted_windows); + AddWindowToSortedBuffer(out_sorted_windows, child); } } } @@ -2150,7 +2151,7 @@ void ImGui::Render() if (window->Flags & ImGuiWindowFlags_ChildWindow) // if a child is visible its parent will add it if (window->Visible) continue; - AddWindowToSortedBuffer(window, g.WindowsSortBuffer); + AddWindowToSortedBuffer(g.WindowsSortBuffer, window); } IM_ASSERT(g.Windows.size() == g.WindowsSortBuffer.size()); // we done something wrong g.Windows.swap(g.WindowsSortBuffer); @@ -2174,25 +2175,37 @@ void ImGui::Render() } // Gather windows to render - // FIXME-OPT: Rework this in a more performance conscious way. - g.RenderDrawLists.resize(0); + for (size_t i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++) + g.RenderDrawLists[i].resize(0); for (size_t i = 0; i != g.Windows.size(); i++) { ImGuiWindow* window = g.Windows[i]; - if (window->Visible && (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) == 0) - AddWindowToRenderList(window); + if (window->Visible && (window->Flags & (ImGuiWindowFlags_ChildWindow)) == 0) + { + // FIXME: Generalize this with a proper layering system so we can stack. + if (window->Flags & ImGuiWindowFlags_Popup) + AddWindowToRenderList(g.RenderDrawLists[1], window); + else if (window->Flags & ImGuiWindowFlags_Tooltip) + AddWindowToRenderList(g.RenderDrawLists[2], window); + else + AddWindowToRenderList(g.RenderDrawLists[0], window); + } } - for (size_t i = 0; i != g.Windows.size(); i++) + + // Flatten layers + size_t n = g.RenderDrawLists[0].size(); + size_t flattened_size = n; + for (size_t i = 1; i < IM_ARRAYSIZE(g.RenderDrawLists); i++) + flattened_size += g.RenderDrawLists[i].size(); + g.RenderDrawLists[0].resize(flattened_size); + for (size_t i = 1; i < IM_ARRAYSIZE(g.RenderDrawLists); i++) { - ImGuiWindow* window = g.Windows[i]; - if (window->Visible && (window->Flags & ImGuiWindowFlags_Popup) != 0) - AddWindowToRenderList(window); - } - for (size_t i = 0; i != g.Windows.size(); i++) - { - ImGuiWindow* window = g.Windows[i]; - if (window->Visible && (window->Flags & ImGuiWindowFlags_Tooltip) != 0) - AddWindowToRenderList(window); + ImVector& layer = g.RenderDrawLists[i]; + if (!layer.empty()) + { + memcpy(&g.RenderDrawLists[0][n], &layer[0], layer.size() * sizeof(ImDrawList*)); + n += layer.size(); + } } if (g.IO.MouseDrawCursor) @@ -2208,13 +2221,12 @@ void ImGui::Render() g.MouseCursorDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0xFF000000); // Black border g.MouseCursorDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], 0xFFFFFFFF); // White fill g.MouseCursorDrawList.PopTextureID(); - AddDrawListToRenderList(&g.MouseCursorDrawList); + AddDrawListToRenderList(g.RenderDrawLists[0], &g.MouseCursorDrawList); } // Render - if (!g.RenderDrawLists.empty()) - g.IO.RenderDrawListsFn(&g.RenderDrawLists[0], (int)g.RenderDrawLists.size()); - g.RenderDrawLists.resize(0); + if (!g.RenderDrawLists[0].empty()) + g.IO.RenderDrawListsFn(&g.RenderDrawLists[0][0], (int)g.RenderDrawLists[0].size()); } } From c6112550ebfedae96ca4f3486966bdbaaee94b14 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 19:02:54 +0000 Subject: [PATCH 36/42] Added Haddock in the (popup) Aquarium --- imgui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index c8f998c9..b27a3edf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9473,7 +9473,7 @@ void ImGui::ShowTestWindow(bool* opened) { static bool popup_open = false; static int selected_fish = -1; - const char* fishes[] = { "Bream", "Mackerel", "Pollock", "Tilefish" }; + const char* fishes[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" }; if (ImGui::Button("Select..")) popup_open = true; ImGui::SameLine(); @@ -9481,6 +9481,8 @@ void ImGui::ShowTestWindow(bool* opened) if (popup_open) { ImGui::BeginPopup(&popup_open); + ImGui::Text("Aquarium"); + ImGui::Separator(); for (size_t i = 0; i < IM_ARRAYSIZE(fishes); i++) { if (ImGui::Selectable(fishes[i], false)) From 4b7818dfc29d8fc7f460283ffe7a38fbf339b2ad Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 19:05:47 +0000 Subject: [PATCH 37/42] Bounding box tests exclude higher bound, so touching items (zero spacing) don't report double hover when cursor is on edge --- imgui.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index b27a3edf..cac1d6d1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -935,9 +935,9 @@ struct ImRect // 2D axis aligned bounding-box ImVec2 GetTR() const { return ImVec2(Max.x,Min.y); } ImVec2 GetBL() const { return ImVec2(Min.x,Max.y); } ImVec2 GetBR() const { return Max; } - bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x <= Max.x && p.y <= Max.y; } - bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; } - bool Overlaps(const ImRect& r) const { return r.Min.y <= Max.y && r.Max.y >= Min.y && r.Min.x <= Max.x && r.Max.x >= Min.x; } + bool Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x < Max.x && p.y < Max.y; } + bool Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x < Max.x && r.Max.y < Max.y; } + bool Overlaps(const ImRect& r) const { return r.Min.y < Max.y && r.Max.y > Min.y && r.Min.x < Max.x && r.Max.x > Min.x; } void Add(const ImVec2& rhs) { Min.x = ImMin(Min.x, rhs.x); Min.y = ImMin(Min.y, rhs.y); Max.x = ImMax(Max.x, rhs.x); Max.y = ImMax(Max.x, rhs.x); } void Add(const ImRect& rhs) { Min.x = ImMin(Min.x, rhs.Min.x); Min.y = ImMin(Min.y, rhs.Min.y); Max.x = ImMax(Max.x, rhs.Max.x); Max.y = ImMax(Max.y, rhs.Max.y); } void Expand(const float amount) { Min.x -= amount; Min.y -= amount; Max.x += amount; Max.y += amount; } From e1de4908f6af2743f40895b09e43dfd11f184006 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 19:18:06 +0000 Subject: [PATCH 38/42] Removed bool return value from BegniPopup() at the moment, it is meaningless. Tidying up. --- imgui.cpp | 13 +++++++------ imgui.h | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index cac1d6d1..df7fae6a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2742,8 +2742,8 @@ int ImGui::GetFrameCount() void ImGui::BeginTooltip() { ImGuiState& g = *GImGui; - ImGuiWindowFlags window_flags = ImGuiWindowFlags_Tooltip|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; - ImGui::Begin("##Tooltip", NULL, ImVec2(0,0), g.Style.Colors[ImGuiCol_TooltipBg].w, window_flags); + ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; + ImGui::Begin("##Tooltip", NULL, ImVec2(0,0), g.Style.Colors[ImGuiCol_TooltipBg].w, flags); } void ImGui::EndTooltip() @@ -2752,12 +2752,13 @@ void ImGui::EndTooltip() ImGui::End(); } -bool ImGui::BeginPopup(bool* p_opened) +void ImGui::BeginPopup(bool* p_opened) { IM_ASSERT(p_opened != NULL); // Must provide a bool at the moment + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); - bool ret = ImGui::Begin("##Popup", p_opened, ImGuiWindowFlags_Popup|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize); - return ret; + ImGuiWindowFlags flags = ImGuiWindowFlags_Popup|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize; + ImGui::Begin("##Popup", p_opened, flags); } void ImGui::EndPopup() @@ -9469,7 +9470,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::TreePop(); } - if (ImGui::TreeNode("Popup Menu")) + if (ImGui::TreeNode("Popup")) { static bool popup_open = false; static int selected_fish = -1; diff --git a/imgui.h b/imgui.h index 74eb1333..09defd79 100644 --- a/imgui.h +++ b/imgui.h @@ -225,7 +225,7 @@ namespace ImGui IMGUI_API void EndTooltip(); // Popup - IMGUI_API bool BeginPopup(bool* p_opened); + IMGUI_API void BeginPopup(bool* p_opened); IMGUI_API void EndPopup(); // Layout From bcd85e7cd6247b59e25b4439fabc8e0856ad2046 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 20:14:15 +0000 Subject: [PATCH 39/42] Auto contents size aware of enforced vertical scrollbar if window is large than display height. --- imgui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index df7fae6a..611c330a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3155,6 +3155,8 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ else { size_auto_fit = ImClamp(window->SizeContents + style.AutoFitPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - style.AutoFitPadding)); + if (size_auto_fit.y < window->SizeContents.y + style.AutoFitPadding.y) + size_auto_fit.x += style.ScrollbarWidth; } const float window_rounding = (window->Flags & ImGuiWindowFlags_ChildWindow) ? style.ChildWindowRounding : style.WindowRounding; @@ -9436,7 +9438,7 @@ void ImGui::ShowTestWindow(bool* opened) static bool selected[3] = { false, true, false }; ImGui::Selectable("1. I am selectable", &selected[0]); ImGui::Selectable("2. I am selectable", &selected[1]); - ImGui::Text("3. I am normal text"); + ImGui::Text("3. I am not selectable"); ImGui::Selectable("4. I am selectable", &selected[2]); ImGui::TreePop(); } From 729e5249552b39f418aa2edafb08cc4cd0063941 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 20:16:53 +0000 Subject: [PATCH 40/42] Version number 1.37 --- imgui.cpp | 2 +- imgui.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 611c330a..86b9f3d9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1,4 +1,4 @@ -// ImGui library v1.37 WIP +// ImGui library v1.37 // See ImGui::ShowTestWindow() for sample code. // Read 'Programmer guide' below for notes on how to setup ImGui in your codebase. // Get latest version at https://github.com/ocornut/imgui diff --git a/imgui.h b/imgui.h index 09defd79..a7c2311f 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// ImGui library v1.37 WIP +// ImGui library v1.37 // See .cpp file for documentation. // See ImGui::ShowTestWindow() for sample code. // Read 'Programmer guide' in .cpp for notes on how to setup ImGui in your codebase. @@ -13,7 +13,7 @@ #include // NULL, malloc, free, qsort, atoi #include // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp -#define IMGUI_VERSION "1.37 WIP" +#define IMGUI_VERSION "1.37" // Define assertion handler. #ifndef IM_ASSERT From a1582874d372280425796bddbcc175fbeef647bd Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 20:24:55 +0000 Subject: [PATCH 41/42] Changed new ImDrawList::AddLine() half_thickness to hickness, just in time for release --- imgui.cpp | 10 +++++----- imgui.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 86b9f3d9..b179ed92 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7555,10 +7555,10 @@ void ImDrawList::AddVtxUV(const ImVec2& pos, ImU32 col, const ImVec2& uv) } // NB: memory should be reserved for 6 vertices by the caller. -void ImDrawList::AddVtxLine(const ImVec2& a, const ImVec2& b, ImU32 col, float half_thickness) +void ImDrawList::AddVtxLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness) { const float inv_length = 1.0f / sqrtf(ImLengthSqr(b - a)); - const ImVec2 hn = (b - a) * (half_thickness * inv_length); // half normal + const ImVec2 hn = (b - a) * (thickness * 0.5f * inv_length);// half normal const ImVec2 hp0 = ImVec2(+hn.y, -hn.x); // half perpendiculars + user offset const ImVec2 hp1 = ImVec2(-hn.y, +hn.x); @@ -7571,13 +7571,13 @@ void ImDrawList::AddVtxLine(const ImVec2& a, const ImVec2& b, ImU32 col, float h AddVtx(a + hp1, col); } -void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float half_thickness) +void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness) { if ((col >> 24) == 0) return; ReserveVertices(6); - AddVtxLine(a, b, col, half_thickness); + AddVtxLine(a, b, col, thickness); } void ImDrawList::AddArc(const ImVec2& center, float rad, ImU32 col, int a_min, int a_max, bool tris, const ImVec2& third_point_offset) @@ -9715,7 +9715,7 @@ void ImGui::ShowTestWindow(bool* opened) // Draw a line between the button and the mouse cursor ImDrawList* draw_list = ImGui::GetWindowDrawList(); draw_list->PushClipRectFullScreen(); - draw_list->AddLine(ImGui::CalcItemRectClosestPoint(ImGui::GetIO().MousePos, true, -2.0f), ImGui::GetIO().MousePos, ImColor(ImGui::GetStyle().Colors[ImGuiCol_Button]), 2.0f); + draw_list->AddLine(ImGui::CalcItemRectClosestPoint(ImGui::GetIO().MousePos, true, -2.0f), ImGui::GetIO().MousePos, ImColor(ImGui::GetStyle().Colors[ImGuiCol_Button]), 4.0f); draw_list->PopClipRect(); } ImGui::SameLine(); ImGui::Text("Raw (%.1f, %.1f), WithLockThresold (%.1f, %.1f)", value_raw.x, value_raw.y, value_with_lock_threshold.x, value_with_lock_threshold.y); diff --git a/imgui.h b/imgui.h index a7c2311f..d914b6f6 100644 --- a/imgui.h +++ b/imgui.h @@ -895,7 +895,7 @@ struct ImDrawList IMGUI_API void PopTextureID(); // Primitives - IMGUI_API void AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float half_thickness = 0.50f); + IMGUI_API void AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness = 1.0f); IMGUI_API void AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners=0x0F); IMGUI_API void AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners=0x0F); IMGUI_API void AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col); @@ -913,7 +913,7 @@ struct ImDrawList 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, float half_thickness = 0.50f); + IMGUI_API void AddVtxLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness = 1.0f); IMGUI_API void UpdateClipRect(); IMGUI_API void UpdateTextureID(); }; From 2e26196aba66dc0fa304043764aa6f6499beee0f Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 26 Mar 2015 21:13:03 +0000 Subject: [PATCH 42/42] Selectable() fixed misuage of GetContentRegionMax().x --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index b179ed92..b6119acf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6603,7 +6603,7 @@ bool ImGui::Selectable(const char* label, bool selected, const ImVec2& size_arg) const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const float w = ImMax(label_size.x, window->Pos.x + ImGui::GetContentRegionMax().x - window->DC.CursorPos.x); + const float w = ImMax(label_size.x, window->Pos.x + ImGui::GetContentRegionMax().x - style.AutoFitPadding.x - window->DC.CursorPos.x); const ImVec2 size(size_arg.x != 0.0f ? size_arg.x : w, size_arg.y != 0.0f ? size_arg.y : label_size.y); const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); ItemSize(bb);