diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 6c01be76..da8b6ee4 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -37,11 +37,13 @@ Breaking Changes: - Removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor `io.OptResizeWindowsFromEdges=true` to enable the feature globally. (#1495) The feature is not currently enabled by default because it is not satisfying enough. + - Style: Renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete). Other Changes: - ArrowButton: Fixed to honor PushButtonRepeat() setting (and internals' ImGuiItemFlags_ButtonRepeat). - ArrowButton: Setup current line text baseline so that ArrowButton() + SameLine() + Text() are aligned properly. + - Nav: Added a CTRL+TAB window list and changed the highlight system accordingly. This is designed to allow CTRL+TAB between Tabs in the future. - Window: Allow menu and popups windows from ignoring the style.WindowMinSize values so short menus/popups are not padded. (#1909) - Window: Added global io.OptResizeWindowsFromEdges option to enable resizing windows from their edges and from the lower-left corner. (#1495) - Drag and Drop: Fixed an incorrect assert when dropping a source that is submitted after the target (bug introduced with 1.62 changes diff --git a/imgui.cpp b/imgui.cpp index 79ba2619..5a268e5f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -305,6 +305,7 @@ When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete). - 2018/07/06 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.OptResizeWindowsFromEdges to enable the feature. - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set. - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details. @@ -896,6 +897,7 @@ static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& static void NavUpdate(); static void NavUpdateWindowing(); +static void NavUpdateWindowingList(); static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id); static void UpdateMouseInputs(); @@ -3051,7 +3053,8 @@ static void NavUpdateWindowingHighlightWindow(int focus_change_dir) ImGuiWindow* window_target = FindWindowNavigable(i_current + focus_change_dir, -INT_MAX, focus_change_dir); if (!window_target) window_target = FindWindowNavigable((focus_change_dir < 0) ? (g.Windows.Size - 1) : 0, i_current, focus_change_dir); - g.NavWindowingTarget = window_target; + if (window_target) // Don't reset windowing target if there's a single window in the list + g.NavWindowingTarget = window_target; g.NavWindowingToggleLayer = false; } @@ -3136,7 +3139,7 @@ static void ImGui::NavUpdateWindowing() { const float NAV_MOVE_SPEED = 800.0f; const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't code variable framerate very well - g.NavWindowingTarget->Pos += move_delta * move_speed; + g.NavWindowingTarget->RootWindow->Pos += move_delta * move_speed; g.NavDisableMouseHover = true; MarkIniSettingsDirty(g.NavWindowingTarget); } @@ -3178,6 +3181,46 @@ static void ImGui::NavUpdateWindowing() } } +// Window has already passed the IsWindowNavFocusable() +static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window) +{ + if (window->Flags & ImGuiWindowFlags_Popup) + return "(Popup)"; + if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0) + return "(Main menu bar)"; + return "(Untitled)"; +} + +// Overlay displayed when using CTRL+TAB. Called by EndFrame(). +void ImGui::NavUpdateWindowingList() +{ + ImGuiContext& g = *GImGui; + if (!g.NavWindowingTarget) + { + g.NavWindowingList = NULL; + return; + } + + if (g.NavWindowingList == NULL) + g.NavWindowingList = FindWindowByName("###NavWindowList"); + SetNextWindowSizeConstraints(ImVec2(g.IO.DisplaySize.x * 0.20f, g.IO.DisplaySize.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX)); + SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f); + Begin("###NavWindowList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize); + for (int n = g.Windows.Size - 1; n >= 0; n--) + { + ImGuiWindow* window = g.Windows[n]; + if (!IsWindowNavFocusable(window)) + continue; + const char* label = window->Name; + if (label == FindRenderedTextEnd(label)) + label = GetFallbackWindowNameForWindowingList(window); + Selectable(label, g.NavWindowingTarget == window); + } + End(); + PopStyleVar(); +} + // Scroll to keep newly navigated item fully into view // NB: We modify rect_rel by the amount we scrolled for, so it is immediately updated. static void NavScrollToBringItemIntoView(ImGuiWindow* window, const ImRect& item_rect) @@ -3590,6 +3633,11 @@ void ImGui::UpdateMovingWindow() } } +static bool IsWindowActiveAndVisible(ImGuiWindow* window) +{ + return (window->HiddenFrames == 0) && (window->Active); +} + static void ImGui::UpdateMouseInputs() { ImGuiContext& g = *GImGui; @@ -3820,10 +3868,10 @@ void ImGui::NewFrame() UpdateHoveredWindowAndCaptureFlags(); // Background darkening/whitening - if (GetFrontMostPopupModal() != NULL) - g.ModalWindowDarkeningRatio = ImMin(g.ModalWindowDarkeningRatio + g.IO.DeltaTime * 6.0f, 1.0f); + if (GetFrontMostPopupModal() != NULL || g.NavWindowingTarget != NULL) + g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f); else - g.ModalWindowDarkeningRatio = 0.0f; + g.DimBgRatio = 0.0f; g.MouseCursor = ImGuiMouseCursor_Arrow; g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1; @@ -4333,6 +4381,8 @@ void ImGui::EndFrame() g.PlatformImeLastPos = g.PlatformImePos; } + NavUpdateWindowingList(); + // Hide implicit "Debug" window if it hasn't been used IM_ASSERT(g.CurrentWindowStack.Size == 1); // Mismatched Begin()/End() calls, did you forget to call end on g.CurrentWindow->Name? if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed) @@ -4421,15 +4471,18 @@ void ImGui::Render() // Gather windows to render g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = g.IO.MetricsActiveWindows = 0; g.DrawDataBuilder.Clear(); - ImGuiWindow* window_to_render_front_most = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget : NULL; + ImGuiWindow* windows_to_render_front_most[2]; + windows_to_render_front_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL; + windows_to_render_front_most[1] = (g.NavWindowingList); for (int n = 0; n != g.Windows.Size; n++) { ImGuiWindow* window = g.Windows[n]; - if (window->Active && window->HiddenFrames == 0 && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != window_to_render_front_most) + if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_front_most[0] && window != windows_to_render_front_most[1]) AddWindowToDrawDataSelectLayer(window); } - if (window_to_render_front_most && window_to_render_front_most->Active && window_to_render_front_most->HiddenFrames == 0) // NavWindowingTarget is always temporarily displayed as the front-most window - AddWindowToDrawDataSelectLayer(window_to_render_front_most); + for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_front_most); n++) + if (windows_to_render_front_most[n] && IsWindowActiveAndVisible(windows_to_render_front_most[n])) // NavWindowingTarget is always temporarily displayed as the front-most window + AddWindowToDrawDataSelectLayer(windows_to_render_front_most[n]); g.DrawDataBuilder.FlattenIntoSingleLayer(); // Draw software mouse cursor if requested @@ -6032,7 +6085,7 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au PopID(); // Navigation resize (keyboard/gamepad) - if (g.NavWindowingTarget == window) + if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window) { ImVec2 nav_resize_delta; if (g.NavInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift) @@ -6391,23 +6444,29 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) else PushClipRect(viewport_rect.Min, viewport_rect.Max, true); - // Draw modal window background (darkens what is behind them) - if ((flags & ImGuiWindowFlags_Modal) != 0 && window == GetFrontMostPopupModal()) - window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, GetColorU32(ImGuiCol_ModalWindowDarkening, g.ModalWindowDarkeningRatio)); + // Draw modal window background (darkens what is behind them, all viewports) + const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetFrontMostPopupModal() && window->HiddenFrames <= 0; + const bool dim_bg_for_window_list = g.NavWindowingTarget && (window == g.NavWindowingTarget->RootWindow); + if (dim_bg_for_modal || dim_bg_for_window_list) + { + const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowListDimBg, g.DimBgRatio); + window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, dim_bg_col); + } // Draw navigation selection/windowing rectangle background - if (g.NavWindowingTarget == window) + if (dim_bg_for_window_list && window == g.NavWindowingTarget->RootWindow) { ImRect bb = window->Rect(); bb.Expand(g.FontSize); if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway - window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding); + window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowListHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding); } // Draw window + handle manual resize const float window_rounding = window->WindowRounding; const float window_border_size = window->WindowBorderSize; - const bool title_bar_is_highlight = want_focus || (g.NavWindow && window->RootWindowForTitleBarHighlight == g.NavWindow->RootWindowForTitleBarHighlight); + const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow; + const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight); const ImRect title_bar_rect = window->TitleBarRect(); if (window->Collapsed) { @@ -6487,7 +6546,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) bb.Expand(-g.FontSize - 1.0f); rounding = window->WindowRounding; } - window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f); + window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowListHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f); } // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars. @@ -7181,10 +7240,10 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx) case ImGuiCol_PlotHistogram: return "PlotHistogram"; case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered"; case ImGuiCol_TextSelectedBg: return "TextSelectedBg"; - case ImGuiCol_ModalWindowDarkening: return "ModalWindowDarkening"; case ImGuiCol_DragDropTarget: return "DragDropTarget"; case ImGuiCol_NavHighlight: return "NavHighlight"; - case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight"; + case ImGuiCol_NavWindowListDimBg: return "NavWindowListDimBg"; + case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg"; } IM_ASSERT(0); return "Unknown"; diff --git a/imgui.h b/imgui.h index b9e3a6d2..da21e833 100644 --- a/imgui.h +++ b/imgui.h @@ -892,15 +892,17 @@ enum ImGuiCol_ ImGuiCol_PlotHistogram, ImGuiCol_PlotHistogramHovered, ImGuiCol_TextSelectedBg, - ImGuiCol_ModalWindowDarkening, // Darken/colorize entire screen behind a modal window, when one is active ImGuiCol_DragDropTarget, ImGuiCol_NavHighlight, // Gamepad/keyboard: current highlighted item - ImGuiCol_NavWindowingHighlight, // Gamepad/keyboard: when holding NavMenu to focus/move/resize windows + ImGuiCol_NavWindowListHighlight,// Highlight window when using CTRL+TAB + ImGuiCol_NavWindowListDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active + ImGuiCol_ModalWindowDimBg, // Darken/colorize entire screen behind a modal window, when one is active ImGuiCol_COUNT // Obsolete names (will be removed) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS , ImGuiCol_ChildWindowBg = ImGuiCol_ChildBg, ImGuiCol_Column = ImGuiCol_Separator, ImGuiCol_ColumnHovered = ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive = ImGuiCol_SeparatorActive + , ImGuiCol_ModalWindowDarkening = ImGuiCol_ModalWindowDimBg //ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered, // [unused since 1.60+] the close button now uses regular button colors. //ImGuiCol_ComboBg, // [unused since 1.53+] ComboBg has been merged with PopupBg, so a redirect isn't accurate. #endif diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 99d6ab14..f33a3a47 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1860,7 +1860,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::OpenPopup("Stacked 1"); if (ImGui::BeginPopupModal("Stacked 1")) { - ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDarkening] for darkening."); + ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it."); static int item = 1; ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0"); static float color[4] = { 0.4f,0.7f,0.0f,0.5f }; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index dfb8bb4b..5d741819 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -194,10 +194,11 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst) colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); - colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); - colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowListHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowListDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); } void ImGui::StyleColorsClassic(ImGuiStyle* dst) @@ -243,10 +244,11 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst) colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); - colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; - colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowListHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); + colors[ImGuiCol_NavWindowListDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); } // Those light colors are better suited with a thicker font than the default one + FrameBorder @@ -293,10 +295,11 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst) colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f); colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); - colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f); colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered]; - colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f); + colors[ImGuiCol_NavWindowListHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f); + colors[ImGuiCol_NavWindowListDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.20f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); } //----------------------------------------------------------------------------- diff --git a/imgui_internal.h b/imgui_internal.h index b7c7f07a..d336b154 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -659,6 +659,7 @@ struct ImGuiContext ImRect NavScoringRectScreen; // Rectangle used for scoring, in screen space. Based of window->DC.NavRefRectRel[], modified for directional navigation scoring. int NavScoringCount; // Metrics for debugging ImGuiWindow* NavWindowingTarget; // When selecting a window (holding Menu+FocusPrev/Next, or equivalent of CTRL-TAB) this window is temporarily displayed front-most. + ImGuiWindow* NavWindowingList; float NavWindowingHighlightTimer; float NavWindowingHighlightAlpha; bool NavWindowingToggleLayer; @@ -686,7 +687,7 @@ struct ImGuiContext // Render ImDrawData DrawData; // Main ImDrawData instance to pass render information to the user ImDrawDataBuilder DrawDataBuilder; - float ModalWindowDarkeningRatio; + float DimBgRatio; // 0.0..1.0 animation when fading in a dimming background (for modal window and CTRL+TAB list) ImDrawList OverlayDrawList; // Optional software render of mouse cursors, if io.MouseDrawCursor is set + a few debug overlays ImGuiMouseCursor MouseCursor; @@ -787,7 +788,7 @@ struct ImGuiContext NavInputSource = ImGuiInputSource_None; NavScoringRectScreen = ImRect(); NavScoringCount = 0; - NavWindowingTarget = NULL; + NavWindowingTarget = NavWindowingList = NULL; NavWindowingHighlightTimer = NavWindowingHighlightAlpha = 0.0f; NavWindowingToggleLayer = false; NavLayer = 0; @@ -806,7 +807,7 @@ struct ImGuiContext NavMoveRequestForward = ImGuiNavForward_None; NavMoveDir = NavMoveDirLast = NavMoveClipDir = ImGuiDir_None; - ModalWindowDarkeningRatio = 0.0f; + DimBgRatio = 0.0f; OverlayDrawList._Data = &DrawListSharedData; OverlayDrawList._OwnerName = "##Overlay"; // Give it a name for debugging MouseCursor = ImGuiMouseCursor_Arrow;