From 27fd1b913b7cbf1eafdffe6a6539a21776171cdf Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 15 Nov 2017 14:35:45 +0100 Subject: [PATCH 1/6] Made it guaranteed by API that after calling Begin() the last Item represent the title bar. (#823) --- imgui.cpp | 5 +++++ imgui_demo.cpp | 11 ++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index f0808585..eef43a4f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4589,6 +4589,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x; window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y; //window->DrawList->AddRect(window->InnerRect.Min, window->InnerRect.Max, IM_COL32_WHITE); + + // After Begin() we fill the last item / hovered data using the title bar data. Make that a standard behavior (to allow usage of context menus on title bar only, etc.). + window->DC.LastItemId = window->MoveId; + window->DC.LastItemRect = title_bar_rect; + window->DC.LastItemRectHoveredRect = IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false); } // Inner clipping rectangle diff --git a/imgui_demo.cpp b/imgui_demo.cpp index d9ccad31..c627f5bd 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -2406,6 +2406,15 @@ struct ExampleAppConsole return; } + // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. So e.g. IsItemHovered() will return true when hovering the title bar. + // Here we create a context menu only available from the title bar. + if (ImGui::BeginPopupContextItem()) + { + if (ImGui::MenuItem("Close")) + *p_open = false; + ImGui::EndPopup(); + } + ImGui::TextWrapped("This example implements a console with basic coloring, completion and history. A more elaborate implementation may want to store entries along with extra data such as timestamp, emitter, etc."); ImGui::TextWrapped("Enter 'HELP' for help, press TAB to use text completion."); @@ -2850,7 +2859,7 @@ static void ShowExampleAppLongText(bool* p_open) static ImGuiTextBuffer log; static int lines = 0; ImGui::Text("Printing unusually long amount of text."); - ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped\0"); + ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped (slow)\0"); ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size()); if (ImGui::Button("Clear")) { log.clear(); lines = 0; } ImGui::SameLine(); From 5ea6e80da155e45d7e94b917966adb85fe992e3c Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 15 Nov 2017 22:20:40 +0100 Subject: [PATCH 2/6] Make it possible to use SetNextWindowPos() on a child window. Useful internally. --- imgui.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index eef43a4f..f52505bf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4293,7 +4293,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->SizeFull = CalcSizeFullWithConstraint(window, window->SizeFull); window->Size = window->Collapsed ? window->TitleBarRect().GetSize() : window->SizeFull; if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup)) + { + IM_ASSERT(window_size_set_by_api); // Submitted by BeginChild() window->Size = window->SizeFull; + } // SCROLLBAR STATUS @@ -4316,11 +4319,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->OrderWithinParent = parent_window->DC.ChildWindows.Size; parent_window->DC.ChildWindows.push_back(window); } - if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup)) - { - IM_ASSERT(window_size_set_by_api); // Submitted by BeginChild() + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api) window->Pos = window->PosFloat = parent_window->DC.CursorPos; - } const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFrames == 0); if (window_pos_with_pivot) From f5bdf443c9436c3585537bd6637a4bbbaa6be26f Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 15 Nov 2017 22:37:43 +0100 Subject: [PATCH 3/6] Minor comments, tweaks --- imgui.cpp | 9 ++------- imgui.h | 4 ++-- imgui_draw.cpp | 37 +++++++++++++++++++------------------ 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index f52505bf..1a5ac52c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1375,13 +1375,8 @@ void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, int* //----------------------------------------------------------------------------- // ImGuiStorage -//----------------------------------------------------------------------------- - // Helper: Key->value storage -void ImGuiStorage::Clear() -{ - Data.clear(); -} +//----------------------------------------------------------------------------- // std::lower_bound but without the bullshit static ImVector::iterator LowerBound(ImVector& data, ImGuiID key) @@ -1651,7 +1646,7 @@ void ImGuiTextBuffer::append(const char* fmt, ...) } //----------------------------------------------------------------------------- -// ImGuiSimpleColumns +// ImGuiSimpleColumns (internal use only) //----------------------------------------------------------------------------- ImGuiSimpleColumns::ImGuiSimpleColumns() diff --git a/imgui.h b/imgui.h index 162ded07..42098322 100644 --- a/imgui.h +++ b/imgui.h @@ -1050,7 +1050,7 @@ struct ImGuiStorage { ImGuiID key; union { int val_i; float val_f; void* val_p; }; - Pair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; } + Pair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; } Pair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; } Pair(ImGuiID _key, void* _val_p) { key = _key; val_p = _val_p; } }; @@ -1059,7 +1059,7 @@ struct ImGuiStorage // - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N) // - Set***() functions find pair, insertion on demand if missing. // - Sorted insertion is costly, paid once. A typical frame shouldn't need to insert any new pair. - IMGUI_API void Clear(); + void Clear() { Data.clear(); } IMGUI_API int GetInt(ImGuiID key, int default_val = 0) const; IMGUI_API void SetInt(ImGuiID key, int val); IMGUI_API bool GetBool(ImGuiID key, bool default_val = false) const; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index cea66452..1b173e85 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -264,7 +264,7 @@ void ImDrawList::ClearFreeMemory() _Channels.clear(); } -// Use macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug mode +// Using macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug builds #define GetCurrentClipRect() (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1] : GNullClipRect) #define GetCurrentTextureId() (_TextureIdStack.Size ? _TextureIdStack.Data[_TextureIdStack.Size-1] : NULL) @@ -388,7 +388,7 @@ void ImDrawList::ChannelsSplit(int channels_count) _Channels.resize(channels_count); _ChannelsCount = channels_count; - // _Channels[] (24 bytes each) hold storage that we'll swap with this->_CmdBuffer/_IdxBuffer + // _Channels[] (24/32 bytes each) hold storage that we'll swap with this->_CmdBuffer/_IdxBuffer // The content of _Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to. // When we switch to the next channel, we'll copy _CmdBuffer/_IdxBuffer into _Channels[0] and then _Channels[1] into _CmdBuffer/_IdxBuffer memset(&_Channels[0], 0, sizeof(ImDrawChannel)); @@ -1208,7 +1208,7 @@ ImFontConfig::ImFontConfig() const int FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF = 90; const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27; const unsigned int FONT_ATLAS_DEFAULT_TEX_DATA_ID = 0x80000000; -const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] = +static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] = { "..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX" "..- -X.....X- X.X - X.X -X.....X - X.....X" @@ -1239,6 +1239,19 @@ const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF " - XX XX - " }; +static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_Count_][3] = +{ + // Pos ........ Size ......... Offset ...... + { ImVec2(0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow + { 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 + { ImVec2(73,0), ImVec2(17,17), ImVec2( 9, 9) }, // ImGuiMouseCursor_ResizeNESW + { ImVec2(55,0), ImVec2(17,17), ImVec2( 9, 9) }, // ImGuiMouseCursor_ResizeNWSE +}; + + ImFontAtlas::ImFontAtlas() { TexID = NULL; @@ -1784,26 +1797,14 @@ static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) atlas->TexUvWhitePixel = ImVec2((r.X + 0.5f) * tex_uv_scale.x, (r.Y + 0.5f) * tex_uv_scale.y); // Setup mouse cursors - const ImVec2 cursor_datas[ImGuiMouseCursor_Count_][3] = - { - // Pos ........ Size ......... Offset ...... - { ImVec2(0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow - { 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 - { 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]; + ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[type][0] + ImVec2((float)r.X, (float)r.Y); + const ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[type][1]; cursor_data.Type = type; cursor_data.Size = size; - cursor_data.HotOffset = cursor_datas[type][2]; + cursor_data.HotOffset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[type][2]; cursor_data.TexUvMin[0] = (pos) * tex_uv_scale; cursor_data.TexUvMax[0] = (pos + size) * tex_uv_scale; pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1; From 9b82d9fbef1f8897503c035fe73753ab5557be67 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 15 Nov 2017 23:11:36 +0100 Subject: [PATCH 4/6] Scrollbar: Minor graphical fix for when scrollbar don't have enough visible space to display the full grab. --- imgui.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1a5ac52c..5b907ac9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4782,10 +4782,12 @@ void ImGui::Scrollbar(ImGuiLayoutType direction) // Render const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab); + ImRect grab_rect; if (horizontal) - window->DrawList->AddRectFilled(ImVec2(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y), ImVec2(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, bb.Max.y), grab_col, style.ScrollbarRounding); + grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImMin(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, window_rect.Max.x), bb.Max.y); else - window->DrawList->AddRectFilled(ImVec2(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm)), ImVec2(bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels), grab_col, style.ScrollbarRounding); + grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImMin(ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels, window_rect.Max.y)); + window->DrawList->AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding); } // Moving window to front of display (which happens to be back of our sorted list) From f36037b3845d45c445e75688b66bc4c85032dee6 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 15 Nov 2017 23:38:17 +0100 Subject: [PATCH 5/6] Menu: Fixed minor rendering issues on the right size with rounded window when resizing a window small. --- imgui.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 5b907ac9..19eeda3a 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9187,10 +9187,12 @@ bool ImGui::BeginMenuBar() if (!(window->Flags & ImGuiWindowFlags_MenuBar)) return false; + ImGuiContext& g = *GImGui; IM_ASSERT(!window->DC.MenuBarAppending); BeginGroup(); // Save position PushID("##menubar"); ImRect rect = window->MenuBarRect(); + rect.Max.x = ImMax(rect.Min.x, rect.Max.x - g.Style.WindowRounding); PushClipRect(ImVec2(ImFloor(rect.Min.x+0.5f), ImFloor(rect.Min.y + window->BorderSize + 0.5f)), ImVec2(ImFloor(rect.Max.x+0.5f), ImFloor(rect.Max.y+0.5f)), false); window->DC.CursorPos = ImVec2(rect.Min.x + window->DC.MenuBarOffsetX, rect.Min.y);// + g.Style.FramePadding.y); window->DC.LayoutType = ImGuiLayoutType_Horizontal; @@ -9241,6 +9243,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) { // Menu inside an horizontal menu bar // Selectable extend their highlight by half ItemSpacing in each direction. + // For ChildMenu, the popup position will be overwritten by the call to FindBestPopupWindowPos() in Begin() popup_pos = ImVec2(pos.x - window->WindowPadding.x, pos.y - style.FramePadding.y + window->MenuBarHeight()); window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f); PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); From e9a7e73bbaacec886f9b39130428b81b7f95bf16 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 15 Nov 2017 23:42:18 +0100 Subject: [PATCH 6/6] Windows with MenuBar have a larger minimum height to avoid artefacts (I fixed most of the vertical/horizontal artefacts, but the ones in rounded corners were too hard to fix). --- imgui.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 19eeda3a..088012bb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4012,7 +4012,10 @@ static ImVec2 CalcSizeFullWithConstraint(ImGuiWindow* window, ImVec2 new_size) } } if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize))) + { new_size = ImMax(new_size, g.Style.WindowMinSize); + new_size.y = ImMax(new_size.y, window->TitleBarHeight() + window->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows + } return new_size; }