Merge branch 'master' into docking

# Conflicts:
#	docs/CHANGELOG.txt
#	imgui.cpp
#	imgui.h
This commit is contained in:
ocornut 2022-12-01 20:22:27 +01:00
commit 3ea0fad204
14 changed files with 461 additions and 282 deletions

View File

@ -7,7 +7,7 @@
// [X] Platform: Clipboard support (from Allegro 5.1.12)
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// Issues:
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
// [ ] Renderer: The renderer is suboptimal as we need to convert vertices manually.
// [ ] Platform: Missing gamepad support.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
@ -17,6 +17,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2022-11-30: Renderer: Restoring using al_draw_indexed_prim() when Allegro version is >= 5.2.5.
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
@ -37,6 +38,7 @@
// 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
// 2018-06-13: Platform: Added clipboard support (from Allegro 5.1.12).
// 2018-06-13: Renderer: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
// 2018-06-13: Renderer: Stopped using al_draw_indexed_prim() as it is buggy in Allegro's DX9 backend.
// 2018-06-13: Renderer: Backup/restore transform and clipping rectangle.
// 2018-06-11: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 2018-04-18: Misc: Renamed file from imgui_impl_a5.cpp to imgui_impl_allegro5.cpp.
@ -56,13 +58,27 @@
#ifdef _WIN32
#include <allegro5/allegro_windows.h>
#endif
#define ALLEGRO_HAS_CLIPBOARD (ALLEGRO_VERSION_INT >= ((5 << 24) | (1 << 16) | (12 << 8))) // Clipboard only supported from Allegro 5.1.12
#define ALLEGRO_HAS_CLIPBOARD (ALLEGRO_VERSION_INT >= ((5 << 24) | (1 << 16) | (12 << 8))) // Clipboard only supported from Allegro 5.1.12
#define ALLEGRO_HAS_DRAW_INDEXED_PRIM (ALLEGRO_VERSION_INT >= ((5 << 24) | (2 << 16) | ( 5 << 8))) // DX9 implementation of al_draw_indexed_prim() got fixed in Allegro 5.2.5
// Visual Studio warnings
#ifdef _MSC_VER
#pragma warning (disable: 4127) // condition expression is constant
#endif
struct ImDrawVertAllegro
{
ImVec2 pos;
ImVec2 uv;
ALLEGRO_COLOR col;
};
// FIXME-OPT: Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 float as well..
// FIXME-OPT: Consider inlining al_map_rgba()?
// see https://github.com/liballeg/allegro5/blob/master/src/pixels.c#L554
// and https://github.com/liballeg/allegro5/blob/master/include/allegro5/internal/aintern_pixels.h
#define DRAW_VERT_IMGUI_TO_ALLEGRO(DST, SRC) { (DST)->pos = (SRC)->pos; (DST)->uv = (SRC)->uv; unsigned char* c = (unsigned char*)&(SRC)->col; (DST)->col = al_map_rgba(c[0], c[1], c[2], c[3]); }
// Allegro Data
struct ImGui_ImplAllegro5_Data
{
@ -73,6 +89,9 @@ struct ImGui_ImplAllegro5_Data
ALLEGRO_VERTEX_DECL* VertexDecl;
char* ClipboardTextData;
ImVector<ImDrawVertAllegro> BufVertices;
ImVector<int> BufIndices;
ImGui_ImplAllegro5_Data() { memset((void*)this, 0, sizeof(*this)); }
};
@ -81,13 +100,6 @@ struct ImGui_ImplAllegro5_Data
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
static ImGui_ImplAllegro5_Data* ImGui_ImplAllegro5_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplAllegro5_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr; }
struct ImDrawVertAllegro
{
ImVec2 pos;
ImVec2 uv;
ALLEGRO_COLOR col;
};
static void ImGui_ImplAllegro5_SetupRenderState(ImDrawData* draw_data)
{
// Setup blending
@ -132,35 +144,40 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
// Allegro's implementation of al_draw_indexed_prim() for DX9 is completely broken. Unindex our buffers ourselves.
// FIXME-OPT: Unfortunately Allegro doesn't support 32-bit packed colors so we have to convert them to 4 float as well..
static ImVector<ImDrawVertAllegro> vertices;
vertices.resize(cmd_list->IdxBuffer.Size);
for (int i = 0; i < cmd_list->IdxBuffer.Size; i++)
ImVector<ImDrawVertAllegro>& vertices = bd->BufVertices;
#if ALLEGRO_HAS_DRAW_INDEXED_PRIM
vertices.resize(cmd_list->VtxBuffer.Size);
for (int i = 0; i < cmd_list->VtxBuffer.Size; i++)
{
const ImDrawVert* src_v = &cmd_list->VtxBuffer[cmd_list->IdxBuffer[i]];
const ImDrawVert* src_v = &cmd_list->VtxBuffer[i];
ImDrawVertAllegro* dst_v = &vertices[i];
dst_v->pos = src_v->pos;
dst_v->uv = src_v->uv;
unsigned char* c = (unsigned char*)&src_v->col;
dst_v->col = al_map_rgba(c[0], c[1], c[2], c[3]);
DRAW_VERT_IMGUI_TO_ALLEGRO(dst_v, src_v);
}
const int* indices = nullptr;
if (sizeof(ImDrawIdx) == 2)
{
// FIXME-OPT: Unfortunately Allegro doesn't support 16-bit indices.. You can '#define ImDrawIdx int' in imconfig.h to request Dear ImGui to output 32-bit indices.
// FIXME-OPT: Allegro doesn't support 16-bit indices.
// You can '#define ImDrawIdx int' in imconfig.h to request Dear ImGui to output 32-bit indices.
// Otherwise, we convert them from 16-bit to 32-bit at runtime here, which works perfectly but is a little wasteful.
static ImVector<int> indices_converted;
indices_converted.resize(cmd_list->IdxBuffer.Size);
bd->BufIndices.resize(cmd_list->IdxBuffer.Size);
for (int i = 0; i < cmd_list->IdxBuffer.Size; ++i)
indices_converted[i] = (int)cmd_list->IdxBuffer.Data[i];
indices = indices_converted.Data;
bd->BufIndices[i] = (int)cmd_list->IdxBuffer.Data[i];
indices = bd->BufIndices.Data;
}
else if (sizeof(ImDrawIdx) == 4)
{
indices = (const int*)cmd_list->IdxBuffer.Data;
}
#else
// Allegro's implementation of al_draw_indexed_prim() for DX9 was broken until 5.2.5. Unindex buffers ourselves while converting vertex format.
vertices.resize(cmd_list->IdxBuffer.Size);
for (int i = 0; i < cmd_list->IdxBuffer.Size; i++)
{
const ImDrawVert* src_v = &cmd_list->VtxBuffer[cmd_list->IdxBuffer[i]];
ImDrawVertAllegro* dst_v = &vertices[i];
DRAW_VERT_IMGUI_TO_ALLEGRO(dst_v, src_v);
}
#endif
// Render command lists
ImVec2 clip_off = draw_data->DisplayPos;
@ -187,7 +204,11 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
// Apply scissor/clipping rectangle, Draw
ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->GetTexID();
al_set_clipping_rectangle(clip_min.x, clip_min.y, clip_max.x - clip_min.x, clip_max.y - clip_min.y);
#if ALLEGRO_HAS_DRAW_INDEXED_PRIM
al_draw_indexed_prim(&vertices[0], bd->VertexDecl, texture, &indices[pcmd->IdxOffset], pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
#else
al_draw_prim(&vertices[0], bd->VertexDecl, texture, pcmd->IdxOffset, pcmd->IdxOffset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
#endif
}
}
}

View File

@ -1,6 +1,7 @@
// dear imgui: Platform Backend for OSX / Cocoa
// This needs to be used along with a Renderer (e.g. OpenGL2, OpenGL3, Vulkan, Metal..)
// [ALPHA] Early backend, not well tested. If you want a portable application, prefer using the GLFW or SDL platform Backends on Mac.
// - Not well tested. If you want a portable application, prefer using the GLFW or SDL platform Backends on Mac.
// - Requires linking with the GameController framework ("-framework GameController").
// Implemented features:
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.

View File

@ -1,6 +1,7 @@
// dear imgui: Platform Backend for OSX / Cocoa
// This needs to be used along with a Renderer (e.g. OpenGL2, OpenGL3, Vulkan, Metal..)
// [ALPHA] Early backend, not well tested. If you want a portable application, prefer using the GLFW or SDL platform Backends on Mac.
// - Not well tested. If you want a portable application, prefer using the GLFW or SDL platform Backends on Mac.
// - Requires linking with the GameController framework ("-framework GameController").
// Implemented features:
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.

View File

@ -1,4 +1,4 @@
// dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications)
// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications)
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// Implemented features:

View File

@ -1,4 +1,4 @@
// dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications)
// dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications)
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// Implemented features:

View File

@ -98,16 +98,49 @@ Other changes:
Note that Linux/Mac still have inconsistent support for multi-viewports. If you want to help see https://github.com/ocornut/imgui/issues/2117.
-----------------------------------------------------------------------
VERSION 1.89.2 WIP (In Progress)
-----------------------------------------------------------------------
Breaking changes:
Other changes:
- Fixed cases where CTRL+Tab or Modal can occasionally lead to the creation of ImDrawCmd with
zero triangles, which would makes the render loop of some backends assert (e.g. Metal with
debugging, Allegro). (#4857, #5937)
- Tables, Columns: Fixed cases where empty columns may lead to empty ImDrawCmd. (#4857, #5937)
- Inputs, Scrolling: better selection of scrolling window when hovering nested windows
and when backend/OS is emitting dual-axis wheeling inputs (typically touch pads on macOS).
We now select a primary axis based on recent events, and select a target window based on it.
We expect this behavior to be further improved/tweaked. (#3795, #4559) [@ocornut, @folays]
- Text: fixed layouting of wrapped-text block when the last source line is above the
clipping region. Regression added in 1.89. (#5720, #5919)
- Fonts: added a 'void* UserData' field in ImFontAtlas, as a convenience for use by
applications using multiple font atlases.
- Demo: simplified "Inputs" section, moved contents to Metrics->Inputs.
- Debug Tools: Metrics: added "Inputs" section, moved from Demo for consistency.
- Misc: fixed parameters to IMGUI_DEBUG_LOG() not being dead-stripped when building
with IMGUI_DISABLE_DEBUG_TOOLS is used. (#5901) [@Teselka]
- Misc: fixed compile-time detection of SSE features on MSVC 32-bits builds. (#5943) [@TheMostDiligent]
- Backends: Allegro5: restoring using al_draw_indexed_prim() when Allegro version is >= 5.2.5. (#5937) [@Espyo]
-----------------------------------------------------------------------
VERSION 1.89.1 (Released 2022-11-24)
-----------------------------------------------------------------------
Decorated log and release notes: https://github.com/ocornut/imgui/releases/tag/v1.89.1
Other changes:
- Scrolling, Focus: fixed SetKeyboardFocusHere()/SetItemDefaultFocus() during a window-appearing
frame (and associated lower-level functions e.g. ScrollToRectEx()) from not centering item. (#5902)
- Inputs: fixed moving a window or drag and dropping from preventing input-owner-unaware code
from accessing keys. (#5888, #4921, #456)
- Inputs, IO: reworked ImGuiMod_Shortcut to redirect to Ctrl/Super at runtime instead of
compile-time, being consistent with our support for io.ConfigMacOSXBehaviors and making it
easier for bindings generators to process that value. (#5923, #456)
- Inputs: fixed moving a window or drag and dropping from capturing mods. (#5888, #4921, #456)
- Layout: fixed End()/EndChild() incorrectly asserting if users manipulates cursor position
inside a collapsed/culled window and IMGUI_DISABLE_OBSOLETE_FUNCTIONS is enabled. (#5548, #5911)
@ -150,6 +183,11 @@ Breaking changes:
Without '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' this will silently be fixed until we obsolete it.
(This incorrect pattern has been mentioned or suggested in: #4510, #3355, #1760, #1490, #4152, #150,
threads have been amended to refer to this issue).
- Inputs: ImGuiKey is now a typed enum, allowing ImGuiKey_XXX symbols to be named in debuggers. (#4921)
This will require uses of legacy backend-dependent indices to be casted, e.g.
- with imgui_impl_glfw: IsKeyPressed(GLFW_KEY_A) -> IsKeyPressed((ImGuiKey)GLFW_KEY_A);
- with imgui_impl_win32: IsKeyPressed('A') -> IsKeyPressed((ImGuiKey)'A')
- etc. however if you are upgrading code you might as well use the backend-agnostic IsKeyPressed(ImGuiKey_A) now.
- Renamed and merged keyboard modifiers key enums and flags into a same set: (#4921, #456)
- ImGuiKey_ModCtrl and ImGuiModFlags_Ctrl -> ImGuiMod_Ctrl
- ImGuiKey_ModShift and ImGuiModFlags_Shift -> ImGuiMod_Shift
@ -278,7 +316,6 @@ Other Changes:
- ImDrawList: Not using alloca() anymore, lift single polygon size limits. (#5704, #1811)
- Platform IME: [Windows] Removed call to ImmAssociateContextEx() leading to freeze on some setups.
(#2589, #5535, #5264, #4972)
- Misc: ImGuiKey is now a typed enum, allowing ImGuiKey_XXX symbols to be named in debuggers. (#4921)
- Misc: better error reporting for PopStyleColor()/PopStyleVar() + easier to recover. (#1651)
- Misc: io.Framerate moving average now converge in 60 frames instead of 120. (#5236, #4138)
- Debug Tools: Debug Log: Visually locate items when hovering a 0xXXXXXXXX value. (#5855)

View File

@ -323,7 +323,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- font: fix AddRemapChar() to work before atlas has been built.
- font: (api breaking) remove "TTF" from symbol names. also because it now supports OTF.
- font/opt: Considering storing standalone AdvanceX table as 16-bit fixed point integer?
- font/opt: Glyph currently 40 bytes (2+9*4). Consider storing UV as 16 bits integer? (->32 bytes). X0/Y0/X1/Y1 as 16 fixed-point integers? Or X0/Y0 as float and X1/Y1 as fixed8_8?
- font/opt: Glyph currently 40 bytes (2+9*4). Consider storing UV as 16-bits integer? (->32 bytes). X0/Y0/X1/Y1 as 16 fixed-point integers? Or X0/Y0 as float and X1/Y1 as fixed8_8?
- nav: some features such as PageUp/Down/Home/End should probably work without ImGuiConfigFlags_NavEnableKeyboard? (where do we draw the line? how about CTRL+Tab)
! nav: never clear NavId on some setup (e.g. gamepad centric)

334
imgui.cpp
View File

@ -1,4 +1,4 @@
// dear imgui, v1.89.1
// dear imgui, v1.89.2 WIP
// (main code and documentation)
// Help:
@ -403,6 +403,11 @@ CODE
the ImGuiKey_ModXXX were introduced in 1.87 and mostly used by backends.
the ImGuiModFlags_XXX have been exposed in imgui.h but not really used by any public api only by third-party extensions.
exceptionally commenting out the older ImGuiKeyModFlags_XXX names ahead of obsolescence schedule to reduce confusion and because they were not meant to be used anyway.
- 2022/09/20 (1.89) - ImGuiKey is now a typed enum, allowing ImGuiKey_XXX symbols to be named in debuggers.
this will require uses of legacy backend-dependent indices to be casted, e.g.
- with imgui_impl_glfw: IsKeyPressed(GLFW_KEY_A) -> IsKeyPressed((ImGuiKey)GLFW_KEY_A);
- with imgui_impl_win32: IsKeyPressed('A') -> IsKeyPressed((ImGuiKey)'A')
- etc. However if you are upgrading code you might well use the better, backend-agnostic IsKeyPressed(ImGuiKey_A) now!
- 2022/09/12 (1.89) - removed the bizarre legacy default argument for 'TreePush(const void* ptr = NULL)', always pass a pointer value explicitly. NULL/nullptr is ok but require cast, e.g. TreePush((void*)nullptr);
- 2022/09/05 (1.89) - commented out redirecting functions/enums names that were marked obsolete in 1.77 and 1.78 (June 2020):
- DragScalar(), DragScalarN(), DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(): For old signatures ending with (..., const char* format, float power = 1.0f) -> use (..., format ImGuiSliderFlags_Logarithmic) if power != 1.0f.
@ -1379,6 +1384,7 @@ void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value)
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
IM_ASSERT(ImGui::IsNamedKeyOrModKey(key)); // Backend needs to pass a valid ImGuiKey_ constant. 0..511 values are legacy native key codes which are not accepted by this API.
IM_ASSERT(!ImGui::IsAliasKey(key)); // Backend cannot submit ImGuiKey_MouseXXX values they are automatically inferred from AddMouseXXX() events.
IM_ASSERT(key != ImGuiMod_Shortcut); // We could easily support the translation here but it seems saner to not accept it (TestEngine perform a translation itself)
// Verify that backend isn't mixing up using new io.AddKeyEvent() api and old io.KeysDown[] + io.KeyMap[] data.
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
@ -2928,11 +2934,14 @@ bool ImGuiListClipper::Step()
if (need_items_height && ItemsHeight > 0.0f)
IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): computed ItemsHeight: %.2f.\n", ItemsHeight);
if (ret)
{
IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): display %d to %d.\n", DisplayStart, DisplayEnd);
}
else
{
IMGUI_DEBUG_LOG_CLIPPER("Clipper: Step(): End.\n");
if (!ret)
End();
}
return ret;
}
@ -4321,16 +4330,15 @@ static void UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt)
rt->Entries.swap(rt->EntriesNext); // Swap new and old indexes
}
// [Internal] Do not use directly (should read io.KeyMods instead)
static ImGuiKeyChord GetMergedModsFromBools()
// [Internal] Do not use directly
static ImGuiKeyChord GetMergedModsFromKeys()
{
ImGuiContext& g = *GImGui;
ImGuiKeyChord key_chord = 0;
if (g.IO.KeyCtrl) { key_chord |= ImGuiMod_Ctrl; }
if (g.IO.KeyShift) { key_chord |= ImGuiMod_Shift; }
if (g.IO.KeyAlt) { key_chord |= ImGuiMod_Alt; }
if (g.IO.KeySuper) { key_chord |= ImGuiMod_Super; }
return key_chord;
ImGuiKeyChord mods = 0;
if (ImGui::IsKeyDown(ImGuiMod_Ctrl)) { mods |= ImGuiMod_Ctrl; }
if (ImGui::IsKeyDown(ImGuiMod_Shift)) { mods |= ImGuiMod_Shift; }
if (ImGui::IsKeyDown(ImGuiMod_Alt)) { mods |= ImGuiMod_Alt; }
if (ImGui::IsKeyDown(ImGuiMod_Super)) { mods |= ImGuiMod_Super; }
return mods;
}
static void ImGui::UpdateKeyboardInputs()
@ -4403,16 +4411,24 @@ static void ImGui::UpdateKeyboardInputs()
#undef NAV_MAP_KEY
}
#endif
#endif
// Synchronize io.KeyMods with individual modifiers io.KeyXXX bools, update aliases
io.KeyMods = GetMergedModsFromBools();
// Update aliases
for (int n = 0; n < ImGuiMouseButton_COUNT; n++)
UpdateAliasKey(MouseButtonToKey(n), io.MouseDown[n], io.MouseDown[n] ? 1.0f : 0.0f);
UpdateAliasKey(ImGuiKey_MouseWheelX, io.MouseWheelH != 0.0f, io.MouseWheelH);
UpdateAliasKey(ImGuiKey_MouseWheelY, io.MouseWheel != 0.0f, io.MouseWheel);
// Synchronize io.KeyMods and io.KeyXXX values.
// - New backends (1.87+): send io.AddKeyEvent(ImGuiMod_XXX) -> -> (here) deriving io.KeyMods + io.KeyXXX from key array.
// - Legacy backends: set io.KeyXXX bools -> (above) set key array from io.KeyXXX -> (here) deriving io.KeyMods + io.KeyXXX from key array.
// So with legacy backends the 4 values will do a unnecessary back-and-forth but it makes the code simpler and future facing.
io.KeyMods = GetMergedModsFromKeys();
io.KeyCtrl = (io.KeyMods & ImGuiMod_Ctrl) != 0;
io.KeyShift = (io.KeyMods & ImGuiMod_Shift) != 0;
io.KeyAlt = (io.KeyMods & ImGuiMod_Alt) != 0;
io.KeySuper = (io.KeyMods & ImGuiMod_Super) != 0;
// Clear gamepad data if disabled
if ((io.BackendFlags & ImGuiBackendFlags_HasGamepad) == 0)
for (int i = ImGuiKey_Gamepad_BEGIN; i < ImGuiKey_Gamepad_END; i++)
@ -4519,13 +4535,58 @@ static void LockWheelingWindow(ImGuiWindow* window, float wheel_amount)
IMGUI_DEBUG_LOG_IO("LockWheelingWindow() \"%s\"\n", window ? window->Name : "NULL");
g.WheelingWindow = window;
g.WheelingWindowRefMousePos = g.IO.MousePos;
if (window == NULL)
{
g.WheelingWindowStartFrame = -1;
g.WheelingAxisAvg = ImVec2(0.0f, 0.0f);
}
}
static ImGuiWindow* FindBestWheelingWindow(const ImVec2& wheel)
{
// For each axis, find window in the hierarchy that may want to use scrolling
ImGuiContext& g = *GImGui;
ImGuiWindow* windows[2] = { NULL, NULL };
for (int axis = 0; axis < 2; axis++)
if (wheel[axis] != 0.0f)
for (ImGuiWindow* window = windows[axis] = g.HoveredWindow; window->Flags & ImGuiWindowFlags_ChildWindow; window = windows[axis] = window->ParentWindow)
{
// Bubble up into parent window if:
// - a child window doesn't allow any scrolling.
// - a child window has the ImGuiWindowFlags_NoScrollWithMouse flag.
//// - a child window doesn't need scrolling because it is already at the edge for the direction we are going in (FIXME-WIP)
const bool has_scrolling = (window->ScrollMax[axis] != 0.0f);
const bool inputs_disabled = (window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs);
//const bool scrolling_past_limits = (wheel_v < 0.0f) ? (window->Scroll[axis] <= 0.0f) : (window->Scroll[axis] >= window->ScrollMax[axis]);
if (has_scrolling && !inputs_disabled) // && !scrolling_past_limits)
break; // select this window
}
if (windows[0] == NULL && windows[1] == NULL)
return NULL;
// If there's only one window or only one axis then there's no ambiguity
if (windows[0] == windows[1] || windows[0] == NULL || windows[1] == NULL)
return windows[1] ? windows[1] : windows[0];
// If candidate are different windows we need to decide which one to prioritize
// - First frame: only find a winner if one axis is zero.
// - Subsequent frames: only find a winner when one is more than the other.
if (g.WheelingWindowStartFrame == -1)
g.WheelingWindowStartFrame = g.FrameCount;
if ((g.WheelingWindowStartFrame == g.FrameCount && wheel.x != 0.0f && wheel.y != 0.0f) || (g.WheelingAxisAvg.x == g.WheelingAxisAvg.y))
{
g.WheelingWindowWheelRemainder = wheel;
return NULL;
}
return (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? windows[0] : windows[1];
}
void ImGui::UpdateMouseWheel()
{
ImGuiContext& g = *GImGui;
// Reset the locked window if we move the mouse or after the timer elapses
// Reset the locked window if we move the mouse or after the timer elapses.
// FIXME: Ideally we could refactor to have one timer for "changing window w/ same axis" and a shorter timer for "changing window or axis w/ other axis" (#3795)
if (g.WheelingWindow != NULL)
{
g.WheelingWindowReleaseTimer -= g.IO.DeltaTime;
@ -4538,8 +4599,6 @@ void ImGui::UpdateMouseWheel()
ImVec2 wheel;
wheel.x = TestKeyOwner(ImGuiKey_MouseWheelX, ImGuiKeyOwner_None) ? g.IO.MouseWheelH : 0.0f;
wheel.y = TestKeyOwner(ImGuiKey_MouseWheelY, ImGuiKeyOwner_None) ? g.IO.MouseWheel : 0.0f;
if (wheel.x == 0.0f && wheel.y == 0.0f)
return;
//IMGUI_DEBUG_LOG("MouseWheel X:%.3f Y:%.3f\n", wheel_x, wheel_y);
ImGuiWindow* mouse_window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow;
@ -4577,39 +4636,41 @@ void ImGui::UpdateMouseWheel()
wheel.y = 0.0f;
}
// Vertical Mouse Wheel scrolling
// Bubble up into parent window if:
// - a child window doesn't allow any scrolling.
// - a child window doesn't need scrolling because it is already at the edge for the direction we are going in.
// - a child window has the ImGuiWindowFlags_NoScrollWithMouse flag.
if (wheel.y != 0.0f)
{
ImGuiWindow* window = mouse_window;
while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
window = window->ParentWindow;
if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
{
LockWheelingWindow(mouse_window, wheel.y);
float max_step = window->InnerRect.GetHeight() * 0.67f;
float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));
SetScrollY(window, window->Scroll.y - wheel.y * scroll_step);
}
}
// Maintain a rough average of moving magnitude on both axises
// FIXME: should by based on wall clock time rather than frame-counter
g.WheelingAxisAvg.x = ImExponentialMovingAverage(g.WheelingAxisAvg.x, ImAbs(wheel.x), 30);
g.WheelingAxisAvg.y = ImExponentialMovingAverage(g.WheelingAxisAvg.y, ImAbs(wheel.y), 30);
// Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held
if (wheel.x != 0.0f)
{
ImGuiWindow* window = mouse_window;
while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
window = window->ParentWindow;
// In the rare situation where FindBestWheelingWindow() had to defer first frame of wheeling due to ambiguous main axis, reinject it now.
wheel += g.WheelingWindowWheelRemainder;
g.WheelingWindowWheelRemainder = ImVec2(0.0f, 0.0f);
if (wheel.x == 0.0f && wheel.y == 0.0f)
return;
// Mouse wheel scrolling: find target and apply
// - don't renew lock if axis doesn't apply on the window.
// - select a main axis when both axises are being moved.
if (ImGuiWindow* window = (g.WheelingWindow ? g.WheelingWindow : FindBestWheelingWindow(wheel)))
if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
{
LockWheelingWindow(mouse_window, wheel.x);
float max_step = window->InnerRect.GetWidth() * 0.67f;
float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));
SetScrollX(window, window->Scroll.x - wheel.x * scroll_step);
bool do_scroll[2] = { wheel.x != 0.0f && window->ScrollMax.x != 0.0f, wheel.y != 0.0f && window->ScrollMax.y != 0.0f };
if (do_scroll[ImGuiAxis_X] && do_scroll[ImGuiAxis_Y])
do_scroll[(g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? ImGuiAxis_Y : ImGuiAxis_X] = false;
if (do_scroll[ImGuiAxis_X])
{
LockWheelingWindow(window, wheel.x);
float max_step = window->InnerRect.GetWidth() * 0.67f;
float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));
SetScrollX(window, window->Scroll.x - wheel.x * scroll_step);
}
if (do_scroll[ImGuiAxis_Y])
{
LockWheelingWindow(window, wheel.y);
float max_step = window->InnerRect.GetHeight() * 0.67f;
float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));
SetScrollY(window, window->Scroll.y - wheel.y * scroll_step);
}
}
}
}
// 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)
@ -8566,9 +8627,12 @@ const char* ImGui::GetKeyName(ImGuiKey key)
return GKeyNames[key - ImGuiKey_NamedKey_BEGIN];
}
// ImGuiMod_Shortcut is translated to either Ctrl or Super.
void ImGui::GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size)
{
ImGuiContext& g = *GImGui;
if (key_chord & ImGuiMod_Shortcut)
key_chord = ConvertShortcutMod(key_chord);
ImFormatString(out_buf, (size_t)out_buf_size, "%s%s%s%s%s",
(key_chord & ImGuiMod_Ctrl) ? "Ctrl+" : "",
(key_chord & ImGuiMod_Shift) ? "Shift+" : "",
@ -8644,6 +8708,8 @@ ImGuiKeyRoutingData* ImGui::GetShortcutRoutingData(ImGuiKeyChord key_chord)
ImGuiContext& g = *GImGui;
ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable;
ImGuiKeyRoutingData* routing_data;
if (key_chord & ImGuiMod_Shortcut)
key_chord = ConvertShortcutMod(key_chord);
ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_);
if (key == ImGuiKey_None)
@ -8761,7 +8827,7 @@ bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiI
bool ImGui::TestShortcutRouting(ImGuiKeyChord key_chord, ImGuiID owner_id)
{
const ImGuiID routing_id = GetRoutingIdFromOwnerId(owner_id);
ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord);
ImGuiKeyRoutingData* routing_data = GetShortcutRoutingData(key_chord); // FIXME: Could avoid creating entry.
return routing_data->RoutingCurr == routing_id;
}
@ -9016,7 +9082,7 @@ static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e)
ImGuiContext& g = *GImGui;
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_MouseWheel) { IMGUI_DEBUG_LOG_IO("%s: MouseWheel (%.3f, %.3f)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY); return; }
if (e->Type == ImGuiInputEventType_MouseViewport){IMGUI_DEBUG_LOG_IO("%s: MouseViewport (0x%08X)\n", prefix, e->MouseViewport.HoveredViewportID); 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; }
if (e->Type == ImGuiInputEventType_Text) { IMGUI_DEBUG_LOG_IO("%s: Text: %c (U+%08X)\n", prefix, e->Text.Char, e->Text.Char); return; }
@ -9092,15 +9158,6 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
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;
@ -9257,12 +9314,14 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags
if (!SetShortcutRouting(key_chord, owner_id, flags))
return false;
ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
if (key_chord & ImGuiMod_Shortcut)
key_chord = ConvertShortcutMod(key_chord);
ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_);
if (g.IO.KeyMods != mods)
return false;
// Special storage location for mods
ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
if (key == ImGuiKey_None)
key = ConvertSingleModFlagToKey(mods);
@ -9418,9 +9477,9 @@ static void ImGui::ErrorCheckEndFrameSanityChecks()
// One possible reason leading to this assert is that your backends update inputs _AFTER_ NewFrame().
// It is known that when some modal native windows called mid-frame takes focus away, some backends such as GLFW will
// send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs.
// We silently accommodate for this case by ignoring/ the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0),
// We silently accommodate for this case by ignoring the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0),
// while still correctly asserting on mid-frame key press events.
const ImGuiKeyChord key_mods = GetMergedModsFromBools();
const ImGuiKeyChord key_mods = GetMergedModsFromKeys();
IM_ASSERT((key_mods == 0 || g.IO.KeyMods == key_mods) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods");
IM_UNUSED(key_mods);
@ -18416,6 +18475,55 @@ static int IMGUI_CDECL ViewportComparerByFrontMostStampCount(const void* lhs, co
return b->LastFrontMostStampCount - a->LastFrontMostStampCount;
}
// Draw an arbitrary US keyboard layout to visualize translated keys
void ImGui::DebugRenderKeyboardPreview(ImDrawList* draw_list)
{
const ImVec2 key_size = ImVec2(35.0f, 35.0f);
const float key_rounding = 3.0f;
const ImVec2 key_face_size = ImVec2(25.0f, 25.0f);
const ImVec2 key_face_pos = ImVec2(5.0f, 3.0f);
const float key_face_rounding = 2.0f;
const ImVec2 key_label_pos = ImVec2(7.0f, 4.0f);
const ImVec2 key_step = ImVec2(key_size.x - 1.0f, key_size.y - 1.0f);
const float key_row_offset = 9.0f;
ImVec2 board_min = GetCursorScreenPos();
ImVec2 board_max = ImVec2(board_min.x + 3 * key_step.x + 2 * key_row_offset + 10.0f, board_min.y + 3 * key_step.y + 10.0f);
ImVec2 start_pos = ImVec2(board_min.x + 5.0f - key_step.x, board_min.y);
struct KeyLayoutData { int Row, Col; const char* Label; ImGuiKey Key; };
const KeyLayoutData keys_to_display[] =
{
{ 0, 0, "", ImGuiKey_Tab }, { 0, 1, "Q", ImGuiKey_Q }, { 0, 2, "W", ImGuiKey_W }, { 0, 3, "E", ImGuiKey_E }, { 0, 4, "R", ImGuiKey_R },
{ 1, 0, "", ImGuiKey_CapsLock }, { 1, 1, "A", ImGuiKey_A }, { 1, 2, "S", ImGuiKey_S }, { 1, 3, "D", ImGuiKey_D }, { 1, 4, "F", ImGuiKey_F },
{ 2, 0, "", ImGuiKey_LeftShift },{ 2, 1, "Z", ImGuiKey_Z }, { 2, 2, "X", ImGuiKey_X }, { 2, 3, "C", ImGuiKey_C }, { 2, 4, "V", ImGuiKey_V }
};
// Elements rendered manually via ImDrawList API are not clipped automatically.
// While not strictly necessary, here IsItemVisible() is used to avoid rendering these shapes when they are out of view.
Dummy(board_max - board_min);
if (!IsItemVisible())
return;
draw_list->PushClipRect(board_min, board_max, true);
for (int n = 0; n < IM_ARRAYSIZE(keys_to_display); n++)
{
const KeyLayoutData* key_data = &keys_to_display[n];
ImVec2 key_min = ImVec2(start_pos.x + key_data->Col * key_step.x + key_data->Row * key_row_offset, start_pos.y + key_data->Row * key_step.y);
ImVec2 key_max = key_min + key_size;
draw_list->AddRectFilled(key_min, key_max, IM_COL32(204, 204, 204, 255), key_rounding);
draw_list->AddRect(key_min, key_max, IM_COL32(24, 24, 24, 255), key_rounding);
ImVec2 face_min = ImVec2(key_min.x + key_face_pos.x, key_min.y + key_face_pos.y);
ImVec2 face_max = ImVec2(face_min.x + key_face_size.x, face_min.y + key_face_size.y);
draw_list->AddRect(face_min, face_max, IM_COL32(193, 193, 193, 255), key_face_rounding, ImDrawFlags_None, 2.0f);
draw_list->AddRectFilled(face_min, face_max, IM_COL32(252, 252, 252, 255), key_face_rounding);
ImVec2 label_min = ImVec2(key_min.x + key_label_pos.x, key_min.y + key_label_pos.y);
draw_list->AddText(label_min, IM_COL32(64, 64, 64, 255), key_data->Label);
if (ImGui::IsKeyDown(key_data->Key))
draw_list->AddRectFilled(key_min, key_max, IM_COL32(255, 0, 0, 128), key_rounding);
}
draw_list->PopClipRect();
}
// Helper tool to diagnose between text encoding issues and font loading issues. Pass your UTF-8 string and verify that there are correct.
void ImGui::DebugTextEncoding(const char* str)
{
@ -18884,41 +18992,95 @@ void ImGui::ShowMetricsWindow(bool* p_open)
TreePop();
}
if (TreeNode("Key Owners & Shortcut Routing"))
if (TreeNode("Inputs"))
{
TextUnformatted("Key Owners:");
if (BeginListBox("##owners", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 8)))
Text("KEYBOARD/GAMEPAD/MOUSE KEYS");
{
for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
{
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key);
if (owner_data->OwnerCurr == ImGuiKeyOwner_None)
continue;
Text("%s: 0x%08X%s", GetKeyName(key), owner_data->OwnerCurr,
owner_data->LockUntilRelease ? " LockUntilRelease" : owner_data->LockThisFrame ? " LockThisFrame" : "");
DebugLocateItemOnHover(owner_data->OwnerCurr);
}
EndListBox();
// We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allows displaying the data for old/new backends.
// User code should never have to go through such hoops: old code may use native keycodes, new code may use ImGuiKey codes.
Indent();
#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } };
#else
struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key < 512 && GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array
//Text("Legacy raw:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key++) { if (io.KeysDown[key]) { SameLine(); Text("\"%s\" %d", GetKeyName(key), key); } }
#endif
Text("Keys down:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyDown(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); SameLine(); Text("(%.02f)", GetKeyData(key)->DownDuration); }
Text("Keys pressed:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyPressed(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); }
Text("Keys released:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !IsKeyReleased(key)) continue; SameLine(); Text(IsNamedKey(key) ? "\"%s\"" : "\"%s\" %d", GetKeyName(key), key); }
Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; SameLine(); Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public.
DebugRenderKeyboardPreview(GetWindowDrawList());
Unindent();
}
TextUnformatted("Shortcut Routing:");
if (BeginListBox("##routes", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 8)))
Text("MOUSE STATE");
{
for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
Indent();
if (IsMousePosValid())
Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
else
Text("Mouse pos: <INVALID>");
Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
int count = IM_ARRAYSIZE(io.MouseDown);
Text("Mouse down:"); for (int i = 0; i < count; i++) if (IsMouseDown(i)) { SameLine(); Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
Text("Mouse clicked:"); for (int i = 0; i < count; i++) if (IsMouseClicked(i)) { SameLine(); Text("b%d (%d)", i, io.MouseClickedCount[i]); }
Text("Mouse released:"); for (int i = 0; i < count; i++) if (IsMouseReleased(i)) { SameLine(); Text("b%d", i); }
Text("Mouse wheel: %.1f", io.MouseWheel);
Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused
Unindent();
}
Text("MOUSE WHEELING");
{
Indent();
Text("WheelingWindow: '%s'", g.WheelingWindow ? g.WheelingWindow->Name : "NULL");
Text("WheelingWindowReleaseTimer: %.2f", g.WheelingWindowReleaseTimer);
Text("WheelingAxisAvg[] = { %.3f, %.3f }, Main Axis: %s", g.WheelingAxisAvg.x, g.WheelingAxisAvg.y, (g.WheelingAxisAvg.x > g.WheelingAxisAvg.y) ? "X" : (g.WheelingAxisAvg.x < g.WheelingAxisAvg.y) ? "Y" : "<none>");
Unindent();
}
Text("KEY OWNERS");
{
Indent();
if (BeginListBox("##owners", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6)))
{
ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable;
for (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; )
for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
{
char key_chord_name[64];
ImGuiKeyRoutingData* routing_data = &rt->Entries[idx];
GetKeyChordName(key | routing_data->Mods, key_chord_name, IM_ARRAYSIZE(key_chord_name));
Text("%s: 0x%08X", key_chord_name, routing_data->RoutingCurr);
DebugLocateItemOnHover(routing_data->RoutingCurr);
idx = routing_data->NextEntryIndex;
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key);
if (owner_data->OwnerCurr == ImGuiKeyOwner_None)
continue;
Text("%s: 0x%08X%s", GetKeyName(key), owner_data->OwnerCurr,
owner_data->LockUntilRelease ? " LockUntilRelease" : owner_data->LockThisFrame ? " LockThisFrame" : "");
DebugLocateItemOnHover(owner_data->OwnerCurr);
}
EndListBox();
}
EndListBox();
Unindent();
}
Text("SHORTCUT ROUTING");
{
Indent();
if (BeginListBox("##routes", ImVec2(-FLT_MIN, GetTextLineHeightWithSpacing() * 6)))
{
for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
{
ImGuiKeyRoutingTable* rt = &g.KeysRoutingTable;
for (ImGuiKeyRoutingIndex idx = rt->Index[key - ImGuiKey_NamedKey_BEGIN]; idx != -1; )
{
char key_chord_name[64];
ImGuiKeyRoutingData* routing_data = &rt->Entries[idx];
GetKeyChordName(key | routing_data->Mods, key_chord_name, IM_ARRAYSIZE(key_chord_name));
Text("%s: 0x%08X", key_chord_name, routing_data->RoutingCurr);
DebugLocateItemOnHover(routing_data->RoutingCurr);
idx = routing_data->NextEntryIndex;
}
}
EndListBox();
}
Text("(ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: 0x%X)", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask);
Unindent();
}
Text("(ActiveIdUsing: AllKeyboardKeys: %d, NavDirMask: 0x%X)", g.ActiveIdUsingAllKeyboardKeys, g.ActiveIdUsingNavDirMask);
TreePop();
}

21
imgui.h
View File

@ -1,4 +1,4 @@
// dear imgui, v1.89.1
// dear imgui, v1.89.2 WIP
// (headers)
// Help:
@ -22,8 +22,8 @@
// Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345')
#define IMGUI_VERSION "1.89.1"
#define IMGUI_VERSION_NUM 18910
#define IMGUI_VERSION "1.89.2 WIP"
#define IMGUI_VERSION_NUM 18914
#define IMGUI_HAS_TABLE
#define IMGUI_HAS_VIEWPORT // Viewport WIP branch
#define IMGUI_HAS_DOCK // Docking WIP branch
@ -1491,7 +1491,7 @@ enum ImGuiKey : int
ImGuiKey_GamepadRStickUp, // [Analog]
ImGuiKey_GamepadRStickDown, // [Analog]
// Mouse Buttons (auto-submitted from AddMouseButtonEvent() calls)
// Aliases: Mouse Buttons (auto-submitted from AddMouseButtonEvent() calls)
// - This is mirroring the data also written to io.MouseDown[], io.MouseWheel, in a format allowing them to be accessed via standard key API.
ImGuiKey_MouseLeft, ImGuiKey_MouseRight, ImGuiKey_MouseMiddle, ImGuiKey_MouseX1, ImGuiKey_MouseX2, ImGuiKey_MouseWheelX, ImGuiKey_MouseWheelY,
@ -1512,12 +1512,8 @@ enum ImGuiKey : int
ImGuiMod_Shift = 1 << 13,
ImGuiMod_Alt = 1 << 14, // Option/Menu
ImGuiMod_Super = 1 << 15, // Cmd/Super/Windows
ImGuiMod_Mask_ = 0xF000,
#if defined(__APPLE__)
ImGuiMod_Shortcut = ImGuiMod_Super,
#else
ImGuiMod_Shortcut = ImGuiMod_Ctrl,
#endif
ImGuiMod_Shortcut = 1 << 11, // [Internal, read-only] Alias of ImGuiMod_Super (macOS) or ImGuiMod_Ctrl (otherwise), decided by io.ConfigMacOSXBehaviors.
ImGuiMod_Mask_ = 0xF800, // 5-bits
// [Internal] Prior to 1.87 we required user to fill io.KeysDown[512] using their own native index + the io.KeyMap[] array.
// We are ditching this method but keeping a legacy path for user code doing e.g. IsKeyPressed(MY_NATIVE_KEY_CODE)
@ -1991,7 +1987,7 @@ struct ImGuiIO
float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds.
float HoverDelayNormal; // = 0.30 sec // Delay on hovering before IsItemHovered(ImGuiHoveredFlags_DelayNormal) returns true.
float HoverDelayShort; // = 0.10 sec // Delay on hovering before IsItemHovered(ImGuiHoveredFlags_DelayShort) returns true.
void* UserData; // = NULL // Store your own data for retrieval by callbacks.
void* UserData; // = NULL // Store your own data.
ImFontAtlas*Fonts; // <auto> // Font atlas: load, rasterize and pack one or more fonts into a single texture.
float FontGlobalScale; // = 1.0f // Global scale all fonts
@ -2118,7 +2114,7 @@ struct ImGuiIO
bool KeySuper; // Keyboard modifier down: Cmd/Super/Windows
// Other state maintained from data above + IO function calls
ImGuiKeyChord KeyMods; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags). Read-only, updated by NewFrame()
ImGuiKeyChord KeyMods; // Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags. DOES NOT CONTAINS ImGuiMod_Shortcut which is pretranslated). Read-only, updated by NewFrame()
ImGuiKeyData KeysData[ImGuiKey_KeysData_SIZE]; // Key state for all known keys. Use IsKeyXXX() functions to access this.
bool WantCaptureMouseUnlessPopupClose; // Alternative to WantCaptureMouse: (WantCaptureMouse == true && WantCaptureMouseUnlessPopupClose == false) when a click over void is expected to close a popup.
ImVec2 MousePosPrev; // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid)
@ -2925,6 +2921,7 @@ struct ImFontAtlas
int TexDesiredWidth; // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height.
int TexGlyphPadding; // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false).
bool Locked; // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert.
void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas).
// [Internal]
// NB: Access texture data via GetTexData*() calls! Which will setup a default font for you.

View File

@ -1,4 +1,4 @@
// dear imgui, v1.89.1
// dear imgui, v1.89.2 WIP
// (demo code)
// Help:
@ -5759,15 +5759,47 @@ namespace ImGui { extern ImGuiKeyData* GetKeyData(ImGuiKey key); }
static void ShowDemoWindowInputs()
{
IMGUI_DEMO_MARKER("Inputs, Navigation & Focus");
if (ImGui::CollapsingHeader("Inputs, Navigation & Focus"))
IMGUI_DEMO_MARKER("Inputs & Focus");
if (ImGui::CollapsingHeader("Inputs & Focus"))
{
ImGuiIO& io = ImGui::GetIO();
// Display ImGuiIO output flags
IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Output");
// Display inputs submitted to ImGuiIO
IMGUI_DEMO_MARKER("Inputs & Focus/Inputs");
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
if (ImGui::TreeNode("Output"))
if (ImGui::TreeNode("Inputs"))
{
HelpMarker(
"This is a simplified view. See more detailed input state:\n"
"- in 'Tools->Metrics/Debugger->Inputs'.\n"
"- in 'Tools->Debug Log->IO'.");
if (ImGui::IsMousePosValid())
ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
else
ImGui::Text("Mouse pos: <INVALID>");
ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
ImGui::Text("Mouse down:");
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
// We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allows displaying the data for old/new backends.
// User code should never have to go through such hoops: old code may use native keycodes, new code may use ImGuiKey codes.
#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } };
#else
struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key < 512 && ImGui::GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array
#endif
ImGui::Text("Keys down:"); for (ImGuiKey key = ImGuiKey_KeysData_OFFSET; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !ImGui::IsKeyDown(key)) continue; ImGui::SameLine(); ImGui::Text((key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); ImGui::SameLine(); ImGui::Text("(%.02f)", ImGui::GetKeyData(key)->DownDuration); }
ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public.
ImGui::TreePop();
}
// Display ImGuiIO output flags
IMGUI_DEMO_MARKER("Inputs & Focus/Outputs");
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
if (ImGui::TreeNode("Outputs"))
{
ImGui::Text("io.WantCaptureMouse: %d", io.WantCaptureMouse);
ImGui::Text("io.WantCaptureMouseUnlessPopupClose: %d", io.WantCaptureMouseUnlessPopupClose);
@ -5778,127 +5810,8 @@ static void ShowDemoWindowInputs()
ImGui::TreePop();
}
// Display Mouse state
IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Mouse State");
if (ImGui::TreeNode("Mouse State"))
{
if (ImGui::IsMousePosValid())
ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
else
ImGui::Text("Mouse pos: <INVALID>");
ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
int count = IM_ARRAYSIZE(io.MouseDown);
ImGui::Text("Mouse down:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseDown(i)) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
ImGui::Text("Mouse clicked:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d (%d)", i, ImGui::GetMouseClickedCount(i)); }
ImGui::Text("Mouse released:"); for (int i = 0; i < count; i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); }
ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
ImGui::Text("Pen Pressure: %.1f", io.PenPressure); // Note: currently unused
ImGui::TreePop();
}
// Display mouse cursors
IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Mouse Cursors");
if (ImGui::TreeNode("Mouse Cursors"))
{
const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" };
IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
ImGuiMouseCursor current = ImGui::GetMouseCursor();
ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]);
ImGui::BeginDisabled(true);
ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
ImGui::EndDisabled();
ImGui::Text("Hover to see mouse cursors:");
ImGui::SameLine(); HelpMarker(
"Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. "
"If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, "
"otherwise your backend needs to handle it.");
for (int i = 0; i < ImGuiMouseCursor_COUNT; i++)
{
char label[32];
sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
ImGui::Bullet(); ImGui::Selectable(label, false);
if (ImGui::IsItemHovered())
ImGui::SetMouseCursor(i);
}
ImGui::TreePop();
}
// Display Keyboard/Mouse state
IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Keyboard, Gamepad & Navigation State");
if (ImGui::TreeNode("Keyboard, Gamepad & Navigation State"))
{
// We iterate both legacy native range and named ImGuiKey ranges, which is a little odd but this allows displaying the data for old/new backends.
// User code should never have to go through such hoops: old code may use native keycodes, new code may use ImGuiKey codes.
#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
struct funcs { static bool IsLegacyNativeDupe(ImGuiKey) { return false; } };
const ImGuiKey key_first = (ImGuiKey)ImGuiKey_NamedKey_BEGIN;
#else
struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key < 512 && ImGui::GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array
const ImGuiKey key_first = (ImGuiKey)0;
//ImGui::Text("Legacy raw:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key++) { if (io.KeysDown[key]) { ImGui::SameLine(); ImGui::Text("\"%s\" %d", ImGui::GetKeyName(key), key); } }
#endif
ImGui::Text("Keys down:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key)) continue; if (ImGui::IsKeyDown(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d (%.02f)", ImGui::GetKeyName(key), key, ImGui::GetKeyData(key)->DownDuration); } }
ImGui::Text("Keys pressed:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key)) continue; if (ImGui::IsKeyPressed(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d", ImGui::GetKeyName(key), key); } }
ImGui::Text("Keys released:"); for (ImGuiKey key = key_first; key < ImGuiKey_COUNT; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key)) continue; if (ImGui::IsKeyReleased(key)) { ImGui::SameLine(); ImGui::Text("\"%s\" %d", ImGui::GetKeyName(key), key); } }
ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public.
// Draw an arbitrary US keyboard layout to visualize translated keys
{
const ImVec2 key_size = ImVec2(35.0f, 35.0f);
const float key_rounding = 3.0f;
const ImVec2 key_face_size = ImVec2(25.0f, 25.0f);
const ImVec2 key_face_pos = ImVec2(5.0f, 3.0f);
const float key_face_rounding = 2.0f;
const ImVec2 key_label_pos = ImVec2(7.0f, 4.0f);
const ImVec2 key_step = ImVec2(key_size.x - 1.0f, key_size.y - 1.0f);
const float key_row_offset = 9.0f;
ImVec2 board_min = ImGui::GetCursorScreenPos();
ImVec2 board_max = ImVec2(board_min.x + 3 * key_step.x + 2 * key_row_offset + 10.0f, board_min.y + 3 * key_step.y + 10.0f);
ImVec2 start_pos = ImVec2(board_min.x + 5.0f - key_step.x, board_min.y);
struct KeyLayoutData { int Row, Col; const char* Label; ImGuiKey Key; };
const KeyLayoutData keys_to_display[] =
{
{ 0, 0, "", ImGuiKey_Tab }, { 0, 1, "Q", ImGuiKey_Q }, { 0, 2, "W", ImGuiKey_W }, { 0, 3, "E", ImGuiKey_E }, { 0, 4, "R", ImGuiKey_R },
{ 1, 0, "", ImGuiKey_CapsLock }, { 1, 1, "A", ImGuiKey_A }, { 1, 2, "S", ImGuiKey_S }, { 1, 3, "D", ImGuiKey_D }, { 1, 4, "F", ImGuiKey_F },
{ 2, 0, "", ImGuiKey_LeftShift },{ 2, 1, "Z", ImGuiKey_Z }, { 2, 2, "X", ImGuiKey_X }, { 2, 3, "C", ImGuiKey_C }, { 2, 4, "V", ImGuiKey_V }
};
// Elements rendered manually via ImDrawList API are not clipped automatically.
// While not strictly necessary, here IsItemVisible() is used to avoid rendering these shapes when they are out of view.
ImGui::Dummy(ImVec2(board_max.x - board_min.x, board_max.y - board_min.y));
if (ImGui::IsItemVisible())
{
ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->PushClipRect(board_min, board_max, true);
for (int n = 0; n < IM_ARRAYSIZE(keys_to_display); n++)
{
const KeyLayoutData* key_data = &keys_to_display[n];
ImVec2 key_min = ImVec2(start_pos.x + key_data->Col * key_step.x + key_data->Row * key_row_offset, start_pos.y + key_data->Row * key_step.y);
ImVec2 key_max = ImVec2(key_min.x + key_size.x, key_min.y + key_size.y);
draw_list->AddRectFilled(key_min, key_max, IM_COL32(204, 204, 204, 255), key_rounding);
draw_list->AddRect(key_min, key_max, IM_COL32(24, 24, 24, 255), key_rounding);
ImVec2 face_min = ImVec2(key_min.x + key_face_pos.x, key_min.y + key_face_pos.y);
ImVec2 face_max = ImVec2(face_min.x + key_face_size.x, face_min.y + key_face_size.y);
draw_list->AddRect(face_min, face_max, IM_COL32(193, 193, 193, 255), key_face_rounding, ImDrawFlags_None, 2.0f);
draw_list->AddRectFilled(face_min, face_max, IM_COL32(252, 252, 252, 255), key_face_rounding);
ImVec2 label_min = ImVec2(key_min.x + key_label_pos.x, key_min.y + key_label_pos.y);
draw_list->AddText(label_min, IM_COL32(64, 64, 64, 255), key_data->Label);
if (ImGui::IsKeyDown(key_data->Key))
draw_list->AddRectFilled(key_min, key_max, IM_COL32(255, 0, 0, 128), key_rounding);
}
draw_list->PopClipRect();
}
}
ImGui::TreePop();
}
if (ImGui::TreeNode("Capture override"))
IMGUI_DEMO_MARKER("Inputs & Focus/IO Output: Capture override");
if (ImGui::TreeNode("IO Output: Capture override"))
{
HelpMarker(
"The value of io.WantCaptureMouse and io.WantCaptureKeyboard are normally set by Dear ImGui "
@ -5932,7 +5845,36 @@ static void ShowDemoWindowInputs()
ImGui::TreePop();
}
IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Tabbing");
// Display mouse cursors
IMGUI_DEMO_MARKER("Inputs & Focus/Mouse Cursors");
if (ImGui::TreeNode("Mouse Cursors"))
{
const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" };
IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
ImGuiMouseCursor current = ImGui::GetMouseCursor();
ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]);
ImGui::BeginDisabled(true);
ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
ImGui::EndDisabled();
ImGui::Text("Hover to see mouse cursors:");
ImGui::SameLine(); HelpMarker(
"Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. "
"If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, "
"otherwise your backend needs to handle it.");
for (int i = 0; i < ImGuiMouseCursor_COUNT; i++)
{
char label[32];
sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
ImGui::Bullet(); ImGui::Selectable(label, false);
if (ImGui::IsItemHovered())
ImGui::SetMouseCursor(i);
}
ImGui::TreePop();
}
IMGUI_DEMO_MARKER("Inputs & Focus/Tabbing");
if (ImGui::TreeNode("Tabbing"))
{
ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields.");
@ -5948,7 +5890,7 @@ static void ShowDemoWindowInputs()
ImGui::TreePop();
}
IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Focus from code");
IMGUI_DEMO_MARKER("Inputs & Focus/Focus from code");
if (ImGui::TreeNode("Focus from code"))
{
bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine();
@ -5990,7 +5932,7 @@ static void ShowDemoWindowInputs()
ImGui::TreePop();
}
IMGUI_DEMO_MARKER("Inputs, Navigation & Focus/Dragging");
IMGUI_DEMO_MARKER("Inputs & Focus/Dragging");
if (ImGui::TreeNode("Dragging"))
{
ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.");

View File

@ -1,4 +1,4 @@
// dear imgui, v1.89.1
// dear imgui, v1.89.2 WIP
// (drawing and font code)
/*
@ -455,11 +455,13 @@ void ImDrawList::AddDrawCmd()
// Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL
void ImDrawList::_PopUnusedDrawCmd()
{
if (CmdBuffer.Size == 0)
return;
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
if (curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL)
while (CmdBuffer.Size > 0)
{
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
if (curr_cmd->ElemCount != 0 || curr_cmd->UserCallback != NULL)
return;// break;
CmdBuffer.pop_back();
}
}
void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
@ -3573,17 +3575,18 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
while (y + line_height < clip_rect.y && s < text_end)
{
const char* line_end = (const char*)memchr(s, '\n', text_end - s);
const char* line_next = line_end ? line_end + 1 : text_end;
if (word_wrap_enabled)
{
// FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPositionA().
// If the specs for CalcWordWrapPositionA() were reworked to optionally return on \n we could combine both.
// However it is still better than nothing performing the fast-forward!
s = CalcWordWrapPositionA(scale, s, line_end, wrap_width);
s = CalcWordWrapPositionA(scale, s, line_next, wrap_width);
s = CalcWordWrapNextLineStartA(s, text_end);
}
else
{
s = line_end ? line_end + 1 : text_end;
s = line_next;
}
y += line_height;
}

View File

@ -1,4 +1,4 @@
// dear imgui, v1.89.1
// dear imgui, v1.89.2 WIP
// (internal structures/api)
// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
@ -56,7 +56,7 @@ Index of this file:
#include <limits.h> // INT_MIN, INT_MAX
// Enable SSE intrinsics if available
#if (defined __SSE__ || defined __x86_64__ || defined _M_X64) && !defined(IMGUI_DISABLE_SSE)
#if (defined __SSE__ || defined __x86_64__ || defined _M_X64 || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1))) && !defined(IMGUI_DISABLE_SSE)
#define IMGUI_ENABLE_SSE
#include <immintrin.h>
#endif
@ -219,7 +219,11 @@ namespace ImStb
#endif
// Debug Logging for ShowDebugLogWindow(). This is designed for relatively rare events so please don't spam.
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
#define IMGUI_DEBUG_LOG(...) ImGui::DebugLog(__VA_ARGS__)
#else
#define IMGUI_DEBUG_LOG(...) ((void)0)
#endif
#define IMGUI_DEBUG_LOG_ACTIVEID(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventActiveId) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
#define IMGUI_DEBUG_LOG_FOCUS(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventFocus) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
#define IMGUI_DEBUG_LOG_POPUP(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
@ -483,6 +487,7 @@ static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a)
static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }
static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
static inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; }
static inline float ImExponentialMovingAverage(float avg, float sample, int n) { avg -= avg / n; avg += sample / n; return avg; }
IM_MSVC_RUNTIME_CHECKS_RESTORE
// Helpers: Geometry
@ -1056,6 +1061,7 @@ struct IMGUI_API ImGuiMenuColumns
// For a given item ID, access with ImGui::GetInputTextState()
struct IMGUI_API ImGuiInputTextState
{
ImGuiContext* Ctx; // parent dear imgui context
ImGuiID ID; // widget id owning the text state
int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not.
ImVector<ImWchar> TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer.
@ -1071,7 +1077,7 @@ struct IMGUI_API ImGuiInputTextState
bool Edited; // edited this frame
ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set.
ImGuiInputTextState() { memset(this, 0, sizeof(*this)); }
ImGuiInputTextState(ImGuiContext* ctx) { memset(this, 0, sizeof(*this)); Ctx = ctx;}
void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); }
void ClearFreeMemory() { TextW.clear(); TextA.clear(); InitialTextA.clear(); }
int GetUndoAvailCount() const { return Stb.undostate.undo_point; }
@ -1312,7 +1318,7 @@ typedef ImS16 ImGuiKeyRoutingIndex;
struct ImGuiKeyRoutingData
{
ImGuiKeyRoutingIndex NextEntryIndex;
ImU16 Mods; // Technically we'd only need 4 bits but for simplify we store ImGuiMod_ values which need 16 bits.
ImU16 Mods; // Technically we'd only need 4-bits but for simplify we store ImGuiMod_ values which need 16-bits. ImGuiMod_Shortcut is already translated to Ctrl/Super.
ImU8 RoutingNextScore; // Lower is better (0: perfect score)
ImGuiID RoutingCurr;
ImGuiID RoutingNext;
@ -1943,7 +1949,10 @@ struct ImGuiContext
ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindowDockTree.
ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window.
ImVec2 WheelingWindowRefMousePos;
int WheelingWindowStartFrame; // This may be set one frame before WheelingWindow is != NULL
float WheelingWindowReleaseTimer;
ImVec2 WheelingWindowWheelRemainder;
ImVec2 WheelingAxisAvg;
// Item/widgets state and tracking information
ImGuiID DebugHookIdInfo; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line]
@ -2202,6 +2211,7 @@ struct ImGuiContext
ImVector<char> TempBuffer; // Temporary text buffer
ImGuiContext(ImFontAtlas* shared_font_atlas)
: InputTextState(this)
{
Initialized = false;
ConfigFlagsCurrFrame = ConfigFlagsLastFrame = ImGuiConfigFlags_None;
@ -2223,6 +2233,7 @@ struct ImGuiContext
HoveredWindowUnderMovingWindow = NULL;
MovingWindow = NULL;
WheelingWindow = NULL;
WheelingWindowStartFrame = -1;
WheelingWindowReleaseTimer = 0.0f;
DebugHookIdInfo = 0;
@ -3098,18 +3109,21 @@ namespace ImGui
// Inputs
// FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions.
inline bool IsNamedKey(ImGuiKey key) { return key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END; }
inline bool IsNamedKeyOrModKey(ImGuiKey key) { return (key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END) || key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super; }
inline bool IsNamedKeyOrModKey(ImGuiKey key) { return (key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END) || key == ImGuiMod_Ctrl || key == ImGuiMod_Shift || key == ImGuiMod_Alt || key == ImGuiMod_Super || key == ImGuiMod_Shortcut; }
inline bool IsLegacyKey(ImGuiKey key) { return key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_LegacyNativeKey_END; }
inline bool IsKeyboardKey(ImGuiKey key) { return key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END; }
inline bool IsGamepadKey(ImGuiKey key) { return key >= ImGuiKey_Gamepad_BEGIN && key < ImGuiKey_Gamepad_END; }
inline bool IsMouseKey(ImGuiKey key) { return key >= ImGuiKey_Mouse_BEGIN && key < ImGuiKey_Mouse_END; }
inline bool IsAliasKey(ImGuiKey key) { return key >= ImGuiKey_Aliases_BEGIN && key < ImGuiKey_Aliases_END; }
inline ImGuiKeyChord ConvertShortcutMod(ImGuiKeyChord key_chord) { ImGuiContext& g = *GImGui; IM_ASSERT_PARANOID(key_chord & ImGuiMod_Shortcut); return (key_chord & ~ImGuiMod_Shortcut) | (g.IO.ConfigMacOSXBehaviors ? ImGuiMod_Super : ImGuiMod_Ctrl); }
inline ImGuiKey ConvertSingleModFlagToKey(ImGuiKey key)
{
ImGuiContext& g = *GImGui;
if (key == ImGuiMod_Ctrl) return ImGuiKey_ReservedForModCtrl;
if (key == ImGuiMod_Shift) return ImGuiKey_ReservedForModShift;
if (key == ImGuiMod_Alt) return ImGuiKey_ReservedForModAlt;
if (key == ImGuiMod_Super) return ImGuiKey_ReservedForModSuper;
if (key == ImGuiMod_Shortcut) return (g.IO.ConfigMacOSXBehaviors ? ImGuiKey_ReservedForModSuper : ImGuiKey_ReservedForModCtrl);
return key;
}
@ -3446,6 +3460,7 @@ namespace ImGui
IMGUI_API void DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* label);
IMGUI_API void DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int windows_size, ImGuiWindow* parent_in_begin_stack);
IMGUI_API void DebugNodeViewport(ImGuiViewportP* viewport);
IMGUI_API void DebugRenderKeyboardPreview(ImDrawList* draw_list);
IMGUI_API void DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb);
// Obsolete functions

View File

@ -1,4 +1,4 @@
// dear imgui, v1.89.1
// dear imgui, v1.89.2 WIP
// (tables and columns code)
/*

View File

@ -1,4 +1,4 @@
// dear imgui, v1.89.1
// dear imgui, v1.89.2 WIP
// (widgets code)
/*
@ -126,7 +126,7 @@ static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1);
// For InputTextEx()
static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source);
static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end);
static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false);
static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false);
//-------------------------------------------------------------------------
// [SECTION] Widgets: Text, etc.
@ -3571,9 +3571,9 @@ static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char**
return line_count;
}
static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line)
static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line)
{
ImGuiContext& g = *GImGui;
ImGuiContext& g = *ctx;
ImFont* font = g.Font;
const float line_height = g.FontSize;
const float scale = line_height / font->FontSize;
@ -3622,14 +3622,14 @@ namespace ImStb
static int STB_TEXTEDIT_STRINGLEN(const ImGuiInputTextState* obj) { return obj->CurLenW; }
static ImWchar STB_TEXTEDIT_GETCHAR(const ImGuiInputTextState* obj, int idx) { return obj->TextW[idx]; }
static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *GImGui; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); }
static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj, int line_start_idx, int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext& g = *obj->Ctx; return g.Font->GetCharAdvance(c) * (g.FontSize / g.Font->FontSize); }
static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x200000 ? 0 : key; }
static ImWchar STB_TEXTEDIT_NEWLINE = '\n';
static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj, int line_start_idx)
{
const ImWchar* text = obj->TextW.Data;
const ImWchar* text_remaining = NULL;
const ImVec2 size = InputTextCalcTextSizeW(text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true);
const ImVec2 size = InputTextCalcTextSizeW(obj->Ctx, text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true);
r->x0 = 0.0f;
r->x1 = size.x;
r->baseline_y_delta = size.y;
@ -3645,7 +3645,7 @@ static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx)
static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; }
static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; }
static int STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; }
static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) { if (ImGui::GetIO().ConfigMacOSXBehaviors) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); }
static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) { ImGuiContext& g = *obj->Ctx; if (g.IO.ConfigMacOSXBehaviors) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); }
#define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h
#define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL
@ -4683,11 +4683,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
searches_result_line_no[1] = line_count;
// Calculate 2d position by finding the beginning of the line and measuring distance
cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;
cursor_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;
cursor_offset.y = searches_result_line_no[0] * g.FontSize;
if (searches_result_line_no[1] >= 0)
{
select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;
select_start_offset.x = InputTextCalcTextSizeW(&g, ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;
select_start_offset.y = searches_result_line_no[1] * g.FontSize;
}
@ -4756,7 +4756,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
}
else
{
ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true);
ImVec2 rect_size = InputTextCalcTextSizeW(&g, p, text_selected_end, &p, NULL, true);
if (rect_size.x <= 0.0f) rect_size.x = IM_FLOOR(g.Font->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines
ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn));
rect.ClipWith(clip_rect);