mirror of
https://github.com/Drezil/imgui.git
synced 2025-07-06 13:08:47 +02:00
Merge branch 'master' into docking
# Conflicts: # backends/imgui_impl_glfw.cpp # backends/imgui_impl_sdl.cpp # backends/imgui_impl_win32.cpp # imgui_demo.cpp # imgui_internal.h
This commit is contained in:
249
imgui.cpp
249
imgui.cpp
@ -398,6 +398,7 @@ CODE
|
||||
- IsKeyPressed(MY_NATIVE_KEY_XXX) -> use IsKeyPressed(ImGuiKey_XXX)
|
||||
- IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX)
|
||||
- Backend writing to io.KeyMap[],io.KeysDown[] -> backend should call io.AddKeyEvent()
|
||||
- one case won't work with backward compatibility: if your custom backend used ImGuiKey as mock native indices (e.g. "io.KeyMap[ImGuiKey_A] = ImGuiKey_A") because those values are now larger than the legacy KeyDown[] array. Will assert.
|
||||
- inputs: added io.AddKeyModsEvent() instead of writing directly to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper.
|
||||
- 2022/01/05 (1.87) - inputs: renamed ImGuiKey_KeyPadEnter to ImGuiKey_KeypadEnter to align with new symbols. Kept redirection enum.
|
||||
- 2022/01/05 (1.87) - removed io.ImeSetInputScreenPosFn() in favor of more flexible io.SetPlatformImeDataFn(). Removed 'void* io.ImeWindowHandle' in favor of writing to 'void* ImGuiViewport::PlatformHandleRaw'.
|
||||
@ -1171,6 +1172,7 @@ ImGuiIO::ImGuiIO()
|
||||
#else
|
||||
ConfigMacOSXBehaviors = false;
|
||||
#endif
|
||||
ConfigInputEventQueue = true;
|
||||
ConfigInputTextCursorBlink = true;
|
||||
ConfigWindowsResizeFromEdges = true;
|
||||
ConfigWindowsMoveFromTitleBarOnly = false;
|
||||
@ -1197,10 +1199,19 @@ ImGuiIO::ImGuiIO()
|
||||
// Pass in translated ASCII characters for text input.
|
||||
// - with glfw you can get those from the callback set in glfwSetCharCallback()
|
||||
// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
|
||||
// FIXME: Should in theory be called "AddCharacterEvent()" to be consistent with new API
|
||||
void ImGuiIO::AddInputCharacter(unsigned int c)
|
||||
{
|
||||
if (c != 0)
|
||||
InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID);
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
|
||||
if (c == 0)
|
||||
return;
|
||||
|
||||
ImGuiInputEvent e;
|
||||
e.Type = ImGuiInputEventType_Char;
|
||||
e.Source = ImGuiInputSource_Keyboard;
|
||||
e.Text.Char = c;
|
||||
g.InputEventsQueue.push_back(e);
|
||||
}
|
||||
|
||||
// UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so
|
||||
@ -1213,7 +1224,7 @@ void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
|
||||
if ((c & 0xFC00) == 0xD800) // High surrogate, must save
|
||||
{
|
||||
if (InputQueueSurrogate != 0)
|
||||
InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID);
|
||||
AddInputCharacter(IM_UNICODE_CODEPOINT_INVALID);
|
||||
InputQueueSurrogate = c;
|
||||
return;
|
||||
}
|
||||
@ -1223,7 +1234,7 @@ void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
|
||||
{
|
||||
if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate
|
||||
{
|
||||
InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID);
|
||||
AddInputCharacter(IM_UNICODE_CODEPOINT_INVALID);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1236,7 +1247,7 @@ void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
|
||||
|
||||
InputQueueSurrogate = 0;
|
||||
}
|
||||
InputQueueCharacters.push_back(cp);
|
||||
AddInputCharacter((unsigned)cp);
|
||||
}
|
||||
|
||||
void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
|
||||
@ -1246,7 +1257,7 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
|
||||
unsigned int c = 0;
|
||||
utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
|
||||
if (c != 0)
|
||||
InputQueueCharacters.push_back((ImWchar)c);
|
||||
AddInputCharacter(c);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1275,12 +1286,13 @@ void ImGuiIO::ClearInputKeys()
|
||||
// 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.
|
||||
// FIXME: In the current version this is setting key data immediately. This will evolve into a trickling queue.
|
||||
void ImGuiIO::AddKeyEvent(ImGuiKey key, bool down)
|
||||
{
|
||||
//if (e->Down) { IMGUI_DEBUG_LOG("AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); }
|
||||
if (key == ImGuiKey_None)
|
||||
return;
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
|
||||
IM_ASSERT(ImGui::IsNamedKey(key)); // Backend needs to pass a valid ImGuiKey_ constant. 0..511 values are legacy native key codes which are not accepted by this API.
|
||||
|
||||
// Verify that backend isn't mixing up using new io.AddKeyEvent() api and old io.KeysDown[] + io.KeyMap[] data.
|
||||
@ -1289,15 +1301,18 @@ void ImGuiIO::AddKeyEvent(ImGuiKey key, bool down)
|
||||
if (BackendUsingLegacyKeyArrays == -1)
|
||||
for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++)
|
||||
IM_ASSERT(KeyMap[n] == -1 && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!");
|
||||
#endif
|
||||
BackendUsingLegacyKeyArrays = 0;
|
||||
#endif
|
||||
|
||||
// Write key
|
||||
const int keydata_index = (key - ImGuiKey_KeysData_OFFSET);
|
||||
KeysData[keydata_index].Down = down;
|
||||
ImGuiInputEvent e;
|
||||
e.Type = ImGuiInputEventType_Key;
|
||||
e.Source = ImGuiInputSource_Keyboard;
|
||||
e.Key.Key = key;
|
||||
e.Key.Down = down;
|
||||
g.InputEventsQueue.push_back(e);
|
||||
}
|
||||
|
||||
// [Optional] Call add AddKeyEvent().
|
||||
// [Optional] Call after AddKeyEvent().
|
||||
// Specify native keycode, scancode + Specify index for legacy <1.87 IsKeyXXX() functions with native indices.
|
||||
// If you are writing a backend in 2022 or don't use IsKeyXXX() with native values that are not ImGuiKey values, you can avoid calling this.
|
||||
void ImGuiIO::SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index)
|
||||
@ -1322,18 +1337,68 @@ void ImGuiIO::SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native
|
||||
|
||||
void ImGuiIO::AddKeyModsEvent(ImGuiKeyModFlags modifiers)
|
||||
{
|
||||
KeyMods = modifiers;
|
||||
KeyCtrl = (modifiers & ImGuiKeyModFlags_Ctrl) != 0;
|
||||
KeyShift = (modifiers & ImGuiKeyModFlags_Shift) != 0;
|
||||
KeyAlt = (modifiers & ImGuiKeyModFlags_Alt) != 0;
|
||||
KeySuper = (modifiers & ImGuiKeyModFlags_Super) != 0;
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
|
||||
|
||||
ImGuiInputEvent e;
|
||||
e.Type = ImGuiInputEventType_KeyMods;
|
||||
e.Source = ImGuiInputSource_Keyboard;
|
||||
e.KeyMods.Mods = modifiers;
|
||||
g.InputEventsQueue.push_back(e);
|
||||
}
|
||||
|
||||
// Queue a mouse move event
|
||||
void ImGuiIO::AddMousePosEvent(float x, float y)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
|
||||
|
||||
ImGuiInputEvent e;
|
||||
e.Type = ImGuiInputEventType_MousePos;
|
||||
e.Source = ImGuiInputSource_Mouse;
|
||||
e.MousePos.PosX = x;
|
||||
e.MousePos.PosY = y;
|
||||
g.InputEventsQueue.push_back(e);
|
||||
}
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
ImGuiInputEvent e;
|
||||
e.Type = ImGuiInputEventType_MouseWheel;
|
||||
e.Source = ImGuiInputSource_Mouse;
|
||||
e.MouseWheel.WheelX = wheel_x;
|
||||
e.MouseWheel.WheelY = wheel_y;
|
||||
g.InputEventsQueue.push_back(e);
|
||||
}
|
||||
|
||||
void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
|
||||
IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT);
|
||||
|
||||
ImGuiInputEvent e;
|
||||
e.Type = ImGuiInputEventType_MouseButton;
|
||||
e.Source = ImGuiInputSource_Mouse;
|
||||
e.MouseButton.Button = mouse_button;
|
||||
e.MouseButton.Down = down;
|
||||
g.InputEventsQueue.push_back(e);
|
||||
}
|
||||
|
||||
void ImGuiIO::AddFocusEvent(bool focused)
|
||||
{
|
||||
// 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.
|
||||
AppFocusLost = !focused;
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
|
||||
|
||||
ImGuiInputEvent e;
|
||||
e.Type = ImGuiInputEventType_Focus;
|
||||
e.AppFocused.Focused = focused;
|
||||
g.InputEventsQueue.push_back(e);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -4014,7 +4079,7 @@ static void ImGui::UpdateMouseInputs()
|
||||
|
||||
// Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well)
|
||||
if (IsMousePosValid(&io.MousePos))
|
||||
io.MousePos = g.MouseLastValidPos = ImFloor(io.MousePos);
|
||||
io.MousePos = g.MouseLastValidPos = ImFloorSigned(io.MousePos);
|
||||
|
||||
// If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta
|
||||
if (IsMousePosValid(&io.MousePos) && IsMousePosValid(&io.MousePosPrev))
|
||||
@ -4375,13 +4440,9 @@ void ImGui::NewFrame()
|
||||
//if (g.IO.AppFocusLost)
|
||||
// ClosePopupsExceptModals();
|
||||
|
||||
// Clear buttons state when focus is lost
|
||||
// (this is useful so e.g. releasing Alt after focus loss on Alt-Tab doesn't trigger the Alt menu toggle)
|
||||
if (g.IO.AppFocusLost)
|
||||
{
|
||||
g.IO.ClearInputKeys();
|
||||
g.IO.AppFocusLost = false;
|
||||
}
|
||||
// Process input queue (trickle as many events as possible)
|
||||
g.InputEventsTrail.resize(0);
|
||||
UpdateInputEvents(g.IO.ConfigInputEventQueue);
|
||||
|
||||
// Update keyboard input state
|
||||
UpdateKeyboardInputs();
|
||||
@ -7998,8 +8059,8 @@ static const char* const GKeyNames[] =
|
||||
"Backslash", "RightBracket", "GraveAccent", "CapsLock", "ScrollLock", "NumLock", "PrintScreen",
|
||||
"Pause", "Keypad0", "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6",
|
||||
"Keypad7", "Keypad8", "Keypad9", "KeypadDecimal", "KeypadDivide", "KeypadMultiply",
|
||||
"KeypadSubtract", "KeypadAdd", "KeypadEnter", "KeypadEqual", "LeftShift", "LeftControl",
|
||||
"LeftAlt", "LeftSuper", "RightShift", "RightControl", "RightAlt", "RightSuper", "Menu",
|
||||
"KeypadSubtract", "KeypadAdd", "KeypadEnter", "KeypadEqual", "LeftCtrl", "LeftShift",
|
||||
"LeftAlt", "LeftSuper", "RightCtrl", "RightShift", "RightAlt", "RightSuper", "Menu",
|
||||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H",
|
||||
"I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
|
||||
"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12"
|
||||
@ -8238,6 +8299,134 @@ static const char* GetInputSourceName(ImGuiInputSource source)
|
||||
}
|
||||
|
||||
|
||||
// Process input queue
|
||||
// - trickle_fast_inputs = false : process all events, turn into flattened input state (e.g. successive down/up/down/up will be lost)
|
||||
// - trickle_fast_inputs = true : process as many events as possible (successive down/up/down/up will be trickled over several frames so nothing is lost) (new feature in 1.87)
|
||||
void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiIO& io = g.IO;
|
||||
|
||||
bool mouse_moved = false, mouse_wheeled = false, key_changed = false, text_inputed = false;
|
||||
int mouse_button_changed = 0x00, key_mods_changed = 0x00;
|
||||
ImBitArray<ImGuiKey_KeysData_SIZE> key_changed_mask;
|
||||
|
||||
int event_n = 0;
|
||||
for (; event_n < g.InputEventsQueue.Size; event_n++)
|
||||
{
|
||||
const ImGuiInputEvent* e = &g.InputEventsQueue[event_n];
|
||||
if (e->Type == ImGuiInputEventType_MousePos)
|
||||
{
|
||||
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()
|
||||
if (io.MousePos.x != event_pos.x || io.MousePos.y != event_pos.y)
|
||||
{
|
||||
// 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 || key_mods_changed || text_inputed))
|
||||
break;
|
||||
io.MousePos = event_pos;
|
||||
mouse_moved = true;
|
||||
}
|
||||
}
|
||||
else if (e->Type == ImGuiInputEventType_MouseButton)
|
||||
{
|
||||
const ImGuiMouseButton button = e->MouseButton.Button;
|
||||
IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT);
|
||||
if (io.MouseDown[button] != e->MouseButton.Down)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
else if (e->Type == ImGuiInputEventType_MouseWheel)
|
||||
{
|
||||
if (e->MouseWheel.WheelX != 0.0f || e->MouseWheel.WheelY != 0.0f)
|
||||
{
|
||||
// Trickling Rule: Stop processing queued events if we got multiple action on the event
|
||||
if (trickle_fast_inputs && (mouse_wheeled || mouse_button_changed != 0))
|
||||
break;
|
||||
io.MouseWheelH += e->MouseWheel.WheelX;
|
||||
io.MouseWheel += e->MouseWheel.WheelY;
|
||||
mouse_wheeled = true;
|
||||
}
|
||||
}
|
||||
else if (e->Type == ImGuiInputEventType_Key)
|
||||
{
|
||||
IM_ASSERT(e->Key.Key != ImGuiKey_None);
|
||||
const int keydata_index = (e->Key.Key - ImGuiKey_KeysData_OFFSET);
|
||||
ImGuiKeyData* keydata = &io.KeysData[keydata_index];
|
||||
if (keydata->Down != e->Key.Down)
|
||||
{
|
||||
// Trickling Rule: Stop processing queued events if we got multiple action on the same button
|
||||
if (trickle_fast_inputs && (key_changed_mask.TestBit(keydata_index) || text_inputed || mouse_button_changed != 0))
|
||||
break;
|
||||
keydata->Down = e->Key.Down;
|
||||
key_changed = true;
|
||||
key_changed_mask.SetBit(keydata_index);
|
||||
}
|
||||
}
|
||||
else if (e->Type == ImGuiInputEventType_KeyMods)
|
||||
{
|
||||
const ImGuiKeyModFlags modifiers = e->KeyMods.Mods;
|
||||
if (io.KeyMods != modifiers)
|
||||
{
|
||||
// Trickling Rule: Stop processing queued events if we got multiple action on the same button
|
||||
ImGuiKeyModFlags modifiers_that_are_changing = (io.KeyMods ^ modifiers);
|
||||
if (trickle_fast_inputs && (key_mods_changed & modifiers_that_are_changing) != 0)
|
||||
break;
|
||||
io.KeyMods = modifiers;
|
||||
io.KeyCtrl = (modifiers & ImGuiKeyModFlags_Ctrl) != 0;
|
||||
io.KeyShift = (modifiers & ImGuiKeyModFlags_Shift) != 0;
|
||||
io.KeyAlt = (modifiers & ImGuiKeyModFlags_Alt) != 0;
|
||||
io.KeySuper = (modifiers & ImGuiKeyModFlags_Super) != 0;
|
||||
key_mods_changed |= modifiers_that_are_changing;
|
||||
}
|
||||
}
|
||||
else if (e->Type == ImGuiInputEventType_Char)
|
||||
{
|
||||
// Trickling Rule: Stop processing queued events if keys/mouse have been interacted with
|
||||
if (trickle_fast_inputs && (key_changed || mouse_button_changed != 0 || mouse_moved || mouse_wheeled))
|
||||
break;
|
||||
unsigned int c = e->Text.Char;
|
||||
io.InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID);
|
||||
text_inputed = true;
|
||||
}
|
||||
else if (e->Type == ImGuiInputEventType_Focus)
|
||||
{
|
||||
// We intentionally overwrite this and process lower, in order to give a chance
|
||||
// to multi-viewports backends to queue AddFocusEvent(false) + AddFocusEvent(true) in same frame.
|
||||
io.AppFocusLost = !e->AppFocused.Focused;
|
||||
}
|
||||
else
|
||||
{
|
||||
IM_ASSERT(0 && "Unknown event!");
|
||||
}
|
||||
}
|
||||
|
||||
// Record trail (for domain-specific applications wanting to access a precise trail)
|
||||
for (int n = 0; n < event_n; n++)
|
||||
g.InputEventsTrail.push_back(g.InputEventsQueue[n]);
|
||||
|
||||
// Remaining events will be processed on the next frame
|
||||
if (event_n == g.InputEventsQueue.Size)
|
||||
g.InputEventsQueue.resize(0);
|
||||
else
|
||||
g.InputEventsQueue.erase(g.InputEventsQueue.Data, g.InputEventsQueue.Data + event_n);
|
||||
|
||||
// Clear buttons state when focus is lost
|
||||
// (this is useful so e.g. releasing Alt after focus loss on Alt-Tab doesn't trigger the Alt menu toggle)
|
||||
if (g.IO.AppFocusLost)
|
||||
{
|
||||
g.IO.ClearInputKeys();
|
||||
g.IO.AppFocusLost = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] ERROR CHECKING
|
||||
//-----------------------------------------------------------------------------
|
||||
|
Reference in New Issue
Block a user