mirror of
				https://github.com/ocornut/imgui.git
				synced 2025-10-26 12:27:30 +00:00 
			
		
		
		
	Windows, Internal: added experimental SkipRefresh mode. (#3515, #4763, #7556, #5116 , #4076, #2749, #2268)
currently: ImGui::SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags_TryToAvoidRefresh); - This is NOT meant to replace frame-wide/app-wide idle mode. - This is another tool: the idea that a given window could avoid refresh and reuse last frame contents. - I think it needs to be backed by a careful and smart design overall (refresh policy, load balancing, making it easy and obvious to user). - It's not there yet, this is currently a toy for experimenting. My other issues with this: - It appears to be very simple, but skipping most of Begin() logic will inevitably lead to tricky/confusing bugs. Let's see how it goes. - I don't like very much that this opens a door to varying inconsistencies - I don't like very much that it can lead us to situation where the lazy refresh gets disabled in bulk due to some reason (e.g. resizing a dock space) and we get sucked in the temptation to update for idle rather than update for dynamism.
This commit is contained in:
		
							
								
								
									
										60
									
								
								imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								imgui.cpp
									
									
									
									
									
								
							| @@ -6334,6 +6334,30 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // [EXPERIMENTAL] Called by Begin(). NextWindowData is valid at this point. | ||||||
|  | // This is designed as a toy/test-bed for | ||||||
|  | void ImGui::UpdateWindowSkipRefresh(ImGuiWindow* window) | ||||||
|  | { | ||||||
|  |     ImGuiContext& g = *GImGui; | ||||||
|  |     window->SkipRefresh = false; | ||||||
|  |     if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasRefreshPolicy) == 0) | ||||||
|  |         return; | ||||||
|  |     if (g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_TryToAvoidRefresh) | ||||||
|  |     { | ||||||
|  |         // FIXME-IDLE: Tests for e.g. mouse clicks or keyboard while focused. | ||||||
|  |         if (window->Appearing) // If currently appearing | ||||||
|  |             return; | ||||||
|  |         if (window->Hidden) // If was hidden (previous frame) | ||||||
|  |             return; | ||||||
|  |         if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnHover) && g.HoveredWindow && window->RootWindow == g.HoveredWindow->RootWindow) | ||||||
|  |             return; | ||||||
|  |         if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnFocus) && g.NavWindow && window->RootWindow == g.NavWindow->RootWindow) | ||||||
|  |             return; | ||||||
|  |         window->DrawList = NULL; | ||||||
|  |         window->SkipRefresh = true; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| // When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing) | // When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing) | ||||||
| // should be positioned behind that modal window, unless the window was created inside the modal begin-stack. | // should be positioned behind that modal window, unless the window was created inside the modal begin-stack. | ||||||
| // In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent. | // In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent. | ||||||
| @@ -6532,11 +6556,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) | |||||||
|     if (window->Appearing) |     if (window->Appearing) | ||||||
|         SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false); |         SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false); | ||||||
|  |  | ||||||
|  |     // [EXPERIMENTAL] Skip Refresh mode | ||||||
|  |     UpdateWindowSkipRefresh(window); | ||||||
|  |  | ||||||
|     // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow() |     // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow() | ||||||
|     g.CurrentWindow = NULL; |     g.CurrentWindow = NULL; | ||||||
|  |  | ||||||
|     // When reusing window again multiple times a frame, just append content (don't need to setup again) |     // When reusing window again multiple times a frame, just append content (don't need to setup again) | ||||||
|     if (first_begin_of_the_frame) |     if (first_begin_of_the_frame && !window->SkipRefresh) | ||||||
|     { |     { | ||||||
|         // Initialize |         // Initialize | ||||||
|         const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345) |         const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345) | ||||||
| @@ -7027,12 +7054,17 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) | |||||||
|     } |     } | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
|  |         // Skip refresh always mark active | ||||||
|  |         if (window->SkipRefresh) | ||||||
|  |             window->Active = true; | ||||||
|  |  | ||||||
|         // Append |         // Append | ||||||
|         SetCurrentWindow(window); |         SetCurrentWindow(window); | ||||||
|         SetLastItemDataForWindow(window, window->TitleBarRect()); |         SetLastItemDataForWindow(window, window->TitleBarRect()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); |     if (!window->SkipRefresh) | ||||||
|  |         PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true); | ||||||
|  |  | ||||||
|     // Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused) |     // Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused) | ||||||
|     window->WriteAccessed = false; |     window->WriteAccessed = false; | ||||||
| @@ -7040,7 +7072,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) | |||||||
|     g.NextWindowData.ClearFlags(); |     g.NextWindowData.ClearFlags(); | ||||||
|  |  | ||||||
|     // Update visibility |     // Update visibility | ||||||
|     if (first_begin_of_the_frame) |     if (first_begin_of_the_frame && !window->SkipRefresh) | ||||||
|     { |     { | ||||||
|         if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ChildMenu)) |         if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_ChildMenu)) | ||||||
|         { |         { | ||||||
| @@ -7086,6 +7118,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) | |||||||
|                 skip_items = true; |                 skip_items = true; | ||||||
|         window->SkipItems = skip_items; |         window->SkipItems = skip_items; | ||||||
|     } |     } | ||||||
|  |     else if (first_begin_of_the_frame) | ||||||
|  |     { | ||||||
|  |         // Skip refresh mode | ||||||
|  |         window->SkipItems = true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // [DEBUG] io.ConfigDebugBeginReturnValue override return value to test Begin/End and BeginChild/EndChild behaviors. |     // [DEBUG] io.ConfigDebugBeginReturnValue override return value to test Begin/End and BeginChild/EndChild behaviors. | ||||||
|     // (The implicit fallback window is NOT automatically ended allowing it to always be able to receive commands without crashing) |     // (The implicit fallback window is NOT automatically ended allowing it to always be able to receive commands without crashing) | ||||||
| @@ -7128,9 +7165,16 @@ void ImGui::End() | |||||||
|     // Close anything that is open |     // Close anything that is open | ||||||
|     if (window->DC.CurrentColumns) |     if (window->DC.CurrentColumns) | ||||||
|         EndColumns(); |         EndColumns(); | ||||||
|     PopClipRect();   // Inner window clip rectangle |     if (!window->SkipRefresh) | ||||||
|  |         PopClipRect();   // Inner window clip rectangle | ||||||
|     PopFocusScope(); |     PopFocusScope(); | ||||||
|  |  | ||||||
|  |     if (window->SkipRefresh) | ||||||
|  |     { | ||||||
|  |         IM_ASSERT(window->DrawList == NULL); | ||||||
|  |         window->DrawList = &window->DrawListInst; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // Stop logging |     // Stop logging | ||||||
|     if (!(window->Flags & ImGuiWindowFlags_ChildWindow))    // FIXME: add more options for scope of logging |     if (!(window->Flags & ImGuiWindowFlags_ChildWindow))    // FIXME: add more options for scope of logging | ||||||
|         LogFinish(); |         LogFinish(); | ||||||
| @@ -7815,6 +7859,14 @@ void ImGui::SetNextWindowBgAlpha(float alpha) | |||||||
|     g.NextWindowData.BgAlphaVal = alpha; |     g.NextWindowData.BgAlphaVal = alpha; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // This is experimental and meant to be a toy for exploring a future/wider range of features. | ||||||
|  | void ImGui::SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags) | ||||||
|  | { | ||||||
|  |     ImGuiContext& g = *GImGui; | ||||||
|  |     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasRefreshPolicy; | ||||||
|  |     g.NextWindowData.RefreshFlagsVal = flags; | ||||||
|  | } | ||||||
|  |  | ||||||
| ImDrawList* ImGui::GetWindowDrawList() | ImDrawList* ImGui::GetWindowDrawList() | ||||||
| { | { | ||||||
|     ImGuiWindow* window = GetCurrentWindow(); |     ImGuiWindow* window = GetCurrentWindow(); | ||||||
|   | |||||||
| @@ -10,6 +10,11 @@ | |||||||
| // Read top of imgui.cpp and imgui.h for many details, documentation, comments, links. | // Read top of imgui.cpp and imgui.h for many details, documentation, comments, links. | ||||||
| // Get the latest version at https://github.com/ocornut/imgui | // Get the latest version at https://github.com/ocornut/imgui | ||||||
|  |  | ||||||
|  | // How to easily locate code? | ||||||
|  | // - Use the Item Picker to debug break in code by clicking any widgets: https://github.com/ocornut/imgui/wiki/Debug-Tools | ||||||
|  | // - Browse an online version the demo with code linked to hovered widgets: https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html | ||||||
|  | // - Find a visible string and search for it in the code! | ||||||
|  |  | ||||||
| //--------------------------------------------------- | //--------------------------------------------------- | ||||||
| // PLEASE DO NOT REMOVE THIS FILE FROM YOUR PROJECT! | // PLEASE DO NOT REMOVE THIS FILE FROM YOUR PROJECT! | ||||||
| //--------------------------------------------------- | //--------------------------------------------------- | ||||||
|   | |||||||
| @@ -385,6 +385,7 @@ void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error) | |||||||
| } | } | ||||||
|  |  | ||||||
| // Initialize before use in a new frame. We always have a command ready in the buffer. | // Initialize before use in a new frame. We always have a command ready in the buffer. | ||||||
|  | // In the majority of cases, you would want to call PushClipRect() and PushTextureID() after this. | ||||||
| void ImDrawList::_ResetForNewFrame() | void ImDrawList::_ResetForNewFrame() | ||||||
| { | { | ||||||
|     // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory. |     // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory. | ||||||
|   | |||||||
| @@ -182,6 +182,7 @@ typedef int ImGuiSeparatorFlags;        // -> enum ImGuiSeparatorFlags_     // F | |||||||
| typedef int ImGuiTextFlags;             // -> enum ImGuiTextFlags_          // Flags: for TextEx() | typedef int ImGuiTextFlags;             // -> enum ImGuiTextFlags_          // Flags: for TextEx() | ||||||
| typedef int ImGuiTooltipFlags;          // -> enum ImGuiTooltipFlags_       // Flags: for BeginTooltipEx() | typedef int ImGuiTooltipFlags;          // -> enum ImGuiTooltipFlags_       // Flags: for BeginTooltipEx() | ||||||
| typedef int ImGuiTypingSelectFlags;     // -> enum ImGuiTypingSelectFlags_  // Flags: for GetTypingSelectRequest() | typedef int ImGuiTypingSelectFlags;     // -> enum ImGuiTypingSelectFlags_  // Flags: for GetTypingSelectRequest() | ||||||
|  | typedef int ImGuiWindowRefreshFlags;    // -> enum ImGuiWindowRefreshFlags_ // Flags: for SetNextWindowRefreshPolicy() | ||||||
|  |  | ||||||
| typedef void (*ImGuiErrorLogCallback)(void* user_data, const char* fmt, ...); | typedef void (*ImGuiErrorLogCallback)(void* user_data, const char* fmt, ...); | ||||||
|  |  | ||||||
| @@ -1117,6 +1118,15 @@ struct IMGUI_API ImGuiInputTextState | |||||||
|  |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | enum ImGuiWindowRefreshFlags_ | ||||||
|  | { | ||||||
|  |     ImGuiWindowRefreshFlags_None                = 0, | ||||||
|  |     ImGuiWindowRefreshFlags_TryToAvoidRefresh   = 1 << 0,   // [EXPERIMENTAL] Try to keep existing contents, USER MUST NOT HONOR BEGIN() RETURNING FALSE AND NOT APPEND. | ||||||
|  |     ImGuiWindowRefreshFlags_RefreshOnHover      = 1 << 1,   // [EXPERIMENTAL] Always refresh on hover | ||||||
|  |     ImGuiWindowRefreshFlags_RefreshOnFocus      = 1 << 2,   // [EXPERIMENTAL] Always refresh on focus | ||||||
|  |     // Refresh policy/frequency, Load Balancing etc. | ||||||
|  | }; | ||||||
|  |  | ||||||
| enum ImGuiNextWindowDataFlags_ | enum ImGuiNextWindowDataFlags_ | ||||||
| { | { | ||||||
|     ImGuiNextWindowDataFlags_None               = 0, |     ImGuiNextWindowDataFlags_None               = 0, | ||||||
| @@ -1129,6 +1139,7 @@ enum ImGuiNextWindowDataFlags_ | |||||||
|     ImGuiNextWindowDataFlags_HasBgAlpha         = 1 << 6, |     ImGuiNextWindowDataFlags_HasBgAlpha         = 1 << 6, | ||||||
|     ImGuiNextWindowDataFlags_HasScroll          = 1 << 7, |     ImGuiNextWindowDataFlags_HasScroll          = 1 << 7, | ||||||
|     ImGuiNextWindowDataFlags_HasChildFlags      = 1 << 8, |     ImGuiNextWindowDataFlags_HasChildFlags      = 1 << 8, | ||||||
|  |     ImGuiNextWindowDataFlags_HasRefreshPolicy   = 1 << 9, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // Storage for SetNexWindow** functions | // Storage for SetNexWindow** functions | ||||||
| @@ -1150,6 +1161,7 @@ struct ImGuiNextWindowData | |||||||
|     void*                       SizeCallbackUserData; |     void*                       SizeCallbackUserData; | ||||||
|     float                       BgAlphaVal;             // Override background alpha |     float                       BgAlphaVal;             // Override background alpha | ||||||
|     ImVec2                      MenuBarOffsetMinVal;    // (Always on) This is not exposed publicly, so we don't clear it and it doesn't have a corresponding flag (could we? for consistency?) |     ImVec2                      MenuBarOffsetMinVal;    // (Always on) This is not exposed publicly, so we don't clear it and it doesn't have a corresponding flag (could we? for consistency?) | ||||||
|  |     ImGuiWindowRefreshFlags     RefreshFlagsVal; | ||||||
|  |  | ||||||
|     ImGuiNextWindowData()       { memset(this, 0, sizeof(*this)); } |     ImGuiNextWindowData()       { memset(this, 0, sizeof(*this)); } | ||||||
|     inline void ClearFlags()    { Flags = ImGuiNextWindowDataFlags_None; } |     inline void ClearFlags()    { Flags = ImGuiNextWindowDataFlags_None; } | ||||||
| @@ -2534,6 +2546,7 @@ struct IMGUI_API ImGuiWindow | |||||||
|     bool                    Collapsed;                          // Set when collapsing window to become only title-bar |     bool                    Collapsed;                          // Set when collapsing window to become only title-bar | ||||||
|     bool                    WantCollapseToggle; |     bool                    WantCollapseToggle; | ||||||
|     bool                    SkipItems;                          // Set when items can safely be all clipped (e.g. window not visible or collapsed) |     bool                    SkipItems;                          // Set when items can safely be all clipped (e.g. window not visible or collapsed) | ||||||
|  |     bool                    SkipRefresh;                        // [EXPERIMENTAL] Reuse previous frame drawn contents, Begin() returns false. | ||||||
|     bool                    Appearing;                          // Set during the frame where the window is appearing (or re-appearing) |     bool                    Appearing;                          // Set during the frame where the window is appearing (or re-appearing) | ||||||
|     bool                    Hidden;                             // Do not display (== HiddenFrames*** > 0) |     bool                    Hidden;                             // Do not display (== HiddenFrames*** > 0) | ||||||
|     bool                    IsFallbackWindow;                   // Set on the "Debug##Default" window. |     bool                    IsFallbackWindow;                   // Set on the "Debug##Default" window. | ||||||
| @@ -3007,6 +3020,7 @@ namespace ImGui | |||||||
|     IMGUI_API ImGuiWindow*  FindWindowByID(ImGuiID id); |     IMGUI_API ImGuiWindow*  FindWindowByID(ImGuiID id); | ||||||
|     IMGUI_API ImGuiWindow*  FindWindowByName(const char* name); |     IMGUI_API ImGuiWindow*  FindWindowByName(const char* name); | ||||||
|     IMGUI_API void          UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window); |     IMGUI_API void          UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window); | ||||||
|  |     IMGUI_API void          UpdateWindowSkipRefresh(ImGuiWindow* window); | ||||||
|     IMGUI_API ImVec2        CalcWindowNextAutoFitSize(ImGuiWindow* window); |     IMGUI_API ImVec2        CalcWindowNextAutoFitSize(ImGuiWindow* window); | ||||||
|     IMGUI_API bool          IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy); |     IMGUI_API bool          IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent, bool popup_hierarchy); | ||||||
|     IMGUI_API bool          IsWindowWithinBeginStackOf(ImGuiWindow* window, ImGuiWindow* potential_parent); |     IMGUI_API bool          IsWindowWithinBeginStackOf(ImGuiWindow* window, ImGuiWindow* potential_parent); | ||||||
| @@ -3032,6 +3046,9 @@ namespace ImGui | |||||||
|     IMGUI_API int           FindWindowDisplayIndex(ImGuiWindow* window); |     IMGUI_API int           FindWindowDisplayIndex(ImGuiWindow* window); | ||||||
|     IMGUI_API ImGuiWindow*  FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* window); |     IMGUI_API ImGuiWindow*  FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* window); | ||||||
|  |  | ||||||
|  |     // Windows: Idle, Refresh Policies [EXPERIMENTAL] | ||||||
|  |     IMGUI_API void          SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags flags); | ||||||
|  |  | ||||||
|     // Fonts, drawing |     // Fonts, drawing | ||||||
|     IMGUI_API void          SetCurrentFont(ImFont* font); |     IMGUI_API void          SetCurrentFont(ImFont* font); | ||||||
|     inline ImFont*          GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } |     inline ImFont*          GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 ocornut
					ocornut