mirror of
https://github.com/ocornut/imgui.git
synced 2026-01-23 02:04:22 +00:00
Merge branch 'master' into docking
# Conflicts: # backends/imgui_impl_opengl3.cpp # backends/imgui_impl_win32.cpp
This commit is contained in:
commit
d91211f9f2
17 changed files with 372 additions and 282 deletions
184
imgui.cpp
184
imgui.cpp
|
|
@ -1318,11 +1318,13 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Perhaps we could clear queued events as well?
|
||||
void ImGuiIO::ClearInputCharacters()
|
||||
{
|
||||
InputQueueCharacters.resize(0);
|
||||
}
|
||||
|
||||
// FIXME: Perhaps we could clear queued events as well?
|
||||
void ImGuiIO::ClearInputKeys()
|
||||
{
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
|
||||
|
|
@ -1338,6 +1340,23 @@ void ImGuiIO::ClearInputKeys()
|
|||
KeyMods = ImGuiMod_None;
|
||||
}
|
||||
|
||||
static ImGuiInputEvent* FindLatestInputEvent(ImGuiInputEventType type, int arg = -1)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
for (int n = g.InputEventsQueue.Size - 1; n >= 0; n--)
|
||||
{
|
||||
ImGuiInputEvent* e = &g.InputEventsQueue[n];
|
||||
if (e->Type != type)
|
||||
continue;
|
||||
if (type == ImGuiInputEventType_Key && e->Key.Key != arg)
|
||||
continue;
|
||||
if (type == ImGuiInputEventType_MouseButton && e->MouseButton.Button != arg)
|
||||
continue;
|
||||
return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Queue a new key down/up event.
|
||||
// - ImGuiKey key: Translated key (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character)
|
||||
// - bool down: Is the key down? use false to signify a key release.
|
||||
|
|
@ -1363,17 +1382,13 @@ void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value)
|
|||
if (ImGui::IsGamepadKey(key))
|
||||
BackendUsingLegacyNavInputArray = false;
|
||||
|
||||
// Partial filter of duplicates (not strictly needed, but makes data neater in particular for key mods and gamepad values which are most commonly spmamed)
|
||||
ImGuiKeyData* key_data = ImGui::GetKeyData(key);
|
||||
if (key_data->Down == down && key_data->AnalogValue == analog_value)
|
||||
{
|
||||
bool found = false;
|
||||
for (int n = g.InputEventsQueue.Size - 1; n >= 0 && !found; n--)
|
||||
if (g.InputEventsQueue[n].Type == ImGuiInputEventType_Key && g.InputEventsQueue[n].Key.Key == key)
|
||||
found = true;
|
||||
if (!found)
|
||||
return;
|
||||
}
|
||||
// Filter duplicate (in particular: key mods and gamepad analog values are commonly spammed)
|
||||
const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_Key, (int)key);
|
||||
const ImGuiKeyData* key_data = ImGui::GetKeyData(key);
|
||||
const bool latest_key_down = latest_event ? latest_event->Key.Down : key_data->Down;
|
||||
const float latest_key_analog = latest_event ? latest_event->Key.AnalogValue : key_data->AnalogValue;
|
||||
if (latest_key_down == down && latest_key_analog == analog_value)
|
||||
return;
|
||||
|
||||
// Add event
|
||||
ImGuiInputEvent e;
|
||||
|
|
@ -1431,11 +1446,20 @@ void ImGuiIO::AddMousePosEvent(float x, float y)
|
|||
if (!AppAcceptingEvents)
|
||||
return;
|
||||
|
||||
// Apply same flooring as UpdateMouseInputs()
|
||||
ImVec2 pos((x > -FLT_MAX) ? ImFloorSigned(x) : x, (y > -FLT_MAX) ? ImFloorSigned(y) : y);
|
||||
|
||||
// Filter duplicate
|
||||
const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_MousePos);
|
||||
const ImVec2 latest_pos = latest_event ? ImVec2(latest_event->MousePos.PosX, latest_event->MousePos.PosY) : g.IO.MousePos;
|
||||
if (latest_pos.x == pos.x && latest_pos.y == pos.y)
|
||||
return;
|
||||
|
||||
ImGuiInputEvent e;
|
||||
e.Type = ImGuiInputEventType_MousePos;
|
||||
e.Source = ImGuiInputSource_Mouse;
|
||||
e.MousePos.PosX = x;
|
||||
e.MousePos.PosY = y;
|
||||
e.MousePos.PosX = pos.x;
|
||||
e.MousePos.PosY = pos.y;
|
||||
g.InputEventsQueue.push_back(e);
|
||||
}
|
||||
|
||||
|
|
@ -1447,6 +1471,12 @@ void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
|
|||
if (!AppAcceptingEvents)
|
||||
return;
|
||||
|
||||
// Filter duplicate
|
||||
const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_MouseButton, (int)mouse_button);
|
||||
const bool latest_button_down = latest_event ? latest_event->MouseButton.Down : g.IO.MouseDown[mouse_button];
|
||||
if (latest_button_down == down)
|
||||
return;
|
||||
|
||||
ImGuiInputEvent e;
|
||||
e.Type = ImGuiInputEventType_MouseButton;
|
||||
e.Source = ImGuiInputSource_Mouse;
|
||||
|
|
@ -1460,7 +1490,9 @@ void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y)
|
|||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
|
||||
if ((wheel_x == 0.0f && wheel_y == 0.0f) || !AppAcceptingEvents)
|
||||
|
||||
// Filter duplicate (unlike most events, wheel values are relative and easy to filter)
|
||||
if (!AppAcceptingEvents || (wheel_x == 0.0f && wheel_y == 0.0f))
|
||||
return;
|
||||
|
||||
ImGuiInputEvent e;
|
||||
|
|
@ -1489,6 +1521,12 @@ void ImGuiIO::AddFocusEvent(bool focused)
|
|||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
|
||||
|
||||
// Filter duplicate
|
||||
const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_Focus);
|
||||
const bool latest_focused = latest_event ? latest_event->AppFocused.Focused : !g.IO.AppFocusLost;
|
||||
if (latest_focused == focused)
|
||||
return;
|
||||
|
||||
ImGuiInputEvent e;
|
||||
e.Type = ImGuiInputEventType_Focus;
|
||||
e.AppFocused.Focused = focused;
|
||||
|
|
@ -3654,6 +3692,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
|
|||
return false;
|
||||
IM_ASSERT((flags & (ImGuiHoveredFlags_AnyWindow | ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_NoPopupHierarchy | ImGuiHoveredFlags_DockHierarchy)) == 0); // Flags not supported by this function
|
||||
|
||||
// Done with rectangle culling so we can perform heavier checks now
|
||||
// Test if we are hovering the right window (our window could be behind another window)
|
||||
// [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851)
|
||||
// [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable
|
||||
|
|
@ -3720,7 +3759,10 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
|
|||
return false;
|
||||
if (!IsMouseHoveringRect(bb.Min, bb.Max))
|
||||
return false;
|
||||
if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None))
|
||||
|
||||
// Done with rectangle culling so we can perform heavier checks now.
|
||||
ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags);
|
||||
if (!(item_flags & ImGuiItemFlags_NoWindowHoverableCheck) && !IsWindowContentHoverable(window, ImGuiHoveredFlags_None))
|
||||
{
|
||||
g.HoveredIdDisabled = true;
|
||||
return false;
|
||||
|
|
@ -3732,7 +3774,6 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
|
|||
SetHoveredID(id);
|
||||
|
||||
// When disabled we'll return false but still set HoveredId
|
||||
ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags);
|
||||
if (item_flags & ImGuiItemFlags_Disabled)
|
||||
{
|
||||
// Release active id if turning disabled
|
||||
|
|
@ -4389,6 +4430,7 @@ static void StartLockWheelingWindow(ImGuiWindow* window)
|
|||
ImGuiContext& g = *GImGui;
|
||||
if (g.WheelingWindow == window)
|
||||
return;
|
||||
IMGUI_DEBUG_LOG_IO("StartLockWheelingWindow() \"%s\"\n", window ? window->Name : "NULL");
|
||||
g.WheelingWindow = window;
|
||||
g.WheelingWindowRefMousePos = g.IO.MousePos;
|
||||
g.WheelingWindowTimer = WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER;
|
||||
|
|
@ -4406,6 +4448,7 @@ void ImGui::UpdateMouseWheel()
|
|||
g.WheelingWindowTimer = 0.0f;
|
||||
if (g.WheelingWindowTimer <= 0.0f)
|
||||
{
|
||||
IMGUI_DEBUG_LOG_IO("UpdateMouseWheel() release WheelingWindow lock \"%s\"\n", g.WheelingWindow->Name);
|
||||
g.WheelingWindow = NULL;
|
||||
g.WheelingWindowTimer = 0.0f;
|
||||
}
|
||||
|
|
@ -4772,9 +4815,10 @@ void ImGui::NewFrame()
|
|||
{
|
||||
ImGuiWindow* window = g.Windows[i];
|
||||
window->WasActive = window->Active;
|
||||
window->BeginCount = 0;
|
||||
window->Active = false;
|
||||
window->WriteAccessed = false;
|
||||
window->BeginCountPreviousFrame = window->BeginCount;
|
||||
window->BeginCount = 0;
|
||||
|
||||
// Garbage collect transient buffers of recently unused windows
|
||||
if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
|
||||
|
|
@ -8410,6 +8454,8 @@ const char* ImGui::GetKeyName(ImGuiKey key)
|
|||
#endif
|
||||
if (key == ImGuiKey_None)
|
||||
return "None";
|
||||
if (key & ImGuiMod_Mask_)
|
||||
key = ConvertSingleModFlagToKey(key);
|
||||
if (!IsNamedKey(key))
|
||||
return "Unknown";
|
||||
|
||||
|
|
@ -8679,7 +8725,7 @@ static const char* GetInputSourceName(ImGuiInputSource source)
|
|||
static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (e->Type == ImGuiInputEventType_MousePos) { IMGUI_DEBUG_LOG_IO("%s: MousePos (%.1f, %.1f)\n", prefix, e->MousePos.PosX, e->MousePos.PosY); return; }
|
||||
if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("%s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("%s: MousePos (%.1f, %.1f)\n", prefix, e->MousePos.PosX, e->MousePos.PosY); return; }
|
||||
if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("%s: MouseButton %d %s\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up"); return; }
|
||||
if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("%s: MouseWheel (%.1f, %.1f)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY); return; }
|
||||
if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("%s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; }
|
||||
|
|
@ -8712,45 +8758,31 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
|
|||
ImGuiInputEvent* e = &g.InputEventsQueue[event_n];
|
||||
if (e->Type == ImGuiInputEventType_MousePos)
|
||||
{
|
||||
// Trickling Rule: Stop processing queued events if we already handled a mouse button change
|
||||
ImVec2 event_pos(e->MousePos.PosX, e->MousePos.PosY);
|
||||
if (IsMousePosValid(&event_pos))
|
||||
event_pos = ImVec2(ImFloorSigned(event_pos.x), ImFloorSigned(event_pos.y)); // Apply same flooring as UpdateMouseInputs()
|
||||
e->IgnoredAsSame = (io.MousePos.x == event_pos.x && io.MousePos.y == event_pos.y);
|
||||
if (!e->IgnoredAsSame)
|
||||
{
|
||||
// Trickling Rule: Stop processing queued events if we already handled a mouse button change
|
||||
if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_wheeled || key_changed || text_inputted))
|
||||
break;
|
||||
io.MousePos = event_pos;
|
||||
mouse_moved = true;
|
||||
}
|
||||
if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_wheeled || key_changed || text_inputted))
|
||||
break;
|
||||
io.MousePos = event_pos;
|
||||
mouse_moved = true;
|
||||
}
|
||||
else if (e->Type == ImGuiInputEventType_MouseButton)
|
||||
{
|
||||
// Trickling Rule: Stop processing queued events if we got multiple action on the same button
|
||||
const ImGuiMouseButton button = e->MouseButton.Button;
|
||||
IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT);
|
||||
e->IgnoredAsSame = (io.MouseDown[button] == e->MouseButton.Down);
|
||||
if (!e->IgnoredAsSame)
|
||||
{
|
||||
// Trickling Rule: Stop processing queued events if we got multiple action on the same button
|
||||
if (trickle_fast_inputs && ((mouse_button_changed & (1 << button)) || mouse_wheeled))
|
||||
break;
|
||||
io.MouseDown[button] = e->MouseButton.Down;
|
||||
mouse_button_changed |= (1 << button);
|
||||
}
|
||||
if (trickle_fast_inputs && ((mouse_button_changed & (1 << button)) || mouse_wheeled))
|
||||
break;
|
||||
io.MouseDown[button] = e->MouseButton.Down;
|
||||
mouse_button_changed |= (1 << button);
|
||||
}
|
||||
else if (e->Type == ImGuiInputEventType_MouseWheel)
|
||||
{
|
||||
e->IgnoredAsSame = (e->MouseWheel.WheelX == 0.0f && e->MouseWheel.WheelY == 0.0f);
|
||||
if (!e->IgnoredAsSame)
|
||||
{
|
||||
// Trickling Rule: Stop processing queued events if we got multiple action on the event
|
||||
if (trickle_fast_inputs && (mouse_moved || mouse_button_changed != 0))
|
||||
break;
|
||||
io.MouseWheelH += e->MouseWheel.WheelX;
|
||||
io.MouseWheel += e->MouseWheel.WheelY;
|
||||
mouse_wheeled = true;
|
||||
}
|
||||
// Trickling Rule: Stop processing queued events if we got multiple action on the event
|
||||
if (trickle_fast_inputs && (mouse_moved || mouse_button_changed != 0))
|
||||
break;
|
||||
io.MouseWheelH += e->MouseWheel.WheelX;
|
||||
io.MouseWheel += e->MouseWheel.WheelY;
|
||||
mouse_wheeled = true;
|
||||
}
|
||||
else if (e->Type == ImGuiInputEventType_MouseViewport)
|
||||
{
|
||||
|
|
@ -8758,37 +8790,33 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
|
|||
}
|
||||
else if (e->Type == ImGuiInputEventType_Key)
|
||||
{
|
||||
// Trickling Rule: Stop processing queued events if we got multiple action on the same button
|
||||
ImGuiKey key = e->Key.Key;
|
||||
IM_ASSERT(key != ImGuiKey_None);
|
||||
ImGuiKeyData* key_data = GetKeyData(key);
|
||||
const int key_data_index = (int)(key_data - g.IO.KeysData);
|
||||
e->IgnoredAsSame = (key_data->Down == e->Key.Down && key_data->AnalogValue == e->Key.AnalogValue);
|
||||
if (!e->IgnoredAsSame)
|
||||
if (trickle_fast_inputs && key_data->Down != e->Key.Down && (key_changed_mask.TestBit(key_data_index) || text_inputted || mouse_button_changed != 0))
|
||||
break;
|
||||
key_data->Down = e->Key.Down;
|
||||
key_data->AnalogValue = e->Key.AnalogValue;
|
||||
key_changed = true;
|
||||
key_changed_mask.SetBit(key_data_index);
|
||||
|
||||
if (key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super)
|
||||
{
|
||||
// Trickling Rule: Stop processing queued events if we got multiple action on the same button
|
||||
if (trickle_fast_inputs && key_data->Down != e->Key.Down && (key_changed_mask.TestBit(key_data_index) || text_inputted || mouse_button_changed != 0))
|
||||
break;
|
||||
key_data->Down = e->Key.Down;
|
||||
key_data->AnalogValue = e->Key.AnalogValue;
|
||||
key_changed = true;
|
||||
key_changed_mask.SetBit(key_data_index);
|
||||
|
||||
if (key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super)
|
||||
{
|
||||
if (key == ImGuiMod_Ctrl) { io.KeyCtrl = key_data->Down; }
|
||||
if (key == ImGuiMod_Shift) { io.KeyShift = key_data->Down; }
|
||||
if (key == ImGuiMod_Alt) { io.KeyAlt = key_data->Down; }
|
||||
if (key == ImGuiMod_Super) { io.KeySuper = key_data->Down; }
|
||||
io.KeyMods = GetMergedModsFromBools();
|
||||
}
|
||||
|
||||
// Allow legacy code using io.KeysDown[GetKeyIndex()] with new backends
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
|
||||
io.KeysDown[key_data_index] = key_data->Down;
|
||||
if (io.KeyMap[key_data_index] != -1)
|
||||
io.KeysDown[io.KeyMap[key_data_index]] = key_data->Down;
|
||||
#endif
|
||||
if (key == ImGuiMod_Ctrl) { io.KeyCtrl = key_data->Down; }
|
||||
if (key == ImGuiMod_Shift) { io.KeyShift = key_data->Down; }
|
||||
if (key == ImGuiMod_Alt) { io.KeyAlt = key_data->Down; }
|
||||
if (key == ImGuiMod_Super) { io.KeySuper = key_data->Down; }
|
||||
io.KeyMods = GetMergedModsFromBools();
|
||||
}
|
||||
|
||||
// Allow legacy code using io.KeysDown[GetKeyIndex()] with new backends
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
|
||||
io.KeysDown[key_data_index] = key_data->Down;
|
||||
if (io.KeyMap[key_data_index] != -1)
|
||||
io.KeysDown[io.KeyMap[key_data_index]] = key_data->Down;
|
||||
#endif
|
||||
}
|
||||
else if (e->Type == ImGuiInputEventType_Text)
|
||||
{
|
||||
|
|
@ -8802,12 +8830,10 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
|
|||
}
|
||||
else if (e->Type == ImGuiInputEventType_Focus)
|
||||
{
|
||||
// We intentionally overwrite this and process lower, in order to give a chance
|
||||
// We intentionally overwrite this and process in NewFrame(), in order to give a chance
|
||||
// to multi-viewports backends to queue AddFocusEvent(false) + AddFocusEvent(true) in same frame.
|
||||
const bool focus_lost = !e->AppFocused.Focused;
|
||||
e->IgnoredAsSame = (io.AppFocusLost == focus_lost);
|
||||
if (!e->IgnoredAsSame)
|
||||
io.AppFocusLost = focus_lost;
|
||||
io.AppFocusLost = focus_lost;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -8824,7 +8850,7 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
|
|||
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
|
||||
if (event_n != 0 && (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO))
|
||||
for (int n = 0; n < g.InputEventsQueue.Size; n++)
|
||||
DebugPrintInputEvent(n < event_n ? (g.InputEventsQueue[n].IgnoredAsSame ? "Processed (Same)" : "Processed") : "Remaining", &g.InputEventsQueue[n]);
|
||||
DebugPrintInputEvent(n < event_n ? "Processed" : "Remaining", &g.InputEventsQueue[n]);
|
||||
#endif
|
||||
|
||||
// Remaining events will be processed on the next frame
|
||||
|
|
@ -11511,7 +11537,7 @@ static void ImGui::NavUpdateCancelRequest()
|
|||
SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, WindowRectAbsToRel(parent_window, child_rect));
|
||||
NavRestoreHighlightAfterMove();
|
||||
}
|
||||
else if (g.OpenPopupStack.Size > 0 && !(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
|
||||
else if (g.OpenPopupStack.Size > 0 && g.OpenPopupStack.back().Window != NULL && !(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
|
||||
{
|
||||
// Close open popup/menu
|
||||
ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue