From 47826830afcc70d8086bf2f81bfafd6baa278ba7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 30 Jun 2015 13:40:13 -0600 Subject: [PATCH 01/12] Adding TitleBgActive color - still issues with popups/menus (#253) --- imgui.cpp | 6 ++++-- imgui.h | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c3625b33..2ffc39bf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -623,8 +623,9 @@ ImGuiStyle::ImGuiStyle() Colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.30f); // Background of checkbox, radio button, plot, slider, text input Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.90f, 0.80f, 0.80f, 0.40f); Colors[ImGuiCol_FrameBgActive] = ImVec4(0.90f, 0.65f, 0.65f, 0.45f); - Colors[ImGuiCol_TitleBg] = ImVec4(0.50f, 0.50f, 1.00f, 0.45f); + Colors[ImGuiCol_TitleBg] = ImVec4(0.50f, 0.50f, 1.00f, 0.40f); Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); + Colors[ImGuiCol_TitleBgActive] = ImVec4(0.50f, 0.50f, 1.00f, 0.55f); Colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.60f); Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.40f, 0.40f, 0.80f, 0.15f); Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f); @@ -3915,7 +3916,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) - window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color(ImGuiCol_TitleBg), window_rounding, 1|2); + window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color((g.FocusedWindow && window->RootWindow == g.FocusedWindow->RootWindow) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg), window_rounding, 1|2); // Menu bar if (flags & ImGuiWindowFlags_MenuBar) @@ -4413,6 +4414,7 @@ const char* ImGui::GetStyleColName(ImGuiCol idx) case ImGuiCol_FrameBgActive: return "FrameBgActive"; case ImGuiCol_TitleBg: return "TitleBg"; case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed"; + case ImGuiCol_TitleBgActive: return "TitleBgActive"; case ImGuiCol_MenuBarBg: return "MenuBarBg"; case ImGuiCol_ScrollbarBg: return "ScrollbarBg"; case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab"; diff --git a/imgui.h b/imgui.h index 51dcca92..cf8ff5f7 100644 --- a/imgui.h +++ b/imgui.h @@ -1,4 +1,4 @@ -// ImGui library v1.42 +// ImGui library v1.42 wip // 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. @@ -499,6 +499,7 @@ enum ImGuiCol_ ImGuiCol_FrameBgActive, ImGuiCol_TitleBg, ImGuiCol_TitleBgCollapsed, + ImGuiCol_TitleBgActive, ImGuiCol_MenuBarBg, ImGuiCol_ScrollbarBg, ImGuiCol_ScrollbarGrab, From c39372e7d5963d0aaf7b152bd3c912339fb2cee7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 30 Jun 2015 13:52:00 -0600 Subject: [PATCH 02/12] Title bar uses TitleBgActive color even when window has popups/menus over (#253) --- imgui.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2ffc39bf..974fd3f3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -623,7 +623,7 @@ ImGuiStyle::ImGuiStyle() Colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.30f); // Background of checkbox, radio button, plot, slider, text input Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.90f, 0.80f, 0.80f, 0.40f); Colors[ImGuiCol_FrameBgActive] = ImVec4(0.90f, 0.65f, 0.65f, 0.45f); - Colors[ImGuiCol_TitleBg] = ImVec4(0.50f, 0.50f, 1.00f, 0.40f); + Colors[ImGuiCol_TitleBg] = ImVec4(0.50f, 0.50f, 1.00f, 0.45f); Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f); Colors[ImGuiCol_TitleBgActive] = ImVec4(0.50f, 0.50f, 1.00f, 0.55f); Colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.60f); @@ -1441,6 +1441,7 @@ struct ImGuiWindow float FontWindowScale; // Scale multiplier per-window ImDrawList* DrawList; ImGuiWindow* RootWindow; + ImGuiWindow* RootNonPopupWindow; // Focus int FocusIdxAllCounter; // Start at -1 and increase as assigned via FocusItemRegister() @@ -1799,6 +1800,7 @@ ImGuiWindow::ImGuiWindow(const char* name) DrawList = (ImDrawList*)ImGui::MemAlloc(sizeof(ImDrawList)); new(DrawList) ImDrawList(); RootWindow = NULL; + RootNonPopupWindow = NULL; FocusIdxAllCounter = FocusIdxTabCounter = -1; FocusIdxAllRequestCurrent = FocusIdxTabRequestCurrent = IM_INT_MAX; @@ -3606,14 +3608,15 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } // Update known root window (if we are a child window, otherwise window == window->RootWindow) - size_t root_idx = g.CurrentWindowStack.size() - 1; - while (root_idx > 0) - { - if ((g.CurrentWindowStack[root_idx]->Flags & ImGuiWindowFlags_ChildWindow) == 0) + size_t root_idx, root_non_popup_idx; + for (root_idx = g.CurrentWindowStack.size() - 1; root_idx > 0; root_idx--) + if (!(g.CurrentWindowStack[root_idx]->Flags & ImGuiWindowFlags_ChildWindow)) + break; + for (root_non_popup_idx = root_idx; root_non_popup_idx > 0; root_non_popup_idx--) + if (!(g.CurrentWindowStack[root_non_popup_idx]->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) break; - root_idx--; - } window->RootWindow = g.CurrentWindowStack[root_idx]; + window->RootNonPopupWindow = g.CurrentWindowStack[root_non_popup_idx]; // This is merely for displaying the TitleBgActive color. // Default alpha if (bg_alpha < 0.0f) @@ -3916,7 +3919,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // Title bar if (!(flags & ImGuiWindowFlags_NoTitleBar)) - window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color((g.FocusedWindow && window->RootWindow == g.FocusedWindow->RootWindow) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg), window_rounding, 1|2); + window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), window->Color((g.FocusedWindow && window->RootNonPopupWindow == g.FocusedWindow->RootNonPopupWindow) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg), window_rounding, 1|2); // Menu bar if (flags & ImGuiWindowFlags_MenuBar) From b74d8e4c875b08cb61971b2d817f62c0b30d710b Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 1 Jul 2015 17:51:44 -0600 Subject: [PATCH 03/12] SetScrollPosHere() takes a y centering ratio and can be used to aim the top or bottom of the window (relate #150) --- imgui.cpp | 20 +++++++++++++------- imgui.h | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 974fd3f3..c4e6d5e0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1412,7 +1412,8 @@ struct ImGuiWindow ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame ImGuiID MoveID; // == window->GetID("#MOVE") float ScrollY; - float ScrollTargetCenterY; // position which we aim to center on + float ScrollTargetAbsY; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (-1.0f for no change) + float ScrollTargetCenterRatioY; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered bool ScrollbarY; bool Active; // Set to true on Begin() bool WasActive; @@ -1778,7 +1779,8 @@ ImGuiWindow::ImGuiWindow(const char* name) Size = SizeFull = ImVec2(0.0f, 0.0f); SizeContents = ImVec2(0.0f, 0.0f); ScrollY = 0.0f; - ScrollTargetCenterY = -1.0f; + ScrollTargetAbsY = -1.0f; + ScrollTargetCenterRatioY = 0.5f; ScrollbarY = false; Active = WasActive = false; Accessed = false; @@ -3836,10 +3838,11 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = IM_INT_MAX; // Apply scrolling - if (window->ScrollTargetCenterY >= 0.0f) + if (window->ScrollTargetAbsY >= 0.0f) { - window->ScrollY = window->ScrollTargetCenterY - (window->Pos.y + (window->SizeFull.y + window->TitleBarHeight() + window->WindowPadding().y) * 0.5f); - window->ScrollTargetCenterY = -1.0f; + float center_ratio_y = window->ScrollTargetCenterRatioY; + window->ScrollY = window->ScrollTargetAbsY - (window->Pos.y + (1.0f - center_ratio_y) * window->TitleBarHeight() + center_ratio_y * window->SizeFull.y); + window->ScrollTargetAbsY = -1.0f; } window->ScrollY = ImMax(window->ScrollY, 0.0f); if (!window->Collapsed && !window->SkipItems) @@ -4800,10 +4803,13 @@ float ImGui::GetScrollMaxY() return window->SizeContents.y - window->SizeFull.y; } -void ImGui::SetScrollPosHere() +void ImGui::SetScrollPosHere(float center_y_ratio) { + // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size + IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); ImGuiWindow* window = GetCurrentWindow(); - window->ScrollTargetCenterY = (float)(int)(window->DC.CursorPos.y + window->ScrollY - window->DC.PrevLineHeight * 0.5f); + window->ScrollTargetAbsY = (float)(int)(window->ScrollY + window->DC.CursorPosPrevLine.y + (window->DC.PrevLineHeight) * center_y_ratio); + window->ScrollTargetCenterRatioY = center_y_ratio; } void ImGui::SetKeyboardFocusHere(int offset) diff --git a/imgui.h b/imgui.h index cf8ff5f7..6905e778 100644 --- a/imgui.h +++ b/imgui.h @@ -138,7 +138,7 @@ namespace ImGui 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 SetScrollPosHere(float center_y_ratio = 0.5f); // adjust scrolling position to make the current cursor position visible. center_y_ratio=0.0: top, =0.5: center, =1.0: bottom. 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(); From 49b7a8e61f828ee6fcc01e463b650eebf70a4c14 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 1 Jul 2015 18:01:43 -0600 Subject: [PATCH 04/12] Added scroll tracking example with SetScrollPosHere() (relate #150) --- imgui.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index c4e6d5e0..50d0016d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -11461,6 +11461,32 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::TreePop(); } + + if (ImGui::TreeNode("Scrolling")) + { + ImGui::TextWrapped("Use SetScrollPosHere() to scroll to a given position."); + static bool track = true; + static int track_line = 50; + ImGui::Checkbox("Track", &track); + ImGui::SameLine(); ImGui::SliderInt("##line", &track_line, 0, 99, "Line %.0f"); + + for (int i = 0; i < 3; i++) + { + if (i > 0) ImGui::SameLine(); + ImGui::BeginGroup(); + ImGui::Text(i == 0 ? "Top" : i == 1 ? "Center" : "Bottom"); + ImGui::BeginChild(ImGui::GetID((void *)i), ImVec2(ImGui::GetWindowWidth() * 0.25f, 200.0f), true); + for (int line = 0; line < 100; line++) + { + ImGui::Text("Line %d", line); + if (track && line == track_line) + ImGui::SetScrollPosHere(i * 0.50f); // 0.0f,0.5f,1.0f + } + ImGui::EndChild(); + ImGui::EndGroup(); + } + ImGui::TreePop(); + } } if (ImGui::CollapsingHeader("Popups & Modal windows")) From 3d7b596a406f2bf121060c169b6d5f0d426b230b Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 1 Jul 2015 18:23:11 -0600 Subject: [PATCH 05/12] SetScrollToPosHere() fixed imprecision + handling lower gap better for bottom alignment (#150) --- imgui.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 50d0016d..c82ee8cd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1412,7 +1412,7 @@ struct ImGuiWindow ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame ImGuiID MoveID; // == window->GetID("#MOVE") float ScrollY; - float ScrollTargetAbsY; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (-1.0f for no change) + float ScrollTargetRelY; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (-1.0f for no change) float ScrollTargetCenterRatioY; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered bool ScrollbarY; bool Active; // Set to true on Begin() @@ -1779,7 +1779,7 @@ ImGuiWindow::ImGuiWindow(const char* name) Size = SizeFull = ImVec2(0.0f, 0.0f); SizeContents = ImVec2(0.0f, 0.0f); ScrollY = 0.0f; - ScrollTargetAbsY = -1.0f; + ScrollTargetRelY = -1.0f; ScrollTargetCenterRatioY = 0.5f; ScrollbarY = false; Active = WasActive = false; @@ -3838,11 +3838,11 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = IM_INT_MAX; // Apply scrolling - if (window->ScrollTargetAbsY >= 0.0f) + if (window->ScrollTargetRelY >= 0.0f) { float center_ratio_y = window->ScrollTargetCenterRatioY; - window->ScrollY = window->ScrollTargetAbsY - (window->Pos.y + (1.0f - center_ratio_y) * window->TitleBarHeight() + center_ratio_y * window->SizeFull.y); - window->ScrollTargetAbsY = -1.0f; + window->ScrollY = window->ScrollTargetRelY - ((1.0f - center_ratio_y) * window->TitleBarHeight()) - (center_ratio_y * window->SizeFull.y); + window->ScrollTargetRelY = -1.0f; } window->ScrollY = ImMax(window->ScrollY, 0.0f); if (!window->Collapsed && !window->SkipItems) @@ -4808,7 +4808,9 @@ void ImGui::SetScrollPosHere(float center_y_ratio) // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); ImGuiWindow* window = GetCurrentWindow(); - window->ScrollTargetAbsY = (float)(int)(window->ScrollY + window->DC.CursorPosPrevLine.y + (window->DC.PrevLineHeight) * center_y_ratio); + window->ScrollTargetRelY = (float)(int)(window->ScrollY + window->DC.CursorPosPrevLine.y - window->Pos.y + (window->DC.PrevLineHeight) * center_y_ratio); + float line_spacing = (window->DC.CursorPos.y - window->DC.CursorPosPrevLine.y) - (window->DC.PrevLineHeight); + window->ScrollTargetRelY += line_spacing * (center_y_ratio - 0.5f) * 2.0f; window->ScrollTargetCenterRatioY = center_y_ratio; } From 824cf5ae85e3b35f420abef0f15d00dd3580a553 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 1 Jul 2015 18:55:42 -0600 Subject: [PATCH 06/12] Fixed window padding being reported incorrectly for child windows with borders when parent have no borders --- imgui.cpp | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index c82ee8cd..0405e911 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1410,6 +1410,7 @@ struct ImGuiWindow ImVec2 Size; // Current size (==SizeFull or collapsed title bar size) ImVec2 SizeFull; // Size when non collapsed ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame + ImVec2 WindowPadding; // Window padding at the time of begin. We need to lock it, in particular manipulation of the ShowBorder would have an effect ImGuiID MoveID; // == window->GetID("#MOVE") float ScrollY; float ScrollTargetRelY; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (-1.0f for no change) @@ -1468,7 +1469,6 @@ public: ImRect TitleBarRect() const { return ImRect(Pos, Pos + ImVec2(SizeFull.x, TitleBarHeight())); } float MenuBarHeight() const { return (Flags & ImGuiWindowFlags_MenuBar) ? CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f : 0.0f; } ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); } - ImVec2 WindowPadding() const { return ((Flags & ImGuiWindowFlags_ChildWindow) && !(Flags & (ImGuiWindowFlags_ShowBorders | ImGuiWindowFlags_ComboBox | ImGuiWindowFlags_Popup))) ? ImVec2(0,0) : GImGui->Style.WindowPadding; } float ScrollbarWidth() const { return ScrollbarY ? GImGui->Style.ScrollbarWidth : 0.0f; } ImU32 Color(ImGuiCol idx, float a=1.f) const { ImVec4 c = GImGui->Style.Colors[idx]; c.w *= GImGui->Style.Alpha * a; return ImGui::ColorConvertFloat4ToU32(c); } ImU32 Color(const ImVec4& col) const { ImVec4 c = col; c.w *= GImGui->Style.Alpha; return ImGui::ColorConvertFloat4ToU32(c); } @@ -1778,6 +1778,7 @@ ImGuiWindow::ImGuiWindow(const char* name) PosFloat = Pos = ImVec2(0.0f, 0.0f); Size = SizeFull = ImVec2(0.0f, 0.0f); SizeContents = ImVec2(0.0f, 0.0f); + WindowPadding = ImVec2(0.0f, 0.0f); ScrollY = 0.0f; ScrollTargetRelY = -1.0f; ScrollTargetCenterRatioY = 0.5f; @@ -3694,17 +3695,19 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } } + // Lock window padding so that altering the ShowBorders flag for childs doesn't have side-effects. + window->WindowPadding = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_ShowBorders | ImGuiWindowFlags_ComboBox | ImGuiWindowFlags_Popup))) ? ImVec2(0,0) : style.WindowPadding; + // Calculate auto-fit size ImVec2 size_auto_fit; - ImVec2 window_padding = window->WindowPadding(); if ((flags & ImGuiWindowFlags_Tooltip) != 0) { // Tooltip always resize. We keep the spacing symmetric on both axises for aesthetic purpose. - size_auto_fit = window->SizeContents + window_padding - ImVec2(0.0f, style.ItemSpacing.y); + size_auto_fit = window->SizeContents + window->WindowPadding - ImVec2(0.0f, style.ItemSpacing.y); } else { - size_auto_fit = ImClamp(window->SizeContents + window_padding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - window_padding)); + size_auto_fit = ImClamp(window->SizeContents + window->WindowPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - window->WindowPadding)); if (size_auto_fit.y < window->SizeContents.y && !(flags & ImGuiWindowFlags_NoScrollbar)) size_auto_fit.x += style.ScrollbarWidth; size_auto_fit.y = ImMax(size_auto_fit.y - style.ItemSpacing.y, 0.0f); @@ -3965,9 +3968,9 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ } // Setup drawing context - window->DC.ColumnsStartX = window->WindowPadding().x; + window->DC.ColumnsStartX = window->WindowPadding.x; window->DC.ColumnsOffsetX = 0.0f; - window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.ColumnsStartX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding().y) - ImVec2(0.0f, window->ScrollY); + window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.ColumnsStartX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y) - ImVec2(0.0f, window->ScrollY); window->DC.CursorPos = window->DC.CursorStartPos; window->DC.CursorPosPrevLine = window->DC.CursorPos; window->DC.CursorMaxPos = window->DC.CursorStartPos; @@ -4041,7 +4044,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, const ImVec2& size_on_first_ // 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+window->MenuBarHeight()+0.5f, window->Rect().Max.x+0.5f-window->WindowPadding().x*0.5f, window->Rect().Max.y-1.5f); + ImVec4 clip_rect(title_bar_rect.Min.x+0.5f+window->WindowPadding.x*0.5f, title_bar_rect.Max.y+window->MenuBarHeight()+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; PushClipRect(clip_rect); @@ -4668,12 +4671,11 @@ void ImGui::SetNextWindowFocus() ImVec2 ImGui::GetContentRegionMax() { ImGuiWindow* window = GetCurrentWindow(); - ImVec2 window_padding = window->WindowPadding(); - ImVec2 mx = window->Size - window_padding; + ImVec2 mx = window->Size - window->WindowPadding; if (window->DC.ColumnsCount != 1) { mx.x = ImGui::GetColumnOffset(window->DC.ColumnsCurrent + 1); - mx.x -= window_padding.x; + mx.x -= window->WindowPadding.x; } else { @@ -4685,13 +4687,13 @@ ImVec2 ImGui::GetContentRegionMax() ImVec2 ImGui::GetWindowContentRegionMin() { ImGuiWindow* window = GetCurrentWindow(); - return ImVec2(0, window->TitleBarHeight() + window->MenuBarHeight()) + window->WindowPadding(); + return ImVec2(0, window->TitleBarHeight() + window->MenuBarHeight()) + window->WindowPadding; } ImVec2 ImGui::GetWindowContentRegionMax() { ImGuiWindow* window = GetCurrentWindow(); - ImVec2 m = window->Size - window->WindowPadding(); + ImVec2 m = window->Size - window->WindowPadding; m.x -= window->ScrollbarWidth(); return m; } @@ -5455,7 +5457,7 @@ bool ImGui::CollapsingHeader(const char* label, const char* str_id, bool display } // Framed header expand a little outside the default padding - const ImVec2 window_padding = window->WindowPadding(); + const ImVec2 window_padding = window->WindowPadding; const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 pos_min = window->DC.CursorPos; const ImVec2 pos_max = window->Pos + GetContentRegionMax(); @@ -7752,7 +7754,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl ItemSize(bb); // Fill horizontal space. - ImVec2 window_padding = window->WindowPadding(); + ImVec2 window_padding = window->WindowPadding; float max_x = (flags & ImGuiSelectableFlags_SpanAllColumns) ? ImGui::GetWindowContentRegionMax().x : ImGui::GetContentRegionMax().x; float w_draw = ImMax(label_size.x, window->Pos.x + max_x - window_padding.x - window->DC.CursorPos.x); ImVec2 size_draw((size_arg.x != 0 && !(flags & ImGuiSelectableFlags_DrawFillAvailWidth)) ? size_arg.x : w_draw, size_arg.y != 0.0f ? size_arg.y : size.y); @@ -8031,7 +8033,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) ImVec2 popup_pos, pos = window->DC.CursorPos; if (window->DC.LayoutType == ImGuiLayoutType_Horizontal) { - popup_pos = ImVec2(pos.x - window->WindowPadding().x, pos.y - style.FramePadding.y + window->MenuBarHeight()); + 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); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f); float w = label_size.x; From 0e5b64ecd2e291eac3475e10ab8aa1fa773a3a03 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 1 Jul 2015 19:01:27 -0600 Subject: [PATCH 07/12] SetScrollPosHere() Minor hack for effective "scroll to top" to appear like user expect it (#150) Compensate the difference between WindowPadding and ItemSpacing --- imgui.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0405e911..78be5fec 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4808,11 +4808,13 @@ float ImGui::GetScrollMaxY() void ImGui::SetScrollPosHere(float center_y_ratio) { // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size + ImGuiState& g = *GImGui; IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f); ImGuiWindow* window = GetCurrentWindow(); window->ScrollTargetRelY = (float)(int)(window->ScrollY + window->DC.CursorPosPrevLine.y - window->Pos.y + (window->DC.PrevLineHeight) * center_y_ratio); - float line_spacing = (window->DC.CursorPos.y - window->DC.CursorPosPrevLine.y) - (window->DC.PrevLineHeight); - window->ScrollTargetRelY += line_spacing * (center_y_ratio - 0.5f) * 2.0f; + window->ScrollTargetRelY += g.Style.ItemSpacing.y * (center_y_ratio - 0.5f) * 2.0f; + if (center_y_ratio <= 0.0f && window->ScrollTargetRelY <= window->WindowPadding.y) // Minor hack to make "scroll to top" take account of WindowPadding, else it would scroll to (WindowPadding.y - ItemSpacing.y) + window->ScrollTargetRelY = 0.0f; window->ScrollTargetCenterRatioY = center_y_ratio; } From 57f70a29b20cb6e0a1b3805aaab61c94ec83fc61 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 2 Jul 2015 07:42:29 -0600 Subject: [PATCH 08/12] Fixed a bug with TextUnformatted() clipping of long text (#257) --- imgui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 78be5fec..ce7add0d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4934,11 +4934,11 @@ void ImGui::TextUnformatted(const char* text, const char* text_end) // Lines to skip (can't skip when logging text) if (!g.LogEnabled) { - int lines_skippable = (int)((clip_rect.y - text_pos.y) / line_height) - 1; + int lines_skippable = (int)((clip_rect.y - text_pos.y) / line_height); if (lines_skippable > 0) { int lines_skipped = 0; - while (line < text_end && lines_skipped <= lines_skippable) + while (line < text_end && lines_skipped < lines_skippable) { const char* line_end = strchr(line, '\n'); line = line_end + 1; From fc7b562635ab893cdedfa8066841f8b5c8f8814e Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 2 Jul 2015 08:16:23 -0600 Subject: [PATCH 09/12] Added font links courtesy of twitter + instructions for fonts compressed in C array --- extra_fonts/README.txt | 45 ++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/extra_fonts/README.txt b/extra_fonts/README.txt index c3a9e7a3..da10e6bb 100644 --- a/extra_fonts/README.txt +++ b/extra_fonts/README.txt @@ -2,6 +2,30 @@ The code in imgui.cpp embeds a copy of 'ProggyClean.ttf' that you can use without any external files. Those are only provided as a convenience, you can load your own .TTF files. +--------------------------------- + LINKS +--------------------------------- + + Typefaces for source code beautification + https://github.com/chrissimpkins/codeface + + Proggy Programming Fonts + http://upperbounds.net + + Inconsolata + http://www.levien.com/type/myfonts/inconsolata.html + + Adobe Source Code Pro: Monospaced font family for user interface and coding environments + https://github.com/adobe-fonts/source-code-pro + + Monospace/Fixed Width Programmer's Fonts + http://www.lowing.org/fonts/ + + (Japanese) M+ fonts by Coji Morishita are free and include most useful Kanjis you would need. + http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/index-en.html + + Or use Arial Unicode or other Unicode fonts provided with Windows for full characters coverage (not sure of their licensing). + --------------------------------- INCLUDED FONTS --------------------------------- @@ -25,20 +49,6 @@ Copyright (c) 2012, Jonathan Pinhorn SIL OPEN FONT LICENSE Version 1.1 ---------------------------------- - OTHER FONTS ---------------------------------- - - For Japanese: - - M+ fonts by Coji Morishita are free and include most useful Kanjis you would need. - mplus-fonts.sourceforge.jp/mplus-outline-fonts/index-en.html - - For Japanese, Chinese, Korean: - - You can use Arial Unicode or other Unicode fonts provided with Windows (not sure of their license). - Other suggestions? - --------------------------------- LOADING INSTRUCTIONS --------------------------------- @@ -54,8 +64,13 @@ io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, io.Fonts->GetGlyphRangesJapanese()); // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, io.Fonts->GetGlyphRangesChinese()); // Include full set of about 21000 CJK Unified Ideographs -Offset font by altering the io.Font->DisplayOffset value: + Offset font vertically by altering the io.Font->DisplayOffset value: ImFont* font = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_pixels); font->DisplayOffset.y += 1; // Render 1 pixel down + If you want to embed the font in source code (e.g. in your engine, so it doesn't have file-system dependencies); + Compile and use 'binary_to_compressed_c.cpp' to create a compressed C style array. Then load the font with: + + ImFont* font = io.Fonts->AddFontFromMemoryCompressedTTF(compressed_data, compressed_data_size, size_pixels, ...); + From eaaab0120a97a95d15c37183fcdcefcafa447785 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 2 Jul 2015 08:57:17 -0600 Subject: [PATCH 10/12] Moved Inputs utilities to their own section in imgui.h + additional comments --- imgui.h | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/imgui.h b/imgui.h index 6905e778..9c27dd6e 100644 --- a/imgui.h +++ b/imgui.h @@ -353,23 +353,7 @@ namespace ImGui IMGUI_API bool IsRootWindowFocused(); // is current root window focused (top parent window in case of child windows) IMGUI_API bool IsRootWindowOrAnyChildFocused(); // is current root window or any of its child (including current window) focused IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle of given size starting from cursor pos is visible (not clipped). to perform coarse clipping on user's side (as an optimization) - IMGUI_API bool IsKeyDown(int key_index); // key_index into the keys_down[512] array, imgui doesn't know the semantic of each entry, uses your own indices! - IMGUI_API bool IsKeyPressed(int key_index, bool repeat = true); // " - IMGUI_API bool IsKeyReleased(int key_index); // " - IMGUI_API bool IsMouseDown(int button); - IMGUI_API bool IsMouseClicked(int button, bool repeat = false); - IMGUI_API bool IsMouseDoubleClicked(int button); - IMGUI_API bool IsMouseReleased(int button); - 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 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 since clicking, also see: GetItemActiveDragDelta(). if lock_threshold < -1.0f uses io.MouseDraggingThreshold - IMGUI_API void ResetMouseDragDelta(int button = 0); - 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); @@ -384,6 +368,24 @@ namespace ImGui IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v); IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b); + // Inputs + IMGUI_API bool IsKeyDown(int key_index); // key_index into the keys_down[512] array, imgui doesn't know the semantic of each entry, uses your own indices! + IMGUI_API bool IsKeyPressed(int key_index, bool repeat = true); // if repeat=true. uses io.KeyRepeatDelay / KeyRepeatRate + IMGUI_API bool IsKeyReleased(int key_index); // " + IMGUI_API bool IsMouseDown(int button); // is mouse button held + IMGUI_API bool IsMouseClicked(int button, bool repeat = false); // did mouse button clicked (went from !Down to Down) + IMGUI_API bool IsMouseDoubleClicked(int button); // did mouse button double-clicked. a double-click returns false in IsMouseClicked(). uses io.MouseDoubleClickTime. + IMGUI_API bool IsMouseReleased(int button); // did mouse button released (went from Down to !Down) + 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 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 since clicking, also see: GetItemActiveDragDelta(). if lock_threshold < -1.0f uses io.MouseDraggingThreshold + IMGUI_API void ResetMouseDragDelta(int button = 0); + 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 + // Helpers functions to access the MemAllocFn/MemFreeFn pointers in ImGui::GetIO() IMGUI_API void* MemAlloc(size_t sz); IMGUI_API void MemFree(void* ptr); From 77fad80e9f367c37cf308cf3d12aaeb7ac91eb4b Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 2 Jul 2015 09:10:31 -0600 Subject: [PATCH 11/12] Added CaptureInputsFromApp() to manually enforce e.g. keyboard capturing --- imgui.cpp | 18 ++++++++++++++++-- imgui.h | 3 ++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index ce7add0d..59992268 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1333,6 +1333,8 @@ struct ImGuiState float FramerateSecPerFrame[120]; // calculate estimate of framerate for user int FramerateSecPerFrameIdx; float FramerateSecPerFrameAccum; + bool CaptureMouseNextFrame; // explicit capture via CaptureInputs() sets those flags + bool CaptureKeyboardNextFrame; char TempBuffer[1024*3+1]; // temporary text buffer ImGuiState() @@ -1394,6 +1396,7 @@ struct ImGuiState memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame)); FramerateSecPerFrameIdx = 0; FramerateSecPerFrameAccum = 0.0f; + CaptureMouseNextFrame = CaptureKeyboardNextFrame = false; } }; @@ -2189,9 +2192,10 @@ void ImGui::NewFrame() mouse_earliest_button_down = i; } 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) || (!mouse_owned_by_application && mouse_any_down) || (g.ActiveId != 0) || (!g.OpenedPopupStack.empty()); - g.IO.WantCaptureKeyboard = (g.ActiveId != 0); + g.IO.WantCaptureMouse = (!mouse_owned_by_application && g.HoveredWindow != NULL) || (!mouse_owned_by_application && mouse_any_down) || (g.ActiveId != 0) || (!g.OpenedPopupStack.empty()) || (g.CaptureMouseNextFrame); + g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (g.CaptureKeyboardNextFrame); g.MouseCursor = ImGuiMouseCursor_Arrow; + g.CaptureMouseNextFrame = g.CaptureKeyboardNextFrame = false; // If mouse was first clicked outside of ImGui bounds we also cancel out hovering. if (mouse_owned_by_application) @@ -3003,6 +3007,12 @@ void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) GImGui->MouseCursor = cursor_type; } +void ImGui::CaptureInputsFromApp(bool capture_mouse, bool capture_keyboard) +{ + GImGui->CaptureMouseNextFrame |= capture_mouse; + GImGui->CaptureKeyboardNextFrame |= capture_keyboard; +} + bool ImGui::IsItemHovered() { ImGuiWindow* window = GetCurrentWindow(); @@ -11857,6 +11867,10 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Text("WantCaptureMouse: %s", io.WantCaptureMouse ? "true" : "false"); ImGui::Text("WantCaptureKeyboard: %s", io.WantCaptureKeyboard ? "true" : "false"); + ImGui::Button("Hover me\nto enforce\ninputs capture"); + if (ImGui::IsItemHovered()) + ImGui::CaptureInputsFromApp(); + ImGui::TreePop(); } diff --git a/imgui.h b/imgui.h index 9c27dd6e..52255db0 100644 --- a/imgui.h +++ b/imgui.h @@ -382,9 +382,10 @@ 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 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 since clicking, also see: GetItemActiveDragDelta(). if lock_threshold < -1.0f uses io.MouseDraggingThreshold - IMGUI_API void ResetMouseDragDelta(int button = 0); + IMGUI_API void ResetMouseDragDelta(int button = 0); // 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 void CaptureInputsFromApp(bool mouse = true, bool keyboard = true); // manually enforce imgui setting the io.WantCaptureMouse / io.WantCaptureKeyboard flags next frame (your application needs to handle them). e.g. capture keyboard when your widget is being hovered. // Helpers functions to access the MemAllocFn/MemFreeFn pointers in ImGui::GetIO() IMGUI_API void* MemAlloc(size_t sz); From e0da1e06584869c150f3d82084b3d36e9cd51dce Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 2 Jul 2015 09:20:15 -0600 Subject: [PATCH 12/12] Split into CaptureKeyboardFromApp() / CaptureMouseFromApp() --- imgui.cpp | 12 ++++++++---- imgui.h | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 59992268..4645d2b3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3007,10 +3007,14 @@ void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type) GImGui->MouseCursor = cursor_type; } -void ImGui::CaptureInputsFromApp(bool capture_mouse, bool capture_keyboard) +void ImGui::CaptureKeyboardFromApp() { - GImGui->CaptureMouseNextFrame |= capture_mouse; - GImGui->CaptureKeyboardNextFrame |= capture_keyboard; + GImGui->CaptureKeyboardNextFrame = true; +} + +void ImGui::CaptureMouseFromApp() +{ + GImGui->CaptureMouseNextFrame = true; } bool ImGui::IsItemHovered() @@ -11869,7 +11873,7 @@ void ImGui::ShowTestWindow(bool* opened) ImGui::Button("Hover me\nto enforce\ninputs capture"); if (ImGui::IsItemHovered()) - ImGui::CaptureInputsFromApp(); + ImGui::CaptureKeyboardFromApp(); ImGui::TreePop(); } diff --git a/imgui.h b/imgui.h index 52255db0..4e12ba47 100644 --- a/imgui.h +++ b/imgui.h @@ -385,7 +385,8 @@ namespace ImGui IMGUI_API void ResetMouseDragDelta(int button = 0); // 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 void CaptureInputsFromApp(bool mouse = true, bool keyboard = true); // manually enforce imgui setting the io.WantCaptureMouse / io.WantCaptureKeyboard flags next frame (your application needs to handle them). e.g. capture keyboard when your widget is being hovered. + IMGUI_API void CaptureKeyboardFromApp(); // manually enforce imgui setting the io.WantCaptureKeyboard flag next frame (your application needs to handle it). e.g. capture keyboard when your widget is being hovered. + IMGUI_API void CaptureMouseFromApp(); // manually enforce imgui setting the io.WantCaptureMouse flag next frame (your application needs to handle it). // Helpers functions to access the MemAllocFn/MemFreeFn pointers in ImGui::GetIO() IMGUI_API void* MemAlloc(size_t sz);