Internals: Refactor: Moved code out of NewFrame() into UpdateTabFocus() and UpdateSettings()

This commit is contained in:
ocornut 2020-03-03 15:23:51 +01:00
parent 095dc996b0
commit 2679bee28d
2 changed files with 86 additions and 64 deletions

View File

@ -87,6 +87,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- input text: option to Tab after an Enter validation. - input text: option to Tab after an Enter validation.
- input text: add ImGuiInputTextFlags_EnterToApply? (off #218) - input text: add ImGuiInputTextFlags_EnterToApply? (off #218)
- input text: easier ways to update buffer (from source char*) while owned. preserve some sort of cursor position for multi-line text. - input text: easier ways to update buffer (from source char*) while owned. preserve some sort of cursor position for multi-line text.
- input text: add flag (e.g. ImGuiInputTextFlags_EscapeClearsBuffer) to clear instead of revert. what to do with focus? (also see #2890)
- input text: add discard flag (e.g. ImGuiInputTextFlags_DiscardActiveBuffer) or make it easier to clear active focus for text replacement during edition (#725) - input text: add discard flag (e.g. ImGuiInputTextFlags_DiscardActiveBuffer) or make it easier to clear active focus for text replacement during edition (#725)
- input text: display bug when clicking a drag/slider after an input text in a different window has all-selected text (order dependent). actually a very old bug but no one appears to have noticed it. - input text: display bug when clicking a drag/slider after an input text in a different window has all-selected text (order dependent). actually a very old bug but no one appears to have noticed it.
- input text: allow centering/positioning text so that ctrl+clicking Drag or Slider keeps the textual value at the same pixel position. - input text: allow centering/positioning text so that ctrl+clicking Drag or Slider keeps the textual value at the same pixel position.

149
imgui.cpp
View File

@ -904,10 +904,12 @@ static void ErrorCheckEndFrame();
static void ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write); static void ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write);
// Misc // Misc
static void UpdateSettings();
static void UpdateMouseInputs(); static void UpdateMouseInputs();
static void UpdateMouseWheel(); static void UpdateMouseWheel();
static bool UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]); static void UpdateTabFocus();
static void UpdateDebugToolItemPicker(); static void UpdateDebugToolItemPicker();
static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]);
static void RenderWindowOuterBorders(ImGuiWindow* window); static void RenderWindowOuterBorders(ImGuiWindow* window);
static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size); static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size);
static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);
@ -3495,6 +3497,42 @@ void ImGui::UpdateMouseWheel()
} }
} }
void ImGui::UpdateTabFocus()
{
ImGuiContext& g = *GImGui;
// Pressing TAB activate widget focus
g.FocusTabPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab));
if (g.ActiveId == 0 && g.FocusTabPressed)
{
// Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also
// manipulate the Next fields even, even though they will be turned into Curr fields by the code below.
g.FocusRequestNextWindow = g.NavWindow;
g.FocusRequestNextCounterRegular = INT_MAX;
if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX)
g.FocusRequestNextCounterTabStop = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1);
else
g.FocusRequestNextCounterTabStop = g.IO.KeyShift ? -1 : 0;
}
// Turn queued focus request into current one
g.FocusRequestCurrWindow = NULL;
g.FocusRequestCurrCounterRegular = g.FocusRequestCurrCounterTabStop = INT_MAX;
if (g.FocusRequestNextWindow != NULL)
{
ImGuiWindow* window = g.FocusRequestNextWindow;
g.FocusRequestCurrWindow = window;
if (g.FocusRequestNextCounterRegular != INT_MAX && window->DC.FocusCounterRegular != -1)
g.FocusRequestCurrCounterRegular = ImModPositive(g.FocusRequestNextCounterRegular, window->DC.FocusCounterRegular + 1);
if (g.FocusRequestNextCounterTabStop != INT_MAX && window->DC.FocusCounterTabStop != -1)
g.FocusRequestCurrCounterTabStop = ImModPositive(g.FocusRequestNextCounterTabStop, window->DC.FocusCounterTabStop + 1);
g.FocusRequestNextWindow = NULL;
g.FocusRequestNextCounterRegular = g.FocusRequestNextCounterTabStop = INT_MAX;
}
g.NavIdTabCounter = INT_MAX;
}
// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app) // The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app)
void ImGui::UpdateHoveredWindowAndCaptureFlags() void ImGui::UpdateHoveredWindowAndCaptureFlags()
{ {
@ -3595,28 +3633,8 @@ void ImGui::NewFrame()
// Check and assert for various common IO and Configuration mistakes // Check and assert for various common IO and Configuration mistakes
NewFrameSanityChecks(); NewFrameSanityChecks();
// Load settings on first frame (if not explicitly loaded manually before) // Load settings on first frame, save settings when modified (after a delay)
if (!g.SettingsLoaded) UpdateSettings();
{
IM_ASSERT(g.SettingsWindows.empty());
if (g.IO.IniFilename)
LoadIniSettingsFromDisk(g.IO.IniFilename);
g.SettingsLoaded = true;
}
// Save settings (with a delay after the last modification, so we don't spam disk too much)
if (g.SettingsDirtyTimer > 0.0f)
{
g.SettingsDirtyTimer -= g.IO.DeltaTime;
if (g.SettingsDirtyTimer <= 0.0f)
{
if (g.IO.IniFilename != NULL)
SaveIniSettingsToDisk(g.IO.IniFilename);
else
g.IO.WantSaveIniSettings = true; // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves.
g.SettingsDirtyTimer = 0.0f;
}
}
g.Time += g.IO.DeltaTime; g.Time += g.IO.DeltaTime;
g.WithinFrameScope = true; g.WithinFrameScope = true;
@ -3625,6 +3643,12 @@ void ImGui::NewFrame()
g.WindowsActiveCount = 0; g.WindowsActiveCount = 0;
g.MenusIdSubmittedThisFrame.resize(0); g.MenusIdSubmittedThisFrame.resize(0);
// Calculate frame-rate for the user, as a purely luxurious feature
g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx];
g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime;
g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);
g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX;
// Setup current font and draw list shared data // Setup current font and draw list shared data
g.IO.Fonts->Locked = true; g.IO.Fonts->Locked = true;
SetCurrentFont(GetDefaultFont()); SetCurrentFont(GetDefaultFont());
@ -3655,7 +3679,7 @@ void ImGui::NewFrame()
if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId) if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId)
KeepAliveID(g.DragDropPayload.SourceId); KeepAliveID(g.DragDropPayload.SourceId);
// Clear reference to active widget if the widget isn't alive anymore // Update HoveredId data
if (!g.HoveredIdPreviousFrame) if (!g.HoveredIdPreviousFrame)
g.HoveredIdTimer = 0.0f; g.HoveredIdTimer = 0.0f;
if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId)) if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId))
@ -3667,6 +3691,8 @@ void ImGui::NewFrame()
g.HoveredIdPreviousFrame = g.HoveredId; g.HoveredIdPreviousFrame = g.HoveredId;
g.HoveredId = 0; g.HoveredId = 0;
g.HoveredIdAllowOverlap = false; g.HoveredIdAllowOverlap = false;
// Update ActiveId data (clear reference to active widget if the widget isn't alive anymore)
if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0) if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0)
ClearActiveID(); ClearActiveID();
if (g.ActiveId) if (g.ActiveId)
@ -3683,8 +3709,9 @@ void ImGui::NewFrame()
g.TempInputId = 0; g.TempInputId = 0;
if (g.ActiveId == 0) if (g.ActiveId == 0)
{ {
g.ActiveIdUsingNavDirMask = g.ActiveIdUsingNavInputMask = 0; g.ActiveIdUsingNavDirMask = 0x00;
g.ActiveIdUsingKeyInputMask = 0; g.ActiveIdUsingNavInputMask = 0x00;
g.ActiveIdUsingKeyInputMask = 0x00;
} }
// Drag and drop // Drag and drop
@ -3704,12 +3731,6 @@ void ImGui::NewFrame()
// Update mouse input state // Update mouse input state
UpdateMouseInputs(); UpdateMouseInputs();
// Calculate frame-rate for the user, as a purely luxurious feature
g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx];
g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime;
g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);
g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX;
// Find hovered window // Find hovered window
// (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame) // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame)
UpdateHoveredWindowAndCaptureFlags(); UpdateHoveredWindowAndCaptureFlags();
@ -3730,36 +3751,8 @@ void ImGui::NewFrame()
// Mouse wheel scrolling, scale // Mouse wheel scrolling, scale
UpdateMouseWheel(); UpdateMouseWheel();
// Pressing TAB activate widget focus // Update legacy TAB focus
g.FocusTabPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab)); UpdateTabFocus();
if (g.ActiveId == 0 && g.FocusTabPressed)
{
// Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also
// manipulate the Next fields even, even though they will be turned into Curr fields by the code below.
g.FocusRequestNextWindow = g.NavWindow;
g.FocusRequestNextCounterRegular = INT_MAX;
if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX)
g.FocusRequestNextCounterTabStop = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1);
else
g.FocusRequestNextCounterTabStop = g.IO.KeyShift ? -1 : 0;
}
// Turn queued focus request into current one
g.FocusRequestCurrWindow = NULL;
g.FocusRequestCurrCounterRegular = g.FocusRequestCurrCounterTabStop = INT_MAX;
if (g.FocusRequestNextWindow != NULL)
{
ImGuiWindow* window = g.FocusRequestNextWindow;
g.FocusRequestCurrWindow = window;
if (g.FocusRequestNextCounterRegular != INT_MAX && window->DC.FocusCounterRegular != -1)
g.FocusRequestCurrCounterRegular = ImModPositive(g.FocusRequestNextCounterRegular, window->DC.FocusCounterRegular + 1);
if (g.FocusRequestNextCounterTabStop != INT_MAX && window->DC.FocusCounterTabStop != -1)
g.FocusRequestCurrCounterTabStop = ImModPositive(g.FocusRequestNextCounterTabStop, window->DC.FocusCounterTabStop + 1);
g.FocusRequestNextWindow = NULL;
g.FocusRequestNextCounterRegular = g.FocusRequestNextCounterTabStop = INT_MAX;
}
g.NavIdTabCounter = INT_MAX;
// Mark all windows as not visible and compact unused memory. // Mark all windows as not visible and compact unused memory.
IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size); IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size);
@ -4972,7 +4965,7 @@ ImGuiID ImGui::GetWindowResizeID(ImGuiWindow* window, int n)
// Handle resize for: Resize Grips, Borders, Gamepad // Handle resize for: Resize Grips, Borders, Gamepad
// Return true when using auto-fit (double click on resize grip) // Return true when using auto-fit (double click on resize grip)
static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]) static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4])
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindowFlags flags = window->Flags; ImGuiWindowFlags flags = window->Flags;
@ -5645,7 +5638,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it.
const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
if (!window->Collapsed) if (!window->Collapsed)
if (UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0])) if (UpdateWindowManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]))
use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true; use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true;
window->ResizeBorderHeld = (signed char)border_held; window->ResizeBorderHeld = (signed char)border_held;
@ -9444,6 +9437,34 @@ void ImGui::LogButtons()
// [SECTION] SETTINGS // [SECTION] SETTINGS
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Called by NewFrame()
void ImGui::UpdateSettings()
{
// Load settings on first frame (if not explicitly loaded manually before)
ImGuiContext& g = *GImGui;
if (!g.SettingsLoaded)
{
IM_ASSERT(g.SettingsWindows.empty());
if (g.IO.IniFilename)
LoadIniSettingsFromDisk(g.IO.IniFilename);
g.SettingsLoaded = true;
}
// Save settings (with a delay after the last modification, so we don't spam disk too much)
if (g.SettingsDirtyTimer > 0.0f)
{
g.SettingsDirtyTimer -= g.IO.DeltaTime;
if (g.SettingsDirtyTimer <= 0.0f)
{
if (g.IO.IniFilename != NULL)
SaveIniSettingsToDisk(g.IO.IniFilename);
else
g.IO.WantSaveIniSettings = true; // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves.
g.SettingsDirtyTimer = 0.0f;
}
}
}
void ImGui::MarkIniSettingsDirty() void ImGui::MarkIniSettingsDirty()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;