From 8828889d5ec1d8fb9ddb72bab16d5e21ba8425c6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 7 Aug 2016 20:05:24 +0200 Subject: [PATCH] Refactored rare transient bool stacks into a set of flags, added unexposed ImGuiItemFlags_SelectableDontClosePopup (#323) --- imgui.cpp | 60 +++++++++++++++++++++++++++++------------------- imgui_internal.h | 24 ++++++++++++------- 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 7e3d690f3..1b5c5f024 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2111,7 +2111,7 @@ bool ImGui::ItemAdd(const ImRect& bb, const ImGuiID* id, const ImRect* nav_bb_ar { const ImRect& nav_bb = nav_bb_arg ? *nav_bb_arg : bb; const ImRect nav_bb_rel(nav_bb.Min - g.NavWindow->Pos, nav_bb.Max - g.NavWindow->Pos); - if (g.NavInitDefaultRequest && g.NavLayer == window->DC.NavLayerCurrent && window->DC.AllowNavDefaultFocus) + if (g.NavInitDefaultRequest && g.NavLayer == window->DC.NavLayerCurrent && (window->DC.ItemFlags & ImGuiItemFlags_AllowNavDefaultFocus)) { g.NavInitDefaultRequest = g.NavInitDefaultResultExplicit = false; // Clear flag immediately, first item gets default, also simplify the if() in ItemAdd() g.NavInitDefaultResultId = *id; @@ -2186,7 +2186,7 @@ bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop { ImGuiContext& g = *GImGui; - const bool allow_keyboard_focus = window->DC.AllowKeyboardFocus; + const bool allow_keyboard_focus = (window->DC.ItemFlags & ImGuiItemFlags_AllowKeyboardFocus) != 0; window->FocusIdxAllCounter++; if (allow_keyboard_focus) window->FocusIdxTabCounter++; @@ -5027,14 +5027,12 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; window->DC.ChildWindows.resize(0); window->DC.LayoutType = ImGuiLayoutType_Vertical; + window->DC.ItemFlags = ImGuiItemFlags_Default_; window->DC.ItemWidth = window->ItemWidthDefault; window->DC.TextWrapPos = -1.0f; // disabled - window->DC.AllowKeyboardFocus = window->DC.AllowNavDefaultFocus = true; - window->DC.ButtonRepeat = false; + window->DC.ItemFlagsStack.resize(0); window->DC.ItemWidthStack.resize(0); window->DC.TextWrapPosStack.resize(0); - window->DC.AllowKeyboardFocusStack.resize(0); - window->DC.ButtonRepeatStack.resize(0); window->DC.ColorEditMode = ImGuiColorEditMode_UserSelect; window->DC.ColumnsCurrent = 0; window->DC.ColumnsCount = 1; @@ -5045,6 +5043,12 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us window->DC.GroupStack.resize(0); window->MenuColumns.Update(3, style.ItemSpacing.x, !window_was_active); + if ((flags & ImGuiWindowFlags_ChildWindow) && (window->DC.ItemFlags != parent_window->DC.ItemFlags)) + { + window->DC.ItemFlags = parent_window->DC.ItemFlags; + window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags); + } + if (window->AutoFitFramesX > 0) window->AutoFitFramesX--; if (window->AutoFitFramesY > 0) @@ -5062,9 +5066,9 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us if (!(flags & ImGuiWindowFlags_NoTitleBar)) { // Close & collapse button are on layer 1 (same as menus) and don't default focus - const bool backup_allow_nav_default_focus = window->DC.AllowNavDefaultFocus; + const ImGuiItemFlags backup_item_options = window->DC.ItemFlags; if (window->Flags & ImGuiWindowFlags_MenuBar) - window->DC.AllowNavDefaultFocus = false; + window->DC.ItemFlags &= ~ImGuiItemFlags_AllowNavDefaultFocus; window->DC.NavLayerCurrent++; // Close button @@ -5090,7 +5094,7 @@ bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_us } window->DC.NavLayerCurrent--; - window->DC.AllowNavDefaultFocus = backup_allow_nav_default_focus; + window->DC.ItemFlags = backup_item_options; // Title text (FIXME: refactor text alignment facilities along with RenderText helpers) ImVec2 text_min = window->Pos + style.FramePadding; @@ -5402,32 +5406,41 @@ void ImGui::PopFont() SetCurrentFont(g.FontStack.empty() ? g.IO.Fonts->Fonts[0] : g.FontStack.back()); } -void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus) +void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled) { ImGuiWindow* window = GetCurrentWindow(); - window->DC.AllowKeyboardFocus = allow_keyboard_focus; - window->DC.AllowKeyboardFocusStack.push_back(allow_keyboard_focus); + if (enabled) + window->DC.ItemFlags |= option; + else + window->DC.ItemFlags &= ~option; + window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags); +} + +void ImGui::PopItemFlag() +{ + ImGuiWindow* window = GetCurrentWindow(); + window->DC.ItemFlagsStack.pop_back(); + window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back(); +} + +void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus) +{ + PushItemFlag(ImGuiItemFlags_AllowKeyboardFocus, allow_keyboard_focus); } void ImGui::PopAllowKeyboardFocus() { - ImGuiWindow* window = GetCurrentWindow(); - window->DC.AllowKeyboardFocusStack.pop_back(); - window->DC.AllowKeyboardFocus = window->DC.AllowKeyboardFocusStack.empty() ? true : window->DC.AllowKeyboardFocusStack.back(); + PopItemFlag(); } void ImGui::PushButtonRepeat(bool repeat) { - ImGuiWindow* window = GetCurrentWindow(); - window->DC.ButtonRepeat = repeat; - window->DC.ButtonRepeatStack.push_back(repeat); + PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); } void ImGui::PopButtonRepeat() { - ImGuiWindow* window = GetCurrentWindow(); - window->DC.ButtonRepeatStack.pop_back(); - window->DC.ButtonRepeat = window->DC.ButtonRepeatStack.empty() ? false : window->DC.ButtonRepeatStack.back(); + PopItemFlag(); } void ImGui::PushTextWrapPos(float wrap_pos_x) @@ -5507,7 +5520,6 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, float val) *pvar = val; } - void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val) { ImGuiContext& g = *GImGui; @@ -6413,7 +6425,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags if (!ItemAdd(bb, &id)) return false; - if (window->DC.ButtonRepeat) flags |= ImGuiButtonFlags_Repeat; + if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat) flags |= ImGuiButtonFlags_Repeat; bool hovered, held; bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); @@ -9481,7 +9493,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor(); // Automatically close popups - if (pressed && !(flags & ImGuiSelectableFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) + if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !((window->DC.ItemFlags & ImGuiItemFlags_SelectableDontClosePopup))) CloseCurrentPopup(); return pressed; } diff --git a/imgui_internal.h b/imgui_internal.h index 647adde39..f726d2a2e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -47,6 +47,7 @@ typedef int ImGuiLayoutType; // enum ImGuiLayoutType_ typedef int ImGuiButtonFlags; // enum ImGuiButtonFlags_ typedef int ImGuiTreeNodeFlags; // enum ImGuiTreeNodeFlags_ typedef int ImGuiSliderFlags; // enum ImGuiSliderFlags_ +typedef int ImGuiItemFlags; // enum ImGuiItemFlags_ //------------------------------------------------------------------------- // STB libraries @@ -574,6 +575,16 @@ struct ImGuiContext } }; +// Transient per-window flags, reset at the beginning of the frame. For child window, inherited from parent on first Begin(). +enum ImGuiItemFlags_ +{ + ImGuiItemFlags_AllowKeyboardFocus = 1 << 0, // [true] + ImGuiItemFlags_AllowNavDefaultFocus = 1 << 1, // [true] + ImGuiItemFlags_ButtonRepeat = 1 << 2, // [false] // Button() can be held will a repeat behavior + ImGuiItemFlags_SelectableDontClosePopup = 1 << 3, // [false] // MenuItem/Selectable() automatically closes owner Popup window + ImGuiItemFlags_Default_ = ImGuiItemFlags_AllowKeyboardFocus|ImGuiItemFlags_AllowNavDefaultFocus +}; + // Transient per-window data, reset at the beginning of the frame // FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiDrawContext is quite tenuous and could be reconsidered. struct IMGUI_API ImGuiDrawContext @@ -602,15 +613,12 @@ struct IMGUI_API ImGuiDrawContext ImGuiLayoutType LayoutType; // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings. + ImGuiItemFlags ItemFlags; // == ItemFlagsStack.back() [empty == ImGuiItemFlags_Default] float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f] - bool AllowKeyboardFocus; // == AllowKeyboardFocusStack.back() [empty == true] - bool AllowNavDefaultFocus; // (not exposed via stack) - bool ButtonRepeat; // == ButtonRepeatStack.back() [empty == false] + ImVectorItemFlagsStack; ImVector ItemWidthStack; ImVector TextWrapPosStack; - ImVector AllowKeyboardFocusStack; - ImVector ButtonRepeatStack; ImVectorGroupStack; ImGuiColorEditMode ColorEditMode; int StackSizesBackup[6]; // Store size of various stacks for asserting @@ -647,8 +655,7 @@ struct IMGUI_API ImGuiDrawContext StateStorage = NULL; LayoutType = ImGuiLayoutType_Vertical; ItemWidth = 0.0f; - ButtonRepeat = false; - AllowKeyboardFocus = AllowNavDefaultFocus = true; + ItemFlags = ImGuiItemFlags_Default_; TextWrapPos = -1.0f; ColorEditMode = ImGuiColorEditMode_RGB; memset(StackSizesBackup, 0, sizeof(StackSizesBackup)); @@ -782,8 +789,9 @@ namespace ImGui IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y); IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x); + IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); + IMGUI_API void PopItemFlag(); IMGUI_API void OpenPopupEx(const char* str_id, bool reopen_existing); - IMGUI_API int CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate); // NB: All position are in absolute pixels coordinates (not window coordinates)