"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "imgui.cpp" between
imgui-1.86.tar.gz and imgui-1.87.tar.gz

About: Dear ImGui is a bloat-free Graphical User Interface for C++ with minimal dependencies.

imgui.cpp  (imgui-1.86):imgui.cpp  (imgui-1.87)
// dear imgui, v1.86 // dear imgui, v1.87
// (main code and documentation) // (main code and documentation)
// Help: // Help:
// - Read FAQ at http://dearimgui.org/faq // - Read FAQ at http://dearimgui.org/faq
// - Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImG ui in your codebase. // - Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImG ui in your codebase.
// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications i n examples/ are doing that. // - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications i n examples/ are doing that.
// Read imgui.cpp for details, links and comments. // Read imgui.cpp for details, links and comments.
// Resources: // Resources:
// - FAQ http://dearimgui.org/faq // - FAQ http://dearimgui.org/faq
skipping to change at line 73 skipping to change at line 73
// [SECTION] MISC HELPERS/UTILITIES (File functions) // [SECTION] MISC HELPERS/UTILITIES (File functions)
// [SECTION] MISC HELPERS/UTILITIES (ImText* functions) // [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
// [SECTION] MISC HELPERS/UTILITIES (Color functions) // [SECTION] MISC HELPERS/UTILITIES (Color functions)
// [SECTION] ImGuiStorage // [SECTION] ImGuiStorage
// [SECTION] ImGuiTextFilter // [SECTION] ImGuiTextFilter
// [SECTION] ImGuiTextBuffer // [SECTION] ImGuiTextBuffer
// [SECTION] ImGuiListClipper // [SECTION] ImGuiListClipper
// [SECTION] STYLING // [SECTION] STYLING
// [SECTION] RENDER HELPERS // [SECTION] RENDER HELPERS
// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!) // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
// [SECTION] INPUTS
// [SECTION] ERROR CHECKING // [SECTION] ERROR CHECKING
// [SECTION] LAYOUT // [SECTION] LAYOUT
// [SECTION] SCROLLING // [SECTION] SCROLLING
// [SECTION] TOOLTIPS // [SECTION] TOOLTIPS
// [SECTION] POPUPS // [SECTION] POPUPS
// [SECTION] KEYBOARD/GAMEPAD NAVIGATION // [SECTION] KEYBOARD/GAMEPAD NAVIGATION
// [SECTION] DRAG AND DROP // [SECTION] DRAG AND DROP
// [SECTION] LOGGING/CAPTURING // [SECTION] LOGGING/CAPTURING
// [SECTION] SETTINGS // [SECTION] SETTINGS
// [SECTION] VIEWPORTS // [SECTION] VIEWPORTS
skipping to change at line 129 skipping to change at line 130
- CTRL+Click on a slider or drag box to input value as text. - CTRL+Click on a slider or drag box to input value as text.
- Use mouse wheel to scroll. - Use mouse wheel to scroll.
- Text editor: - Text editor:
- Hold SHIFT or use mouse to select text. - Hold SHIFT or use mouse to select text.
- CTRL+Left/Right to word jump. - CTRL+Left/Right to word jump.
- CTRL+Shift+Left/Right to select words. - CTRL+Shift+Left/Right to select words.
- CTRL+A our Double-Click to select all. - CTRL+A our Double-Click to select all.
- CTRL+X,CTRL+C,CTRL+V to use OS clipboard/ - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/
- CTRL+Z,CTRL+Y to undo/redo. - CTRL+Z,CTRL+Y to undo/redo.
- ESCAPE to revert text to its original value. - ESCAPE to revert text to its original value.
- You can apply arithmetic operators +,*,/ on numerical values. Use +- to sub tract (because - would set a negative value!)
- Controls are automatically adjusted for OSX to match standard OSX text edit ing operations. - Controls are automatically adjusted for OSX to match standard OSX text edit ing operations.
- General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard. - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard.
- General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://dearim gui.org/controls_sheets - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://dearim gui.org/controls_sheets
PROGRAMMER GUIDE PROGRAMMER GUIDE
================ ================
READ FIRST READ FIRST
---------- ----------
- Remember to check the wonderful Wiki (https://github.com/ocornut/imgui/wiki) - Remember to check the wonderful Wiki (https://github.com/ocornut/imgui/wiki)
skipping to change at line 252 skipping to change at line 252
io.Fonts->SetTexID((void*)texture); io.Fonts->SetTexID((void*)texture);
// Application main loop // Application main loop
while (true) while (true)
{ {
// Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc. // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc.
// (In the examples/ app this is usually done within the ImGui_ImplXXX_N ewFrame() function from one of the demo Platform Backends) // (In the examples/ app this is usually done within the ImGui_ImplXXX_N ewFrame() function from one of the demo Platform Backends)
io.DeltaTime = 1.0f/60.0f; // set the time elapsed since th e previous frame (in seconds) io.DeltaTime = 1.0f/60.0f; // set the time elapsed since th e previous frame (in seconds)
io.DisplaySize.x = 1920.0f; // set the current display width io.DisplaySize.x = 1920.0f; // set the current display width
io.DisplaySize.y = 1280.0f; // set the current display heigh t here io.DisplaySize.y = 1280.0f; // set the current display heigh t here
io.MousePos = my_mouse_pos; // set the mouse position io.AddMousePosEvent(mouse_x, mouse_y); // update mouse position
io.MouseDown[0] = my_mouse_buttons[0]; // set the mouse button states io.AddMouseButtonEvent(0, mouse_b[0]); // update mouse button states
io.MouseDown[1] = my_mouse_buttons[1]; io.AddMouseButtonEvent(1, mouse_b[1]); // update mouse button states
// Call NewFrame(), after this point you can use ImGui::* functions anyt ime // Call NewFrame(), after this point you can use ImGui::* functions anyt ime
// (So you want to try calling NewFrame() as early as you can in your ma in loop to be able to use Dear ImGui everywhere) // (So you want to try calling NewFrame() as early as you can in your ma in loop to be able to use Dear ImGui everywhere)
ImGui::NewFrame(); ImGui::NewFrame();
// Most of your application code here // Most of your application code here
ImGui::Text("Hello, world!"); ImGui::Text("Hello, world!");
MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin(" My window"); ImGui::Text("Hello, world!"); ImGui::End(); MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin(" My window"); ImGui::Text("Hello, world!"); ImGui::End();
MyGameRender(); // may use any Dear ImGui functions as well! MyGameRender(); // may use any Dear ImGui functions as well!
skipping to change at line 291 skipping to change at line 291
HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
--------------------------------------------- ---------------------------------------------
The backends in impl_impl_XXX.cpp files contain many working implementations of a rendering function. The backends in impl_impl_XXX.cpp files contain many working implementations of a rendering function.
void void MyImGuiRenderFunction(ImDrawData* draw_data) void void MyImGuiRenderFunction(ImDrawData* draw_data)
{ {
// TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
// TODO: Setup viewport covering draw_data->DisplayPos to draw_data->Disp layPos + draw_data->DisplaySize // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->Disp layPos + draw_data->DisplaySize
// TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
// TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragm ent shader sample color from 1 texture, multiply by vertex color. // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragm ent shader sample color from 1 texture, multiply by vertex color.
ImVec2 clip_off = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++) for (int n = 0; n < draw_data->CmdListsCount; n++)
{ {
const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawList* cmd_list = draw_data->CmdLists[n];
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex bu ffer generated by Dear ImGui const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex bu ffer generated by Dear ImGui
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buf fer generated by Dear ImGui const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buf fer generated by Dear ImGui
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{ {
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback) if (pcmd->UserCallback)
{ {
pcmd->UserCallback(cmd_list, pcmd); pcmd->UserCallback(cmd_list, pcmd);
} }
else else
{ {
// The texture for the draw call is specified by pcmd->GetTexID // Project scissor/clipping rectangles into framebuffer space
(). ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y
// The vast majority of draw calls will use the Dear ImGui text - clip_off.y);
ure atlas, which value you have set yourself during initialization. ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w
MyEngineBindTexture((MyTexture*)pcmd->GetTexID()); - clip_off.y);
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// We are using scissoring to clip some objects. All low-level graphics API should support it. // We are using scissoring to clip some objects. All low-level graphics API should support it.
// - If your engine doesn't support scissoring yet, you may ign ore this at first. You will get some small glitches // - If your engine doesn't support scissoring yet, you may ign ore this at first. You will get some small glitches
// (some elements visible outside their bounds) but you can f ix that once everything else works! // (some elements visible outside their bounds) but you can f ix that once everything else works!
// - Clipping coordinates are provided in imgui coordinates spa ce: // - Clipping coordinates are provided in imgui coordinates spa ce:
// - For a given viewport, draw_data->DisplayPos == viewport- >Pos and draw_data->DisplaySize == viewport->Size // - For a given viewport, draw_data->DisplayPos == viewport- >Pos and draw_data->DisplaySize == viewport->Size
// - In a single viewport application, draw_data->DisplayPos == (0,0) and draw_data->DisplaySize == io.DisplaySize, but always use GetMainVie wport()->Pos/Size instead of hardcoding those values. // - In a single viewport application, draw_data->DisplayPos == (0,0) and draw_data->DisplaySize == io.DisplaySize, but always use GetMainVie wport()->Pos/Size instead of hardcoding those values.
// - In the interest of supporting multi-viewport application s (see 'docking' branch on github), // - In the interest of supporting multi-viewport application s (see 'docking' branch on github),
// always subtract draw_data->DisplayPos from clipping boun ds to convert them to your viewport space. // always subtract draw_data->DisplayPos from clipping boun ds to convert them to your viewport space.
// - Note that pcmd->ClipRect contains Min+Max bounds. Some gra phics API may use Min+Max, other may use Min+Size (size being Max-Min) // - Note that pcmd->ClipRect contains Min+Max bounds. Some gra phics API may use Min+Max, other may use Min+Size (size being Max-Min)
ImVec2 pos = draw_data->DisplayPos; MyEngineSetScissor(clip_min.x, clip_min.y, clip_max.x, clip_max
MyEngineScissor((int)(pcmd->ClipRect.x - pos.x), (int)(pcmd->Cl .y);
ipRect.y - pos.y), (int)(pcmd->ClipRect.z - pos.x), (int)(pcmd->ClipRect.w - pos
.y)); // The texture for the draw call is specified by pcmd->GetTexID
().
// The vast majority of draw calls will use the Dear ImGui text
ure atlas, which value you have set yourself during initialization.
MyEngineBindTexture((MyTexture*)pcmd->GetTexID());
// Render 'pcmd->ElemCount/3' indexed triangles. // Render 'pcmd->ElemCount/3' indexed triangles.
// By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices. // By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices.
MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer); MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset, vtx_b uffer, pcmd->VtxOffset);
} }
idx_buffer += pcmd->ElemCount;
} }
} }
} }
USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS
------------------------------------------ ------------------------------------------
- The gamepad/keyboard navigation is fairly functional and keeps being improved . - The gamepad/keyboard navigation is fairly functional and keeps being improved .
- Gamepad support is particularly useful to use Dear ImGui on a console system (e.g. PS4, Switch, XB1) without a mouse! - Gamepad support is particularly useful to use Dear ImGui on a console system (e.g. PS4, Switch, XB1) without a mouse!
- You can ask questions and report issues at https://github.com/ocornut/imgui/i ssues/787 - You can ask questions and report issues at https://github.com/ocornut/imgui/i ssues/787
- The initial focus was to support game controllers, but keyboard is becoming i ncreasingly and decently usable. - The initial focus was to support game controllers, but keyboard is becoming i ncreasingly and decently usable.
- Keyboard: - Keyboard:
- Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. - Application: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to e
NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDow nable.
n[] + io.KeyMap[] arrays. - Internally: NewFrame() will automatically fill io.NavInputs[] based on bac
- When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEna kend's io.AddKeyEvent() calls.
bleKeyboard), the io.WantCaptureKeyboard flag - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEna
will be set. For more advanced uses, you may want to read from: bleKeyboard),
the io.WantCaptureKeyboard flag will be set. For more advanced uses, you m
ay want to read from:
- io.NavActive: true when a window is focused and it doesn't have the ImG uiWindowFlags_NoNavInputs flag set. - io.NavActive: true when a window is focused and it doesn't have the ImG uiWindowFlags_NoNavInputs flag set.
- io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used). - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used).
- or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_ AnyWindow), IsItemFocused() etc. functions. - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_ AnyWindow), IsItemFocused() etc. functions.
Please reach out if you think the game vs navigation input sharing could b e improved. Please reach out if you think the game vs navigation input sharing could b e improved.
- Gamepad: - Gamepad:
- Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. - Application: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to en
- Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io able.
.NavInputs[] fields before calling NewFrame(). - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + call io.Add
Note that io.NavInputs[] is cleared by EndFrame(). KeyEvent/AddKeyAnalogEvent() with ImGuiKey_Gamepad_XXX keys.
- See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each For analog values (0.0f to 1.0f), backend is responsible to handling a dea
entry of io.NavInputs[], set the following values: d-zone and rescaling inputs accordingly.
0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values f Backend code will probably need to transform your raw inputs (such as e.g.
or analog triggers/sticks. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.).
- We use a simple >0.0f test for activation testing, and won't attempt to te - Internally: NewFrame() will automatically fill io.NavInputs[] based on bac
st for a dead-zone. kend's io.AddKeyEvent() + io.AddKeyAnalogEvent() calls.
Your code will probably need to transform your raw inputs (such as e.g. re - BEFORE 1.87, BACKENDS USED TO WRITE DIRECTLY TO io.NavInputs[]. This is go
mapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.). ing to be obsoleted in the future. Please call io functions instead!
- You can download PNG/PSD files depicting the gamepad controls for common c ontrollers at: http://dearimgui.org/controls_sheets - You can download PNG/PSD files depicting the gamepad controls for common c ontrollers at: http://dearimgui.org/controls_sheets
- If you need to share inputs between your game and the imgui parts, the eas - If you need to share inputs between your game and the Dear ImGui interface
iest approach is to go all-or-nothing, with a buttons combo , the easiest approach is to go all-or-nothing,
to toggle the target. Please reach out if you think the game vs navigation with a buttons combo to toggle the target. Please reach out if you think t
input sharing could be improved. he game vs navigation input sharing could be improved.
- Mouse: - Mouse:
- PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback. - PS4/PS5 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback.
- Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + uSynergy.c (on your console/tablet/phone app) to share your PC mouse/keybo ard. - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + uSynergy.c (on your console/tablet/phone app) to share your PC mouse/keybo ard.
- On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag. - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag.
Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetM ousePos instructs dear imgui to move your mouse cursor along with navigation mov ements. Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetM ousePos instructs dear imgui to move your mouse cursor along with navigation mov ements.
When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io. WantSetMousePos' to notify you that it wants the mouse cursor to be moved. When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io. WantSetMousePos' to notify you that it wants the mouse cursor to be moved.
When that happens your backend NEEDS to move the OS or underlying mouse cu rsor on the next frame. Some of the backends in examples/ do that. When that happens your backend NEEDS to move the OS or underlying mouse cu rsor on the next frame. Some of the backends in examples/ do that.
(If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMouse Pos' properly, imgui will misbehave as it will see your mouse moving back and fo rth!) (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMouse Pos' properly, imgui will misbehave as it will see your mouse moving back and fo rth!)
(In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want
to set a boolean to ignore your other external mouse positions until the external source is moved again.) to set a boolean to ignore your other external mouse positions until the external source is moved again.)
API BREAKING CHANGES API BREAKING CHANGES
==================== ====================
Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix. Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code. Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code.
When you are not sure about an old symbol or function name, try using the Searc h/Find function of your IDE to look for comments or references in all imgui file s. When you are not sure about an old symbol or function name, try using the Searc h/Find function of your IDE to look for comments or references in all imgui file s.
You can read releases logs https://github.com/ocornut/imgui/releases for more d etails. You can read releases logs https://github.com/ocornut/imgui/releases for more d etails.
- 2022/01/20 (1.87) - inputs: reworded gamepad IO.
- Backend writing to io.NavInputs[] -> backen
d should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX v
alues.
- 2022/01/19 (1.87) - sliders, drags: removed support for legacy arithmetic ope
rators (+,+-,*,/) when inputing text. This doesn't break any api/code but a feat
ure that used to be accessible by end-users (which seemingly no one used).
- 2022/01/17 (1.87) - inputs: reworked mouse IO.
- Backend writing to io.MousePos -> backen
d should call io.AddMousePosEvent()
- Backend writing to io.MouseDown[] -> backen
d should call io.AddMouseButtonEvent()
- Backend writing to io.MouseWheel -> backen
d should call io.AddMouseWheelEvent()
- Backend writing to io.MouseHoveredViewport -> backen
d should call io.AddMouseViewportEvent() [Docking branch w/ multi-viewports only
]
- 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.Key
sDown[] in favor of calling io.AddKeyEvent(). Removed GetKeyIndex(), now unecess
ary. All IsKeyXXX() functions now take ImGuiKey values. All features are still f
unctional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Rele
ase Notes for details.
- IsKeyPressed(MY_NATIVE_KEY_XXX) -> use Is
KeyPressed(ImGuiKey_XXX)
- IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use Is
KeyPressed(ImGuiKey_XXX)
- Backend writing to io.KeyMap[],io.KeysDown[] -> backen
d should call io.AddKeyEvent()
- Backend writing to io.KeyCtrl, io.KeyShift.. -> backen
d should call io.AddKeyEvent() with ImGuiKey_ModXXX values. *IF YOU PULLED CODE
BETWEEN 2021/01/10 and 2021/01/27: We used to have a io.AddKeyModsEvent() functi
on which was now replaced by io.AddKeyEvent() with ImGuiKey_ModXXX values.*
- 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[] ar
ray. Will assert.
- inputs: added ImGuiKey_ModCtrl/ImGuiKey_ModShift/ImGuiKey
_ModAlt/ImGuiKey_ModSuper values to submit keyboard modifiers using io.AddKeyEve
nt(), instead of writing directly to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeyS
uper.
- 2022/01/05 (1.87) - inputs: renamed ImGuiKey_KeyPadEnter to ImGuiKey_KeypadEn
ter to align with new symbols. Kept redirection enum.
- 2022/01/05 (1.87) - removed io.ImeSetInputScreenPosFn() in favor of more flex
ible io.SetPlatformImeDataFn(). Removed 'void* io.ImeWindowHandle' in favor of w
riting to 'void* ImGuiViewport::PlatformHandleRaw'.
- 2022/01/01 (1.87) - commented out redirecting functions/enums names that were
marked obsolete in 1.69, 1.70, 1.71, 1.72 (March-July 2019)
- ImGui::SetNextTreeNodeOpen() -> use ImGui::SetN
extItemOpen()
- ImGui::GetContentRegionAvailWidth() -> use ImGui::GetC
ontentRegionAvail().x
- ImGui::TreeAdvanceToLabelPos() -> use ImGui::SetC
ursorPosX(ImGui::GetCursorPosX() + ImGui::GetTreeNodeToLabelSpacing());
- ImFontAtlas::CustomRect -> use ImFontAtlas
CustomRect
- ImGuiColorEditFlags_RGB/HSV/HEX -> use ImGuiColorE
ditFlags_DisplayRGB/HSV/Hex
- 2021/12/20 (1.86) - backends: removed obsolete Marmalade backend (imgui_impl_ marmalade.cpp) + example. Find last supported version at https://github.com/ocor nut/imgui/wiki/Bindings - 2021/12/20 (1.86) - backends: removed obsolete Marmalade backend (imgui_impl_ marmalade.cpp) + example. Find last supported version at https://github.com/ocor nut/imgui/wiki/Bindings
- 2021/11/04 (1.86) - removed CalcListClipping() function. Prefer using ImGuiLi stClipper which can return non-contiguous ranges. Please open an issue if you th ink you really need this function. - 2021/11/04 (1.86) - removed CalcListClipping() function. Prefer using ImGuiLi stClipper which can return non-contiguous ranges. Please open an issue if you th ink you really need this function.
- 2021/08/23 (1.85) - removed GetWindowContentRegionWidth() function. keep inli ne redirection helper. can use 'GetWindowContentRegionMax().x - GetWindowContent RegionMin().x' instead for generally 'GetContentRegionAvail().x' is more useful. - 2021/08/23 (1.85) - removed GetWindowContentRegionWidth() function. keep inli ne redirection helper. can use 'GetWindowContentRegionMax().x - GetWindowContent RegionMin().x' instead for generally 'GetContentRegionAvail().x' is more useful.
- 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019): - 2021/07/26 (1.84) - commented out redirecting functions/enums names that were marked obsolete in 1.67 and 1.69 (March 2019):
- ImGui::GetOverlayDrawList() -> use ImGui::GetForegroun dDrawList() - ImGui::GetOverlayDrawList() -> use ImGui::GetForegroun dDrawList()
- ImFont::GlyphRangesBuilder -> use ImFontGlyphRangesBu ilder - ImFont::GlyphRangesBuilder -> use ImFontGlyphRangesBu ilder
- 2021/05/19 (1.83) - backends: obsoleted direct access to ImDrawCmd::TextureId in favor of calling ImDrawCmd::GetTexID(). - 2021/05/19 (1.83) - backends: obsoleted direct access to ImDrawCmd::TextureId in favor of calling ImDrawCmd::GetTexID().
- if you are using official backends from the source tre e: you have nothing to do. - if you are using official backends from the source tre e: you have nothing to do.
- if you have copied old backend code or using your own: change access to draw_cmd->TextureId to draw_cmd->GetTexID(). - if you have copied old backend code or using your own: change access to draw_cmd->TextureId to draw_cmd->GetTexID().
- 2021/03/12 (1.82) - upgraded ImDrawList::AddRect(), AddRectFilled(), PathRect () to use ImDrawFlags instead of ImDrawCornersFlags. - 2021/03/12 (1.82) - upgraded ImDrawList::AddRect(), AddRectFilled(), PathRect () to use ImDrawFlags instead of ImDrawCornersFlags.
skipping to change at line 901 skipping to change at line 928
// Settings // Settings
static void WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSetti ngsHandler*); static void WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSetti ngsHandler*);
static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSetti ngsHandler*, const char* name); static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSetti ngsHandler*, const char* name);
static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSetti ngsHandler*, void* entry, const char* line); static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSetti ngsHandler*, void* entry, const char* line);
static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSetti ngsHandler*); static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSetti ngsHandler*);
static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSetti ngsHandler*, ImGuiTextBuffer* buf); static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSetti ngsHandler*, ImGuiTextBuffer* buf);
// Platform Dependents default implementation for IO functions // Platform Dependents default implementation for IO functions
static const char* GetClipboardTextFn_DefaultImpl(void* user_data); static const char* GetClipboardTextFn_DefaultImpl(void* user_data);
static void SetClipboardTextFn_DefaultImpl(void* user_data, const ch ar* text); static void SetClipboardTextFn_DefaultImpl(void* user_data, const ch ar* text);
static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y); static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport , ImGuiPlatformImeData* data);
namespace ImGui namespace ImGui
{ {
// Navigation // Navigation
static void NavUpdate(); static void NavUpdate();
static void NavUpdateWindowing(); static void NavUpdateWindowing();
static void NavUpdateWindowingOverlay(); static void NavUpdateWindowingOverlay();
static void NavUpdateCancelRequest(); static void NavUpdateCancelRequest();
static void NavUpdateCreateMoveRequest(); static void NavUpdateCreateMoveRequest();
static void NavUpdateCreateTabbingRequest(); static void NavUpdateCreateTabbingRequest();
skipping to change at line 935 skipping to change at line 962
static int FindWindowFocusIndex(ImGuiWindow* window); static int FindWindowFocusIndex(ImGuiWindow* window);
// Error Checking and Debug Tools // Error Checking and Debug Tools
static void ErrorCheckNewFrameSanityChecks(); static void ErrorCheckNewFrameSanityChecks();
static void ErrorCheckEndFrameSanityChecks(); static void ErrorCheckEndFrameSanityChecks();
static void UpdateDebugToolItemPicker(); static void UpdateDebugToolItemPicker();
static void UpdateDebugToolStackQueries(); static void UpdateDebugToolStackQueries();
// Misc // Misc
static void UpdateSettings(); static void UpdateSettings();
static void UpdateKeyboardInputs();
static void UpdateMouseInputs(); static void UpdateMouseInputs();
static void UpdateMouseWheel(); static void UpdateMouseWheel();
static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVe c2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_co l[4], const ImRect& visibility_rect); static bool UpdateWindowManualResize(ImGuiWindow* window, const ImVe c2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_co l[4], const ImRect& visibility_rect);
static void RenderWindowOuterBorders(ImGuiWindow* window); static void RenderWindowOuterBorders(ImGuiWindow* window);
static void RenderWindowDecorations(ImGuiWindow* window, const ImRec t& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU 32 resize_grip_col[4], float resize_grip_draw_size); static void RenderWindowDecorations(ImGuiWindow* window, const ImRec t& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU 32 resize_grip_col[4], float resize_grip_draw_size);
static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open); static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);
static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col); static void RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32 col);
static void RenderDimmedBackgrounds(); static void RenderDimmedBackgrounds();
static ImGuiWindow* FindBlockingModal(ImGuiWindow* window); static ImGuiWindow* FindBlockingModal(ImGuiWindow* window);
skipping to change at line 1076 skipping to change at line 1104
TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor (TabMinWidthForCloseButton * scale_factor) : FLT_MAX; TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor (TabMinWidthForCloseButton * scale_factor) : FLT_MAX;
DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor);
DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor);
MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); MouseCursorScale = ImFloor(MouseCursorScale * scale_factor);
} }
ImGuiIO::ImGuiIO() ImGuiIO::ImGuiIO()
{ {
// Most fields are initialized with zero // Most fields are initialized with zero
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
IM_ASSERT(IM_ARRAYSIZE(ImGuiIO::MouseDown) == ImGuiMouseButton_COUNT && IM_A RRAYSIZE(ImGuiIO::MouseClicked) == ImGuiMouseButton_COUNT); // Our pre-C++11 IM_ STATIC_ASSERT() macros triggers warning on modern compilers so we don't use it h ere. IM_STATIC_ASSERT(IM_ARRAYSIZE(ImGuiIO::MouseDown) == ImGuiMouseButton_COUNT && IM_ARRAYSIZE(ImGuiIO::MouseClicked) == ImGuiMouseButton_COUNT);
// Settings // Settings
ConfigFlags = ImGuiConfigFlags_None; ConfigFlags = ImGuiConfigFlags_None;
BackendFlags = ImGuiBackendFlags_None; BackendFlags = ImGuiBackendFlags_None;
DisplaySize = ImVec2(-1.0f, -1.0f); DisplaySize = ImVec2(-1.0f, -1.0f);
DeltaTime = 1.0f / 60.0f; DeltaTime = 1.0f / 60.0f;
IniSavingRate = 5.0f; IniSavingRate = 5.0f;
IniFilename = "imgui.ini"; // Important: "imgui.ini" is relative to current working dir, most apps will want to lock this to an absolute path (e.g. same pat h as executables). IniFilename = "imgui.ini"; // Important: "imgui.ini" is relative to current working dir, most apps will want to lock this to an absolute path (e.g. same pat h as executables).
LogFilename = "imgui_log.txt"; LogFilename = "imgui_log.txt";
MouseDoubleClickTime = 0.30f; MouseDoubleClickTime = 0.30f;
MouseDoubleClickMaxDist = 6.0f; MouseDoubleClickMaxDist = 6.0f;
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
for (int i = 0; i < ImGuiKey_COUNT; i++) for (int i = 0; i < ImGuiKey_COUNT; i++)
KeyMap[i] = -1; KeyMap[i] = -1;
#endif
KeyRepeatDelay = 0.275f; KeyRepeatDelay = 0.275f;
KeyRepeatRate = 0.050f; KeyRepeatRate = 0.050f;
UserData = NULL; UserData = NULL;
Fonts = NULL; Fonts = NULL;
FontGlobalScale = 1.0f; FontGlobalScale = 1.0f;
FontDefault = NULL; FontDefault = NULL;
FontAllowUserScaling = false; FontAllowUserScaling = false;
DisplayFramebufferScale = ImVec2(1.0f, 1.0f); DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
// Miscellaneous options // Miscellaneous options
MouseDrawCursor = false; MouseDrawCursor = false;
#ifdef __APPLE__ #ifdef __APPLE__
ConfigMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APP LE__ compile time flag ConfigMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APP LE__ compile time flag
#else #else
ConfigMacOSXBehaviors = false; ConfigMacOSXBehaviors = false;
#endif #endif
ConfigInputTrickleEventQueue = true;
ConfigInputTextCursorBlink = true; ConfigInputTextCursorBlink = true;
ConfigWindowsResizeFromEdges = true; ConfigWindowsResizeFromEdges = true;
ConfigWindowsMoveFromTitleBarOnly = false; ConfigWindowsMoveFromTitleBarOnly = false;
ConfigMemoryCompactTimer = 60.0f; ConfigMemoryCompactTimer = 60.0f;
// Platform Functions // Platform Functions
BackendPlatformName = BackendRendererName = NULL; BackendPlatformName = BackendRendererName = NULL;
BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL;
GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations
SetClipboardTextFn = SetClipboardTextFn_DefaultImpl; SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
ClipboardUserData = NULL; ClipboardUserData = NULL;
ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl; SetPlatformImeDataFn = SetPlatformImeDataFn_DefaultImpl;
ImeWindowHandle = NULL;
// Input (NB: we already have memset zero the entire structure!) // Input (NB: we already have memset zero the entire structure!)
MousePos = ImVec2(-FLT_MAX, -FLT_MAX); MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX); MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);
MouseDragThreshold = 6.0f; MouseDragThreshold = 6.0f;
for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[ i] = MouseDownDurationPrev[i] = -1.0f; for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[ i] = MouseDownDurationPrev[i] = -1.0f;
for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f; for (int i = 0; i < IM_ARRAYSIZE(KeysData); i++) { KeysData[i].DownDuration = KeysData[i].DownDurationPrev = -1.0f; }
for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownD uration[i] = -1.0f; for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownD uration[i] = -1.0f;
BackendUsingLegacyKeyArrays = (ImS8)-1;
BackendUsingLegacyNavInputArray = true; // assume using legacy array until p
roven wrong
} }
// Pass in translated ASCII characters for text input. // Pass in translated ASCII characters for text input.
// - with glfw you can get those from the callback set in glfwSetCharCallback() // - 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_CH AR message // - on Windows you can get those using ToAscii+keyboard state, or via the WM_CH AR message
// FIXME: Should in theory be called "AddCharacterEvent()" to be consistent with new API
void ImGuiIO::AddInputCharacter(unsigned int c) void ImGuiIO::AddInputCharacter(unsigned int c)
{ {
if (c != 0) ImGuiContext& g = *GImGui;
InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar) IM_ASSERT(&g.IO == this && "Can only add events to current context.");
c : IM_UNICODE_CODEPOINT_INVALID); 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 // UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so
// we should save the high surrogate. // we should save the high surrogate.
void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c) void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
{ {
if (c == 0 && InputQueueSurrogate == 0) if (c == 0 && InputQueueSurrogate == 0)
return; return;
if ((c & 0xFC00) == 0xD800) // High surrogate, must save if ((c & 0xFC00) == 0xD800) // High surrogate, must save
{ {
if (InputQueueSurrogate != 0) if (InputQueueSurrogate != 0)
InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID); AddInputCharacter(IM_UNICODE_CODEPOINT_INVALID);
InputQueueSurrogate = c; InputQueueSurrogate = c;
return; return;
} }
ImWchar cp = c; ImWchar cp = c;
if (InputQueueSurrogate != 0) if (InputQueueSurrogate != 0)
{ {
if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate
{ {
InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID); AddInputCharacter(IM_UNICODE_CODEPOINT_INVALID);
} }
else else
{ {
#if IM_UNICODE_CODEPOINT_MAX == 0xFFFF #if IM_UNICODE_CODEPOINT_MAX == 0xFFFF
cp = IM_UNICODE_CODEPOINT_INVALID; // Codepoint will not fit in ImWc har cp = IM_UNICODE_CODEPOINT_INVALID; // Codepoint will not fit in ImWc har
#else #else
cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000); cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000);
#endif #endif
} }
InputQueueSurrogate = 0; InputQueueSurrogate = 0;
} }
InputQueueCharacters.push_back(cp); AddInputCharacter((unsigned)cp);
} }
void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars) void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
{ {
while (*utf8_chars != 0) while (*utf8_chars != 0)
{ {
unsigned int c = 0; unsigned int c = 0;
utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL); utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
if (c != 0) if (c != 0)
InputQueueCharacters.push_back((ImWchar)c); AddInputCharacter(c);
} }
} }
void ImGuiIO::ClearInputCharacters() void ImGuiIO::ClearInputCharacters()
{ {
InputQueueCharacters.resize(0); InputQueueCharacters.resize(0);
} }
void ImGuiIO::ClearInputKeys() void ImGuiIO::ClearInputKeys()
{ {
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
memset(KeysDown, 0, sizeof(KeysDown)); memset(KeysDown, 0, sizeof(KeysDown));
for (int n = 0; n < IM_ARRAYSIZE(KeysDownDuration); n++) #endif
KeysDownDuration[n] = KeysDownDurationPrev[n] = -1.0f; for (int n = 0; n < IM_ARRAYSIZE(KeysData); n++)
{
KeysData[n].Down = false;
KeysData[n].DownDuration = -1.0f;
KeysData[n].DownDurationPrev = -1.0f;
}
KeyCtrl = KeyShift = KeyAlt = KeySuper = false; KeyCtrl = KeyShift = KeyAlt = KeySuper = false;
KeyMods = KeyModsPrev = ImGuiKeyModFlags_None; KeyMods = KeyModsPrev = ImGuiKeyModFlags_None;
for (int n = 0; n < IM_ARRAYSIZE(NavInputsDownDuration); n++) for (int n = 0; n < IM_ARRAYSIZE(NavInputsDownDuration); n++)
NavInputsDownDuration[n] = NavInputsDownDurationPrev[n] = -1.0f; NavInputsDownDuration[n] = NavInputsDownDurationPrev[n] = -1.0f;
} }
// 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.
// - float analog_value: 0.0f..1.0f
void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value)
{
//if (e->Down) { IMGUI_DEBUG_LOG("AddKeyEvent() Key='%s' %d, NativeKeycode =
%d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycod
e, 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 ol
d io.KeysDown[] + io.KeyMap[] data.
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
IM_ASSERT((BackendUsingLegacyKeyArrays == -1 || BackendUsingLegacyKeyArrays
== 0) && "Backend needs to either only use io.AddKeyEvent(), either only fill le
gacy io.KeysDown[] + io.KeyMap[]. Not both!");
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.Ad
dKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!");
BackendUsingLegacyKeyArrays = 0;
#endif
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.Input
EventsQueue[n].Key.Key == key)
found = true;
if (!found)
return;
}
// Add event
ImGuiInputEvent e;
e.Type = ImGuiInputEventType_Key;
e.Source = ImGui::IsGamepadKey(key) ? ImGuiInputSource_Gamepad : ImGuiInputS
ource_Keyboard;
e.Key.Key = key;
e.Key.Down = down;
e.Key.AnalogValue = analog_value;
g.InputEventsQueue.push_back(e);
}
void ImGuiIO::AddKeyEvent(ImGuiKey key, bool down)
{
AddKeyAnalogEvent(key, down, down ? 1.0f : 0.0f);
}
// [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 valu
es 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)
{
if (key == ImGuiKey_None)
return;
IM_ASSERT(ImGui::IsNamedKey(key)); // >= 512
IM_ASSERT(native_legacy_index == -1 || ImGui::IsLegacyKey(native_legacy_inde
x)); // >= 0 && <= 511
IM_UNUSED(native_keycode); // Yet unused
IM_UNUSED(native_scancode); // Yet unused
// Build native->imgui map so old user code can still call key functions wit
h native 0..511 values.
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
const int legacy_key = (native_legacy_index != -1) ? native_legacy_index : n
ative_keycode;
if (ImGui::IsLegacyKey(legacy_key))
KeyMap[legacy_key] = key;
#else
IM_UNUSED(key);
IM_UNUSED(native_legacy_index);
#endif
}
// 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::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);
}
// Queue a mouse wheel event (most mouse/API will only have a Y component)
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::AddFocusEvent(bool focused) void ImGuiIO::AddFocusEvent(bool focused)
{ {
// We intentionally overwrite this and process in NewFrame(), in order to gi ImGuiContext& g = *GImGui;
ve a chance IM_ASSERT(&g.IO == this && "Can only add events to current context.");
// to multi-viewports backends to queue AddFocusEvent(false),AddFocusEvent(t
rue) in same frame. ImGuiInputEvent e;
AppFocusLost = !focused; e.Type = ImGuiInputEventType_Focus;
e.AppFocused.Focused = focused;
g.InputEventsQueue.push_back(e);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] MISC HELPERS/UTILITIES (Geometry functions) // [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec 2& p3, const ImVec2& p4, const ImVec2& p, int num_segments) ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec 2& p3, const ImVec2& p4, const ImVec2& p, int num_segments)
{ {
IM_ASSERT(num_segments > 0); // Use ImBezierCubicClosestPointCasteljau() IM_ASSERT(num_segments > 0); // Use ImBezierCubicClosestPointCasteljau()
ImVec2 p_last = p1; ImVec2 p_last = p1;
skipping to change at line 3191 skipping to change at line 3360
} }
} }
g.ActiveId = id; g.ActiveId = id;
g.ActiveIdAllowOverlap = false; g.ActiveIdAllowOverlap = false;
g.ActiveIdNoClearOnFocusLoss = false; g.ActiveIdNoClearOnFocusLoss = false;
g.ActiveIdWindow = window; g.ActiveIdWindow = window;
g.ActiveIdHasBeenEditedThisFrame = false; g.ActiveIdHasBeenEditedThisFrame = false;
if (id) if (id)
{ {
g.ActiveIdIsAlive = id; g.ActiveIdIsAlive = id;
g.ActiveIdSource = (g.NavActivateId == id || g.NavActivateInputId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse; g.ActiveIdSource = (g.NavActivateId == id || g.NavActivateInputId == id || g.NavJustMovedToId == id) ? (ImGuiInputSource)ImGuiInputSource_Nav : ImGuiInp utSource_Mouse;
} }
// Clear declaration of inputs claimed by the widget // Clear declaration of inputs claimed by the widget
// (Please note that this is WIP and not all keys/inputs are thoroughly decl ared by all widgets yet) // (Please note that this is WIP and not all keys/inputs are thoroughly decl ared by all widgets yet)
g.ActiveIdUsingMouseWheel = false; g.ActiveIdUsingMouseWheel = false;
g.ActiveIdUsingNavDirMask = 0x00; g.ActiveIdUsingNavDirMask = 0x00;
g.ActiveIdUsingNavInputMask = 0x00; g.ActiveIdUsingNavInputMask = 0x00;
g.ActiveIdUsingKeyInputMask = 0x00; g.ActiveIdUsingKeyInputMask.ClearAllBits();
} }
void ImGui::ClearActiveID() void ImGui::ClearActiveID()
{ {
SetActiveID(0, NULL); // g.ActiveId = 0; SetActiveID(0, NULL); // g.ActiveId = 0;
} }
void ImGui::SetHoveredID(ImGuiID id) void ImGui::SetHoveredID(ImGuiID id)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
skipping to change at line 3730 skipping to change at line 3899
bool hovered_window_above_modal = g.HoveredWindow && (modal == NULL || I sWindowAbove(g.HoveredWindow, modal)); bool hovered_window_above_modal = g.HoveredWindow && (modal == NULL || I sWindowAbove(g.HoveredWindow, modal));
ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : mod al, true); ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : mod al, true);
} }
} }
static bool IsWindowActiveAndVisible(ImGuiWindow* window) static bool IsWindowActiveAndVisible(ImGuiWindow* window)
{ {
return (window->Active) && (!window->Hidden); return (window->Active) && (!window->Hidden);
} }
static void ImGui::UpdateKeyboardInputs()
{
ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO;
// Synchronize io.KeyMods with individual modifiers io.KeyXXX bools
io.KeyMods = GetMergedKeyModFlags();
// Import legacy keys or verify they are not used
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
if (io.BackendUsingLegacyKeyArrays == 0)
{
// Backend used new io.AddKeyEvent() API: Good! Verify that old arrays a
re never written too.
for (int n = 0; n < IM_ARRAYSIZE(io.KeysDown); n++)
IM_ASSERT(io.KeysDown[n] == false && "Backend needs to either only u
se io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not bo
th!");
}
else
{
if (g.FrameCount == 0)
for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNati
veKey_END; n++)
IM_ASSERT(g.IO.KeyMap[n] == -1 && "Backend is not allowed to wri
te to io.KeyMap[0..511]!");
// Build reverse KeyMap (Named -> Legacy)
for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++)
if (io.KeyMap[n] != -1)
{
IM_ASSERT(IsLegacyKey((ImGuiKey)io.KeyMap[n]));
io.KeyMap[io.KeyMap[n]] = n;
}
// Import legacy keys into new ones
for (int n = ImGuiKey_LegacyNativeKey_BEGIN; n < ImGuiKey_LegacyNativeKe
y_END; n++)
if (io.KeysDown[n] || io.BackendUsingLegacyKeyArrays == 1)
{
const ImGuiKey key = (ImGuiKey)(io.KeyMap[n] != -1 ? io.KeyMap[n
] : n);
IM_ASSERT(io.KeyMap[n] == -1 || IsNamedKey(key));
io.KeysData[key].Down = io.KeysDown[n];
io.BackendUsingLegacyKeyArrays = 1;
}
if (io.BackendUsingLegacyKeyArrays == 1)
{
io.KeysData[ImGuiKey_ModCtrl].Down = io.KeyCtrl;
io.KeysData[ImGuiKey_ModShift].Down = io.KeyShift;
io.KeysData[ImGuiKey_ModAlt].Down = io.KeyAlt;
io.KeysData[ImGuiKey_ModSuper].Down = io.KeySuper;
}
}
#endif
// Clear gamepad data if disabled
if ((io.BackendFlags & ImGuiBackendFlags_HasGamepad) == 0)
for (int i = ImGuiKey_Gamepad_BEGIN; i < ImGuiKey_Gamepad_END; i++)
{
io.KeysData[i - ImGuiKey_KeysData_OFFSET].Down = false;
io.KeysData[i - ImGuiKey_KeysData_OFFSET].AnalogValue = 0.0f;
}
// Update keys
for (int i = 0; i < IM_ARRAYSIZE(io.KeysData); i++)
{
ImGuiKeyData& key_data = io.KeysData[i];
key_data.DownDurationPrev = key_data.DownDuration;
key_data.DownDuration = key_data.Down ? (key_data.DownDuration < 0.0f ?
0.0f : key_data.DownDuration + io.DeltaTime) : -1.0f;
}
}
static void ImGui::UpdateMouseInputs() static void ImGui::UpdateMouseInputs()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO;
// Round mouse position to avoid spreading non-rounded position (e.g. Update ManualResize doesn't support them well) // Round mouse position to avoid spreading non-rounded position (e.g. Update ManualResize doesn't support them well)
if (IsMousePosValid(&g.IO.MousePos)) if (IsMousePosValid(&io.MousePos))
g.IO.MousePos = g.MouseLastValidPos = ImFloor(g.IO.MousePos); io.MousePos = g.MouseLastValidPos = ImFloorSigned(io.MousePos);
// If mouse just appeared or disappeared (usually denoted by -FLT_MAX compon ents) we cancel out movement in MouseDelta // If mouse just appeared or disappeared (usually denoted by -FLT_MAX compon ents) we cancel out movement in MouseDelta
if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev)) if (IsMousePosValid(&io.MousePos) && IsMousePosValid(&io.MousePosPrev))
g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev; io.MouseDelta = io.MousePos - io.MousePosPrev;
else else
g.IO.MouseDelta = ImVec2(0.0f, 0.0f); io.MouseDelta = ImVec2(0.0f, 0.0f);
// If mouse moved we re-enable mouse hovering in case it was disabled by gam epad/keyboard. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true. // If mouse moved we re-enable mouse hovering in case it was disabled by gam epad/keyboard. In theory should use a >0.0f threshold but would need to reset in everywhere we set this to true.
if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f) if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f)
g.NavDisableMouseHover = false; g.NavDisableMouseHover = false;
g.IO.MousePosPrev = g.IO.MousePos; io.MousePosPrev = io.MousePos;
for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++) for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
{ {
g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < io.MouseClicked[i] = io.MouseDown[i] && io.MouseDownDuration[i] < 0.0f;
0.0f; io.MouseClickedCount[i] = 0; // Will be filled below
g.IO.MouseClickedCount[i] = 0; // Will be filled below io.MouseReleased[i] = !io.MouseDown[i] && io.MouseDownDuration[i] >= 0.0
g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] f;
>= 0.0f; io.MouseDownDurationPrev[i] = io.MouseDownDuration[i];
g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i]; io.MouseDownDuration[i] = io.MouseDown[i] ? (io.MouseDownDuration[i] < 0
g.IO.MouseDownDuration[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownDuration[ .0f ? 0.0f : io.MouseDownDuration[i] + io.DeltaTime) : -1.0f;
i] < 0.0f ? 0.0f : g.IO.MouseDownDuration[i] + g.IO.DeltaTime) : -1.0f; if (io.MouseClicked[i])
if (g.IO.MouseClicked[i])
{ {
bool is_repeated_click = false; bool is_repeated_click = false;
if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleCli ckTime) if ((float)(g.Time - io.MouseClickedTime[i]) < io.MouseDoubleClickTi me)
{ {
ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? ImVec2 delta_from_click_pos = IsMousePosValid(&io.MousePos) ? (i
(g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); o.MousePos - io.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMax if (ImLengthSqr(delta_from_click_pos) < io.MouseDoubleClickMaxDi
Dist * g.IO.MouseDoubleClickMaxDist) st * io.MouseDoubleClickMaxDist)
is_repeated_click = true; is_repeated_click = true;
} }
if (is_repeated_click) if (is_repeated_click)
g.IO.MouseClickedLastCount[i]++; io.MouseClickedLastCount[i]++;
else else
g.IO.MouseClickedLastCount[i] = 1; io.MouseClickedLastCount[i] = 1;
g.IO.MouseClickedTime[i] = g.Time; io.MouseClickedTime[i] = g.Time;
g.IO.MouseClickedPos[i] = g.IO.MousePos; io.MouseClickedPos[i] = io.MousePos;
g.IO.MouseClickedCount[i] = g.IO.MouseClickedLastCount[i]; io.MouseClickedCount[i] = io.MouseClickedLastCount[i];
g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f); io.MouseDragMaxDistanceSqr[i] = 0.0f;
g.IO.MouseDragMaxDistanceSqr[i] = 0.0f;
} }
else if (g.IO.MouseDown[i]) else if (io.MouseDown[i])
{ {
// Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold
ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.I float delta_sqr_click_pos = IsMousePosValid(&io.MousePos) ? ImLength
O.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f); Sqr(io.MousePos - io.MouseClickedPos[i]) : 0.0f;
g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr io.MouseDragMaxDistanceSqr[i] = ImMax(io.MouseDragMaxDistanceSqr[i],
[i], ImLengthSqr(delta_from_click_pos)); delta_sqr_click_pos);
g.IO.MouseDragMaxDistanceAbs[i].x = ImMax(g.IO.MouseDragMaxDistanceA
bs[i].x, delta_from_click_pos.x < 0.0f ? -delta_from_click_pos.x : delta_from_cl
ick_pos.x);
g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceA
bs[i].y, delta_from_click_pos.y < 0.0f ? -delta_from_click_pos.y : delta_from_cl
ick_pos.y);
} }
// We provide io.MouseDoubleClicked[] as a legacy service // We provide io.MouseDoubleClicked[] as a legacy service
g.IO.MouseDoubleClicked[i] = (g.IO.MouseClickedCount[i] == 2); io.MouseDoubleClicked[i] = (io.MouseClickedCount[i] == 2);
// Clicking any mouse button reactivate mouse hovering which may have be en deactivated by gamepad/keyboard navigation // Clicking any mouse button reactivate mouse hovering which may have be en deactivated by gamepad/keyboard navigation
if (g.IO.MouseClicked[i]) if (io.MouseClicked[i])
g.NavDisableMouseHover = false; g.NavDisableMouseHover = false;
} }
} }
static void StartLockWheelingWindow(ImGuiWindow* window) static void StartLockWheelingWindow(ImGuiWindow* window)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.WheelingWindow == window) if (g.WheelingWindow == window)
return; return;
g.WheelingWindow = window; g.WheelingWindow = window;
skipping to change at line 4077 skipping to change at line 4310
g.ActiveIdIsAlive = 0; g.ActiveIdIsAlive = 0;
g.ActiveIdHasBeenEditedThisFrame = false; g.ActiveIdHasBeenEditedThisFrame = false;
g.ActiveIdPreviousFrameIsAlive = false; g.ActiveIdPreviousFrameIsAlive = false;
g.ActiveIdIsJustActivated = false; g.ActiveIdIsJustActivated = false;
if (g.TempInputId != 0 && g.ActiveId != g.TempInputId) if (g.TempInputId != 0 && g.ActiveId != g.TempInputId)
g.TempInputId = 0; g.TempInputId = 0;
if (g.ActiveId == 0) if (g.ActiveId == 0)
{ {
g.ActiveIdUsingNavDirMask = 0x00; g.ActiveIdUsingNavDirMask = 0x00;
g.ActiveIdUsingNavInputMask = 0x00; g.ActiveIdUsingNavInputMask = 0x00;
g.ActiveIdUsingKeyInputMask = 0x00; g.ActiveIdUsingKeyInputMask.ClearAllBits();
} }
// Drag and drop // Drag and drop
g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr; g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr;
g.DragDropAcceptIdCurr = 0; g.DragDropAcceptIdCurr = 0;
g.DragDropAcceptIdCurrRectSurface = FLT_MAX; g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
g.DragDropWithinSource = false; g.DragDropWithinSource = false;
g.DragDropWithinTarget = false; g.DragDropWithinTarget = false;
g.DragDropHoldJustPressedId = 0; g.DragDropHoldJustPressedId = 0;
// Close popups on focus lost (currently wip/opt-in) // Close popups on focus lost (currently wip/opt-in)
//if (g.IO.AppFocusLost) //if (g.IO.AppFocusLost)
// ClosePopupsExceptModals(); // ClosePopupsExceptModals();
// Clear buttons state when focus is lost // Process input queue (trickle as many events as possible)
// (this is useful so e.g. releasing Alt after focus loss on Alt-Tab doesn't g.InputEventsTrail.resize(0);
trigger the Alt menu toggle) UpdateInputEvents(g.IO.ConfigInputTrickleEventQueue);
if (g.IO.AppFocusLost)
{
g.IO.ClearInputKeys();
g.IO.AppFocusLost = false;
}
// Update keyboard input state // Update keyboard input state
// Synchronize io.KeyMods with individual modifiers io.KeyXXX bools UpdateKeyboardInputs();
g.IO.KeyMods = GetMergedKeyModFlags();
memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDow //IM_ASSERT(g.IO.KeyCtrl == IsKeyDown(ImGuiKey_LeftCtrl) || IsKeyDown(ImGuiK
nDuration)); ey_RightCtrl));
for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++) //IM_ASSERT(g.IO.KeyShift == IsKeyDown(ImGuiKey_LeftShift) || IsKeyDown(ImGu
g.IO.KeysDownDuration[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownDuration[i] iKey_RightShift));
< 0.0f ? 0.0f : g.IO.KeysDownDuration[i] + g.IO.DeltaTime) : -1.0f; //IM_ASSERT(g.IO.KeyAlt == IsKeyDown(ImGuiKey_LeftAlt) || IsKeyDown(ImGuiKey
_RightAlt));
//IM_ASSERT(g.IO.KeySuper == IsKeyDown(ImGuiKey_LeftSuper) || IsKeyDown(ImGu
iKey_RightSuper));
// Update gamepad/keyboard navigation // Update gamepad/keyboard navigation
NavUpdate(); NavUpdate();
// Update mouse input state // Update mouse input state
UpdateMouseInputs(); UpdateMouseInputs();
// Find hovered window // Find hovered window
// (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredW indowUnderMovingWindow on the mouse release frame) // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredW indowUnderMovingWindow on the mouse release frame)
UpdateHoveredWindowAndCaptureFlags(); UpdateHoveredWindowAndCaptureFlags();
skipping to change at line 4128 skipping to change at line 4358
UpdateMouseMovingWindowNewFrame(); UpdateMouseMovingWindowNewFrame();
// Background darkening/whitening // Background darkening/whitening
if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.Nav WindowingHighlightAlpha > 0.0f)) if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.Nav WindowingHighlightAlpha > 0.0f))
g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f); g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f);
else else
g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f); g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f);
g.MouseCursor = ImGuiMouseCursor_Arrow; g.MouseCursor = ImGuiMouseCursor_Arrow;
g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInp utNextFrame = -1; g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInp utNextFrame = -1;
g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on
top-left of our window by default // Platform IME data: reset for the frame
g.PlatformImeDataPrev = g.PlatformImeData;
g.PlatformImeData.WantVisible = false;
// Mouse wheel scrolling, scale // Mouse wheel scrolling, scale
UpdateMouseWheel(); UpdateMouseWheel();
// Mark all windows as not visible and compact unused memory. // Mark all windows as not visible and compact unused memory.
IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size); IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size);
const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemory CompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer; const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemory CompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
for (int i = 0; i != g.Windows.Size; i++) for (int i = 0; i != g.Windows.Size; i++)
{ {
ImGuiWindow* window = g.Windows[i]; ImGuiWindow* window = g.Windows[i];
skipping to change at line 4324 skipping to change at line 4557
{ {
ImGuiWindow* child = window->DC.ChildWindows[i]; ImGuiWindow* child = window->DC.ChildWindows[i];
if (child->Active) if (child->Active)
AddWindowToSortBuffer(out_sorted_windows, child); AddWindowToSortBuffer(out_sorted_windows, child);
} }
} }
} }
static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* d raw_list) static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* d raw_list)
{ {
// Remove trailing command if unused.
// Technically we could return directly instead of popping, but this make th
ings looks neat in Metrics/Debugger window as well.
draw_list->_PopUnusedDrawCmd();
if (draw_list->CmdBuffer.Size == 0) if (draw_list->CmdBuffer.Size == 0)
return; return;
if (draw_list->CmdBuffer.Size == 1 && draw_list->CmdBuffer[0].ElemCount == 0
&& draw_list->CmdBuffer[0].UserCallback == NULL)
return;
// Draw list sanity check. Detect mismatch between PrimReserve() calls and i ncrementing _VtxCurrentIdx, _VtxWritePtr etc. // Draw list sanity check. Detect mismatch between PrimReserve() calls and i ncrementing _VtxCurrentIdx, _VtxWritePtr etc.
// May trigger for you if you are using PrimXXX functions incorrectly. // May trigger for you if you are using PrimXXX functions incorrectly.
IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_ list->VtxBuffer.Data + draw_list->VtxBuffer.Size); IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_ list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_ list->IdxBuffer.Data + draw_list->IdxBuffer.Size); IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_ list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset)) if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset))
IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size); IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
// Check that draw_list doesn't use more vertices than indexable (default Im DrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window) // Check that draw_list doesn't use more vertices than indexable (default Im DrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
// If this assert triggers because you are drawing lots of stuff manually: // If this assert triggers because you are drawing lots of stuff manually:
skipping to change at line 4414 skipping to change at line 4646
ImDrawData* draw_data = &viewport->DrawDataP; ImDrawData* draw_data = &viewport->DrawDataP;
draw_data->Valid = true; draw_data->Valid = true;
draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL; draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL;
draw_data->CmdListsCount = draw_lists->Size; draw_data->CmdListsCount = draw_lists->Size;
draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0; draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0;
draw_data->DisplayPos = viewport->Pos; draw_data->DisplayPos = viewport->Pos;
draw_data->DisplaySize = viewport->Size; draw_data->DisplaySize = viewport->Size;
draw_data->FramebufferScale = io.DisplayFramebufferScale; draw_data->FramebufferScale = io.DisplayFramebufferScale;
for (int n = 0; n < draw_lists->Size; n++) for (int n = 0; n < draw_lists->Size; n++)
{ {
draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size; ImDrawList* draw_list = draw_lists->Data[n];
draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size; draw_list->_PopUnusedDrawCmd();
draw_data->TotalVtxCount += draw_list->VtxBuffer.Size;
draw_data->TotalIdxCount += draw_list->IdxBuffer.Size;
} }
} }
// Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-lev el ImDrawList rendering. // Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-lev el ImDrawList rendering.
// - When using this function it is sane to ensure that float are perfectly roun ded to integer values, // - When using this function it is sane to ensure that float are perfectly roun ded to integer values,
// so that e.g. (int)(max.x-min.x) in user's render produce correct result. // so that e.g. (int)(max.x-min.x) in user's render produce correct result.
// - If the code here changes, may need to update code of functions like NextCol umn() and PushColumnClipRect(): // - If the code here changes, may need to update code of functions like NextCol umn() and PushColumnClipRect():
// some frequently called functions which to modify both channels and clipping simultaneously tend to use the // some frequently called functions which to modify both channels and clipping simultaneously tend to use the
// more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous up dates of underlying ImDrawCmds. // more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous up dates of underlying ImDrawCmds.
void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_ma x, bool intersect_with_current_clip_rect) void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_ma x, bool intersect_with_current_clip_rect)
skipping to change at line 4451 skipping to change at line 4685
if ((col & IM_COL32_A_MASK) == 0) if ((col & IM_COL32_A_MASK) == 0)
return; return;
ImGuiViewportP* viewport = (ImGuiViewportP*)GetMainViewport(); ImGuiViewportP* viewport = (ImGuiViewportP*)GetMainViewport();
ImRect viewport_rect = viewport->GetMainRect(); ImRect viewport_rect = viewport->GetMainRect();
// Draw behind window by moving the draw command at the FRONT of the draw li st // Draw behind window by moving the draw command at the FRONT of the draw li st
{ {
// We've already called AddWindowToDrawData() which called DrawList->Cha nnelsMerge() on DockNodeHost windows, // We've already called AddWindowToDrawData() which called DrawList->Cha nnelsMerge() on DockNodeHost windows,
// and draw list have been trimmed already, hence the explicit recreatio n of a draw command if missing. // and draw list have been trimmed already, hence the explicit recreatio n of a draw command if missing.
// FIXME: This is creating complication, might be simpler if we could in ject a drawlist in drawdata at a given position and not attempt to manipulate Im DrawCmd order.
ImDrawList* draw_list = window->RootWindow->DrawList; ImDrawList* draw_list = window->RootWindow->DrawList;
if (draw_list->CmdBuffer.Size == 0) if (draw_list->CmdBuffer.Size == 0)
draw_list->AddDrawCmd(); draw_list->AddDrawCmd();
draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect. Max + ImVec2(1, 1), false); // Ensure ImDrawCmd are not merged draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect. Max + ImVec2(1, 1), false); // Ensure ImDrawCmd are not merged
draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col); draw_list->AddRectFilled(viewport_rect.Min, viewport_rect.Max, col);
ImDrawCmd cmd = draw_list->CmdBuffer.back(); ImDrawCmd cmd = draw_list->CmdBuffer.back();
IM_ASSERT(cmd.ElemCount == 6); IM_ASSERT(cmd.ElemCount == 6);
draw_list->CmdBuffer.pop_back(); draw_list->CmdBuffer.pop_back();
draw_list->CmdBuffer.push_front(cmd); draw_list->CmdBuffer.push_front(cmd);
draw_list->PopClipRect(); draw_list->PopClipRect();
draw_list->AddDrawCmd(); // We need to create a command as CmdBuffer.bac k().IdxOffset won't be correct if we append to same command.
} }
} }
ImGuiWindow* ImGui::FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* par ent_window) ImGuiWindow* ImGui::FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* par ent_window)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* bottom_most_visible_window = parent_window; ImGuiWindow* bottom_most_visible_window = parent_window;
for (int i = FindWindowDisplayIndex(parent_window); i >= 0; i--) for (int i = FindWindowDisplayIndex(parent_window); i >= 0; i--)
{ {
ImGuiWindow* window = g.Windows[i]; ImGuiWindow* window = g.Windows[i];
skipping to change at line 4485 skipping to change at line 4721
if (IsWindowActiveAndVisible(window) && GetWindowDisplayLayer(window) <= GetWindowDisplayLayer(parent_window)) if (IsWindowActiveAndVisible(window) && GetWindowDisplayLayer(window) <= GetWindowDisplayLayer(parent_window))
bottom_most_visible_window = window; bottom_most_visible_window = window;
} }
return bottom_most_visible_window; return bottom_most_visible_window;
} }
static void ImGui::RenderDimmedBackgrounds() static void ImGui::RenderDimmedBackgrounds()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* modal_window = GetTopMostAndVisiblePopupModal(); ImGuiWindow* modal_window = GetTopMostAndVisiblePopupModal();
if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
return;
const bool dim_bg_for_modal = (modal_window != NULL); const bool dim_bg_for_modal = (modal_window != NULL);
const bool dim_bg_for_window_list = (g.NavWindowingTargetAnim != NULL && g.N avWindowingTargetAnim->Active); const bool dim_bg_for_window_list = (g.NavWindowingTargetAnim != NULL && g.N avWindowingTargetAnim->Active);
if (!dim_bg_for_modal && !dim_bg_for_window_list) if (!dim_bg_for_modal && !dim_bg_for_window_list)
return; return;
if (dim_bg_for_modal) if (dim_bg_for_modal)
{ {
// Draw dimming behind modal or a begin stack child, whichever comes fir st in draw order. // Draw dimming behind modal or a begin stack child, whichever comes fir st in draw order.
ImGuiWindow* dim_behind_window = FindBottomMostVisibleWindowWithinBeginS tack(modal_window); ImGuiWindow* dim_behind_window = FindBottomMostVisibleWindowWithinBeginS tack(modal_window);
RenderDimmedBackgroundBehindWindow(dim_behind_window, GetColorU32(ImGuiC ol_ModalWindowDimBg, g.DimBgRatio)); RenderDimmedBackgroundBehindWindow(dim_behind_window, GetColorU32(ImGuiC ol_ModalWindowDimBg, g.DimBgRatio));
skipping to change at line 4532 skipping to change at line 4770
// Don't process EndFrame() multiple times. // Don't process EndFrame() multiple times.
if (g.FrameCountEnded == g.FrameCount) if (g.FrameCountEnded == g.FrameCount)
return; return;
IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?"); IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?");
CallContextHooks(&g, ImGuiContextHookType_EndFramePre); CallContextHooks(&g, ImGuiContextHookType_EndFramePre);
ErrorCheckEndFrameSanityChecks(); ErrorCheckEndFrameSanityChecks();
// Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs // Notify Platform/OS when our Input Method Editor cursor has moved (e.g. CJ
using Microsoft IME) K inputs using Microsoft IME)
if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImL if (g.IO.SetPlatformImeDataFn && memcmp(&g.PlatformImeData, &g.PlatformImeDa
engthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f)) taPrev, sizeof(ImGuiPlatformImeData)) != 0)
{ g.IO.SetPlatformImeDataFn(GetMainViewport(), &g.PlatformImeData);
g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImeP
os.y);
g.PlatformImeLastPos = g.PlatformImePos;
}
// Hide implicit/fallback "Debug" window if it hasn't been used // Hide implicit/fallback "Debug" window if it hasn't been used
g.WithinFrameScopeWithImplicitWindow = false; g.WithinFrameScopeWithImplicitWindow = false;
if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed) if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed)
g.CurrentWindow->Active = false; g.CurrentWindow->Active = false;
End(); End();
// Update navigation: CTRL+Tab, wrap-around requests // Update navigation: CTRL+Tab, wrap-around requests
NavEndFrame(); NavEndFrame();
skipping to change at line 4753 skipping to change at line 4988
if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow)) if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow))
hovered_window_ignoring_moving_window = window; hovered_window_ignoring_moving_window = window;
if (hovered_window && hovered_window_ignoring_moving_window) if (hovered_window && hovered_window_ignoring_moving_window)
break; break;
} }
g.HoveredWindow = hovered_window; g.HoveredWindow = hovered_window;
g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window; g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window;
} }
// Test if mouse cursor is hovering given rectangle
// NB- Rectangle is clipped by our current clip setting
// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.
TouchExtraPadding)
bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool c
lip)
{
ImGuiContext& g = *GImGui;
// Clip
ImRect rect_clipped(r_min, r_max);
if (clip)
rect_clipped.ClipWith(g.CurrentWindow->ClipRect);
// Expand for touch input
const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, re
ct_clipped.Max + g.Style.TouchExtraPadding);
if (!rect_for_touch.Contains(g.IO.MousePos))
return false;
return true;
}
int ImGui::GetKeyIndex(ImGuiKey imgui_key)
{
IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT);
ImGuiContext& g = *GImGui;
return g.IO.KeyMap[imgui_key];
}
// Note that dear imgui doesn't know the semantic of each entry of io.KeysDown[]
!
// Use your own indices/enums according to how your backend/engine stored them i
nto io.KeysDown[]!
bool ImGui::IsKeyDown(int user_key_index)
{
if (user_key_index < 0)
return false;
ImGuiContext& g = *GImGui;
IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown
));
return g.IO.KeysDown[user_key_index];
}
// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime)
// t1 = current time (e.g.: g.Time)
// An event is triggered at:
// t = 0.0f t = repeat_delay, t = repeat_delay + repeat_rate*N
int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, flo
at repeat_rate)
{
if (t1 == 0.0f)
return 1;
if (t0 >= t1)
return 0;
if (repeat_rate <= 0.0f)
return (t0 < repeat_delay) && (t1 >= repeat_delay);
const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) /
repeat_rate);
const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) /
repeat_rate);
const int count = count_t1 - count_t0;
return count;
}
int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_r
ate)
{
ImGuiContext& g = *GImGui;
if (key_index < 0)
return 0;
IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
const float t = g.IO.KeysDownDuration[key_index];
return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat
_rate);
}
bool ImGui::IsKeyPressed(int user_key_index, bool repeat)
{
ImGuiContext& g = *GImGui;
if (user_key_index < 0)
return false;
IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown
));
const float t = g.IO.KeysDownDuration[user_key_index];
if (t == 0.0f)
return true;
if (repeat && t > g.IO.KeyRepeatDelay)
return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.Key
RepeatRate) > 0;
return false;
}
bool ImGui::IsKeyReleased(int user_key_index)
{
ImGuiContext& g = *GImGui;
if (user_key_index < 0) return false;
IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown
));
return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[u
ser_key_index];
}
bool ImGui::IsMouseDown(ImGuiMouseButton button)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
return g.IO.MouseDown[button];
}
bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
const float t = g.IO.MouseDownDuration[button];
if (t == 0.0f)
return true;
if (repeat && t > g.IO.KeyRepeatDelay)
{
// FIXME: 2019/05/03: Our old repeat code was wrong here and led to doub
ling the repeat rate, which made it an ok rate for repeat on mouse hold.
int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRe
peatDelay, g.IO.KeyRepeatRate * 0.50f);
if (amount > 0)
return true;
}
return false;
}
bool ImGui::IsMouseReleased(ImGuiMouseButton button)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
return g.IO.MouseReleased[button];
}
bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
return g.IO.MouseClickedCount[button] == 2;
}
int ImGui::GetMouseClickedCount(ImGuiMouseButton button)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
return g.IO.MouseClickedCount[button];
}
// Return if a mouse click/drag went past the given threshold. Valid to call dur
ing the MouseReleased frame.
// [Internal] This doesn't test if the button is pressed
bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_thresho
ld)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
if (lock_threshold < 0.0f)
lock_threshold = g.IO.MouseDragThreshold;
return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_thresho
ld;
}
bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
if (!g.IO.MouseDown[button])
return false;
return IsMouseDragPastThreshold(button, lock_threshold);
}
ImVec2 ImGui::GetMousePos()
{
ImGuiContext& g = *GImGui;
return g.IO.MousePos;
}
// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem
is activated, the popup is already closed!
ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup()
{
ImGuiContext& g = *GImGui;
if (g.BeginPopupStack.Size > 0)
return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos;
return g.IO.MousePos;
}
// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse positio
n.
bool ImGui::IsMousePosValid(const ImVec2* mouse_pos)
{
// The assert is only to silence a false-positive in XCode Static Analysis.
// Because GImGui is not dereferenced in every code path, the static analyze
r assume that it may be NULL (which it doesn't for other functions).
IM_ASSERT(GImGui != NULL);
const float MOUSE_INVALID = -256000.0f;
ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos;
return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID;
}
bool ImGui::IsAnyMouseDown()
{
ImGuiContext& g = *GImGui;
for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++)
if (g.IO.MouseDown[n])
return true;
return false;
}
// Return the delta from the initial clicking position while the mouse button is
clicked or was just released.
// This is locked and return 0.0f until the mouse moves past a distance threshol
d at least once.
// NB: This is only valid if IsMousePosValid(). backends in theory should always
keep mouse position valid when dragging even outside the client window.
ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
if (lock_threshold < 0.0f)
lock_threshold = g.IO.MouseDragThreshold;
if (g.IO.MouseDown[button] || g.IO.MouseReleased[button])
if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_thresh
old)
if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseCl
ickedPos[button]))
return g.IO.MousePos - g.IO.MouseClickedPos[button];
return ImVec2(0.0f, 0.0f);
}
void ImGui::ResetMouseDragDelta(ImGuiMouseButton button)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
// NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
g.IO.MouseClickedPos[button] = g.IO.MousePos;
}
ImGuiMouseCursor ImGui::GetMouseCursor()
{
return GImGui->MouseCursor;
}
void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type)
{
GImGui->MouseCursor = cursor_type;
}
void ImGui::CaptureKeyboardFromApp(bool capture)
{
GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0;
}
void ImGui::CaptureMouseFromApp(bool capture)
{
GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0;
}
bool ImGui::IsItemActive() bool ImGui::IsItemActive()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.ActiveId) if (g.ActiveId)
return g.ActiveId == g.LastItemData.ID; return g.ActiveId == g.LastItemData.ID;
return false; return false;
} }
bool ImGui::IsItemActivated() bool ImGui::IsItemActivated()
{ {
skipping to change at line 5102 skipping to change at line 5105
if (g.ActiveId == id) if (g.ActiveId == id)
g.ActiveIdUsingMouseWheel = true; g.ActiveIdUsingMouseWheel = true;
} }
void ImGui::SetActiveIdUsingNavAndKeys() void ImGui::SetActiveIdUsingNavAndKeys()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(g.ActiveId != 0); IM_ASSERT(g.ActiveId != 0);
g.ActiveIdUsingNavDirMask = ~(ImU32)0; g.ActiveIdUsingNavDirMask = ~(ImU32)0;
g.ActiveIdUsingNavInputMask = ~(ImU32)0; g.ActiveIdUsingNavInputMask = ~(ImU32)0;
g.ActiveIdUsingKeyInputMask = ~(ImU64)0; g.ActiveIdUsingKeyInputMask.SetAllBits();
NavMoveRequestCancel(); NavMoveRequestCancel();
} }
ImVec2 ImGui::GetItemRectMin() ImVec2 ImGui::GetItemRectMin()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
return g.LastItemData.Rect.Min; return g.LastItemData.Rect.Min;
} }
ImVec2 ImGui::GetItemRectMax() ImVec2 ImGui::GetItemRectMax()
skipping to change at line 5915 skipping to change at line 5918
static ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window) static ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.OpenPopupStack.Size <= 0) if (g.OpenPopupStack.Size <= 0)
return NULL; return NULL;
// Find a modal that has common parent with specified window. Specified wind ow should be positioned behind that modal. // Find a modal that has common parent with specified window. Specified wind ow should be positioned behind that modal.
for (int i = g.OpenPopupStack.Size - 1; i >= 0; i--) for (int i = g.OpenPopupStack.Size - 1; i >= 0; i--)
{ {
ImGuiWindow* popup_window = g.OpenPopupStack.Data[i].Window; ImGuiWindow* popup_window = g.OpenPopupStack.Data[i].Window;
if (popup_window == NULL || !popup_window->WasActive || !(popup_window-> if (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Mod
Flags & ImGuiWindowFlags_Modal)) // Check WasActive, because this code may run b al))
efore popup renders on current frame. continue;
if (!popup_window->Active && !popup_window->WasActive) // Check Was
Active, because this code may run before popup renders on current frame, also ch
eck Active to handle newly created windows.
continue; continue;
if (IsWindowWithinBeginStackOf(window, popup_window)) // Window is rendered over last modal, no render order change needed. if (IsWindowWithinBeginStackOf(window, popup_window)) // Window is rendered over last modal, no render order change needed.
break; break;
for (ImGuiWindow* parent = popup_window->ParentWindowInBeginStack->RootW indow; parent != NULL; parent = parent->ParentWindowInBeginStack->RootWindow) for (ImGuiWindow* parent = popup_window->ParentWindowInBeginStack->RootW indow; parent != NULL; parent = parent->ParentWindowInBeginStack->RootWindow)
if (IsWindowWithinBeginStackOf(window, parent)) if (IsWindowWithinBeginStackOf(window, parent))
return popup_window; // Place win dow above its begin stack parent. return popup_window; // Place win dow above its begin stack parent.
} }
return NULL; return NULL;
} }
skipping to change at line 6077 skipping to change at line 6082
if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus) if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus)
FocusWindow(window); FocusWindow(window);
if (window->Appearing) if (window->Appearing)
SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false); SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);
// When reusing window again multiple times a frame, just append content (do n't need to setup again) // When reusing window again multiple times a frame, just append content (do n't need to setup again)
if (first_begin_of_the_frame) if (first_begin_of_the_frame)
{ {
// Initialize // Initialize
const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWind ow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior o f Child+Tooltip for pinned tooltip (#1345) const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWind ow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior o f Child+Tooltip for pinned tooltip (#1345)
const bool window_just_appearing_after_hidden_for_resize = (window->Hidd enFramesCannotSkipItems > 0);
window->Active = true; window->Active = true;
window->HasCloseButton = (p_open != NULL); window->HasCloseButton = (p_open != NULL);
window->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX); window->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX);
window->IDStack.resize(1); window->IDStack.resize(1);
window->DrawList->_ResetForNewFrame(); window->DrawList->_ResetForNewFrame();
window->DC.CurrentTableIdx = -1; window->DC.CurrentTableIdx = -1;
// Restore buffer capacity when woken from a compacted state, to avoid // Restore buffer capacity when woken from a compacted state, to avoid
if (window->MemoryCompacted) if (window->MemoryCompacted)
GcAwakeTransientWindowBuffers(window); GcAwakeTransientWindowBuffers(window);
skipping to change at line 6103 skipping to change at line 6109
if (window_title_visible_elsewhere && !window_just_created && strcmp(nam e, window->Name) != 0) if (window_title_visible_elsewhere && !window_just_created && strcmp(nam e, window->Name) != 0)
{ {
size_t buf_len = (size_t)window->NameBufLen; size_t buf_len = (size_t)window->NameBufLen;
window->Name = ImStrdupcpy(window->Name, &buf_len, name); window->Name = ImStrdupcpy(window->Name, &buf_len, name);
window->NameBufLen = (int)buf_len; window->NameBufLen = (int)buf_len;
} }
// UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
// Update contents size from last frame for auto-fitting (or use explici t size) // Update contents size from last frame for auto-fitting (or use explici t size)
const bool window_just_appearing_after_hidden_for_resize = (window->Hidd enFramesCannotSkipItems > 0);
CalcWindowContentSizes(window, &window->ContentSize, &window->ContentSiz eIdeal); CalcWindowContentSizes(window, &window->ContentSize, &window->ContentSiz eIdeal);
if (window->HiddenFramesCanSkipItems > 0) if (window->HiddenFramesCanSkipItems > 0)
window->HiddenFramesCanSkipItems--; window->HiddenFramesCanSkipItems--;
if (window->HiddenFramesCannotSkipItems > 0) if (window->HiddenFramesCannotSkipItems > 0)
window->HiddenFramesCannotSkipItems--; window->HiddenFramesCannotSkipItems--;
if (window->HiddenFramesForRenderOnly > 0) if (window->HiddenFramesForRenderOnly > 0)
window->HiddenFramesForRenderOnly--; window->HiddenFramesForRenderOnly--;
// Hide new windows for one frame until they calculate their size // Hide new windows for one frame until they calculate their size
if (window_just_created && (!window_size_x_set_by_api || !window_size_y_ set_by_api)) if (window_just_created && (!window_size_x_set_by_api || !window_size_y_ set_by_api))
skipping to change at line 6293 skipping to change at line 6298
want_focus = false; want_focus = false;
if (window == window->RootWindow) if (window == window->RootWindow)
{ {
ImGuiWindow* blocking_modal = FindBlockingModal(window); ImGuiWindow* blocking_modal = FindBlockingModal(window);
IM_ASSERT(blocking_modal != NULL); IM_ASSERT(blocking_modal != NULL);
BringWindowToDisplayBehind(window, blocking_modal); BringWindowToDisplayBehind(window, blocking_modal);
} }
} }
} }
// [Test Engine] Register whole window in the item system
#ifdef IMGUI_ENABLE_TEST_ENGINE
if (g.TestEngineHookItems)
{
IM_ASSERT(window->IDStack.Size == 1);
window->IDStack.Size = 0;
IMGUI_TEST_ENGINE_ITEM_ADD(window->Rect(), window->ID);
IMGUI_TEST_ENGINE_ITEM_INFO(window->ID, window->Name, (g.HoveredWind
ow == window) ? ImGuiItemStatusFlags_HoveredRect : 0);
window->IDStack.Size = 1;
}
#endif
// Handle manual resize: Resize Grips, Borders, Gamepad // Handle manual resize: Resize Grips, Borders, Gamepad
int border_held = -1; int border_held = -1;
ImU32 resize_grip_col[4] = {}; ImU32 resize_grip_col[4] = {};
const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it.
const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.10f, w indow->WindowRounding + 1.0f + g.FontSize * 0.2f)); const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.10f, w indow->WindowRounding + 1.0f + g.FontSize * 0.2f));
if (!window->Collapsed) if (!window->Collapsed)
if (UpdateWindowManualResize(window, size_auto_fit, &border_held, re size_grip_count, &resize_grip_col[0], visibility_rect)) if (UpdateWindowManualResize(window, size_auto_fit, &border_held, re size_grip_count, &resize_grip_col[0], visibility_rect))
use_current_size_for_scrollbar_x = use_current_size_for_scrollba r_y = true; use_current_size_for_scrollbar_x = use_current_size_for_scrollba r_y = true;
window->ResizeBorderHeld = (signed char)border_held; window->ResizeBorderHeld = (signed char)border_held;
skipping to change at line 6514 skipping to change at line 6531
//if (g.NavWindow == window && g.ActiveId == 0) //if (g.NavWindow == window && g.ActiveId == 0)
if (g.ActiveId == window->MoveId) if (g.ActiveId == window->MoveId)
if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C)) if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C))
LogToClipboard(); LogToClipboard();
*/ */
// We fill last item data based on Title Bar/Tab, in order for IsItemHov ered() and IsItemActive() to be usable after Begin(). // We fill last item data based on Title Bar/Tab, in order for IsItemHov ered() and IsItemActive() to be usable after Begin().
// This is useful to allow creating context menus on title bar only, etc . // This is useful to allow creating context menus on title bar only, etc .
SetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect( title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRec t : 0, title_bar_rect); SetLastItemData(window->MoveId, g.CurrentItemFlags, IsMouseHoveringRect( title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRec t : 0, title_bar_rect);
#ifdef IMGUI_ENABLE_TEST_ENGINE // [Test Engine] Register title bar / tab
if (!(window->Flags & ImGuiWindowFlags_NoTitleBar)) if (!(window->Flags & ImGuiWindowFlags_NoTitleBar))
IMGUI_TEST_ENGINE_ITEM_ADD(g.LastItemData.Rect, g.LastItemData.ID); IMGUI_TEST_ENGINE_ITEM_ADD(g.LastItemData.Rect, g.LastItemData.ID);
#endif
} }
else else
{ {
// Append // Append
SetCurrentWindow(window); SetCurrentWindow(window);
} }
// Pull/inherit current state // Pull/inherit current state
window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : window->GetID("#FOCUSSCOPE"); // Inh erit from parent only // -V595 window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : window->GetID("#FOCUSSCOPE"); // Inh erit from parent only // -V595
skipping to change at line 7446 skipping to change at line 7462
return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.Cur sorPos + size)); return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.Cur sorPos + size));
} }
bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max) bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
{ {
ImGuiWindow* window = GImGui->CurrentWindow; ImGuiWindow* window = GImGui->CurrentWindow;
return window->ClipRect.Overlaps(ImRect(rect_min, rect_max)); return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] INPUTS
//-----------------------------------------------------------------------------
// Test if mouse cursor is hovering given rectangle
// NB- Rectangle is clipped by our current clip setting
// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.
TouchExtraPadding)
bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool c
lip)
{
ImGuiContext& g = *GImGui;
// Clip
ImRect rect_clipped(r_min, r_max);
if (clip)
rect_clipped.ClipWith(g.CurrentWindow->ClipRect);
// Expand for touch input
const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, re
ct_clipped.Max + g.Style.TouchExtraPadding);
if (!rect_for_touch.Contains(g.IO.MousePos))
return false;
return true;
}
ImGuiKeyData* ImGui::GetKeyData(ImGuiKey key)
{
ImGuiContext& g = *GImGui;
int index;
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
IM_ASSERT(key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_NamedKey_E
ND);
if (IsLegacyKey(key))
index = (g.IO.KeyMap[key] != -1) ? g.IO.KeyMap[key] : key; // Remap nati
ve->imgui or imgui->native
else
index = key;
#else
IM_ASSERT(IsNamedKey(key) && "Support for user key indices was dropped in fa
vor of ImGuiKey. Please update backend & user code.");
index = key - ImGuiKey_NamedKey_BEGIN;
#endif
return &g.IO.KeysData[index];
}
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
int ImGui::GetKeyIndex(ImGuiKey key)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(IsNamedKey(key));
const ImGuiKeyData* key_data = GetKeyData(key);
return (int)(key_data - g.IO.KeysData);
}
#endif
// Those names a provided for debugging purpose and are not meant to be saved pe
rsistently not compared.
static const char* const GKeyNames[] =
{
"Tab", "LeftArrow", "RightArrow", "UpArrow", "DownArrow", "PageUp", "PageDow
n",
"Home", "End", "Insert", "Delete", "Backspace", "Space", "Enter", "Escape",
"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",
"Apostrophe", "Comma", "Minus", "Period", "Slash", "Semicolon", "Equal", "Le
ftBracket",
"Backslash", "RightBracket", "GraveAccent", "CapsLock", "ScrollLock", "NumLo
ck", "PrintScreen",
"Pause", "Keypad0", "Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "
Keypad6",
"Keypad7", "Keypad8", "Keypad9", "KeypadDecimal", "KeypadDivide", "KeypadMul
tiply",
"KeypadSubtract", "KeypadAdd", "KeypadEnter", "KeypadEqual",
"GamepadStart", "GamepadBack", "GamepadFaceUp", "GamepadFaceDown", "GamepadF
aceLeft", "GamepadFaceRight",
"GamepadDpadUp", "GamepadDpadDown", "GamepadDpadLeft", "GamepadDpadRight",
"GamepadL1", "GamepadR1", "GamepadL2", "GamepadR2", "GamepadL3", "GamepadR3"
,
"GamepadLStickUp", "GamepadLStickDown", "GamepadLStickLeft", "GamepadLStickR
ight",
"GamepadRStickUp", "GamepadRStickDown", "GamepadRStickLeft", "GamepadRStickR
ight",
"ModCtrl", "ModShift", "ModAlt", "ModSuper"
};
IM_STATIC_ASSERT(ImGuiKey_NamedKey_COUNT == IM_ARRAYSIZE(GKeyNames));
const char* ImGui::GetKeyName(ImGuiKey key)
{
#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
IM_ASSERT((IsNamedKey(key) || key == ImGuiKey_None) && "Support for user key
indices was dropped in favor of ImGuiKey. Please update backend and user code."
);
#else
if (IsLegacyKey(key))
{
ImGuiIO& io = GetIO();
if (io.KeyMap[key] == -1)
return "N/A";
IM_ASSERT(IsNamedKey((ImGuiKey)io.KeyMap[key]));
key = (ImGuiKey)io.KeyMap[key];
}
#endif
if (key == ImGuiKey_None)
return "None";
if (!IsNamedKey(key))
return "Unknown";
return GKeyNames[key - ImGuiKey_NamedKey_BEGIN];
}
// Note that Dear ImGui doesn't know the meaning/semantic of ImGuiKey from 0..51
1: they are legacy native keycodes.
// Consider transitioning from 'IsKeyDown(MY_ENGINE_KEY_A)' (<1.87) to IsKeyDown
(ImGuiKey_A) (>= 1.87)
bool ImGui::IsKeyDown(ImGuiKey key)
{
const ImGuiKeyData* key_data = GetKeyData(key);
return key_data->Down;
}
// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime)
// t1 = current time (e.g.: g.Time)
// An event is triggered at:
// t = 0.0f t = repeat_delay, t = repeat_delay + repeat_rate*N
int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, flo
at repeat_rate)
{
if (t1 == 0.0f)
return 1;
if (t0 >= t1)
return 0;
if (repeat_rate <= 0.0f)
return (t0 < repeat_delay) && (t1 >= repeat_delay);
const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) /
repeat_rate);
const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) /
repeat_rate);
const int count = count_t1 - count_t0;
return count;
}
int ImGui::GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float repeat_ra
te)
{
ImGuiContext& g = *GImGui;
const ImGuiKeyData* key_data = GetKeyData(key);
const float t = key_data->DownDuration;
return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat
_rate);
}
bool ImGui::IsKeyPressed(ImGuiKey key, bool repeat)
{
ImGuiContext& g = *GImGui;
const ImGuiKeyData* key_data = GetKeyData(key);
const float t = key_data->DownDuration;
if (t == 0.0f)
return true;
if (repeat && t > g.IO.KeyRepeatDelay)
return GetKeyPressedAmount(key, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate)
> 0;
return false;
}
bool ImGui::IsKeyReleased(ImGuiKey key)
{
const ImGuiKeyData* key_data = GetKeyData(key);
return key_data->DownDurationPrev >= 0.0f && !key_data->Down;
}
bool ImGui::IsMouseDown(ImGuiMouseButton button)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
return g.IO.MouseDown[button];
}
bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
const float t = g.IO.MouseDownDuration[button];
if (t == 0.0f)
return true;
if (repeat && t > g.IO.KeyRepeatDelay)
{
// FIXME: 2019/05/03: Our old repeat code was wrong here and led to doub
ling the repeat rate, which made it an ok rate for repeat on mouse hold.
int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRe
peatDelay, g.IO.KeyRepeatRate * 0.50f);
if (amount > 0)
return true;
}
return false;
}
bool ImGui::IsMouseReleased(ImGuiMouseButton button)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
return g.IO.MouseReleased[button];
}
bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
return g.IO.MouseClickedCount[button] == 2;
}
int ImGui::GetMouseClickedCount(ImGuiMouseButton button)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
return g.IO.MouseClickedCount[button];
}
// Return if a mouse click/drag went past the given threshold. Valid to call dur
ing the MouseReleased frame.
// [Internal] This doesn't test if the button is pressed
bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_thresho
ld)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
if (lock_threshold < 0.0f)
lock_threshold = g.IO.MouseDragThreshold;
return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_thresho
ld;
}
bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
if (!g.IO.MouseDown[button])
return false;
return IsMouseDragPastThreshold(button, lock_threshold);
}
ImVec2 ImGui::GetMousePos()
{
ImGuiContext& g = *GImGui;
return g.IO.MousePos;
}
// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem
is activated, the popup is already closed!
ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup()
{
ImGuiContext& g = *GImGui;
if (g.BeginPopupStack.Size > 0)
return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos;
return g.IO.MousePos;
}
// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse positio
n.
bool ImGui::IsMousePosValid(const ImVec2* mouse_pos)
{
// The assert is only to silence a false-positive in XCode Static Analysis.
// Because GImGui is not dereferenced in every code path, the static analyze
r assume that it may be NULL (which it doesn't for other functions).
IM_ASSERT(GImGui != NULL);
const float MOUSE_INVALID = -256000.0f;
ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos;
return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID;
}
// [WILL OBSOLETE] This was designed for backends, but prefer having backend mai
ntain a mask of held mouse buttons, because upcoming input queue system will mak
e this invalid.
bool ImGui::IsAnyMouseDown()
{
ImGuiContext& g = *GImGui;
for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++)
if (g.IO.MouseDown[n])
return true;
return false;
}
// Return the delta from the initial clicking position while the mouse button is
clicked or was just released.
// This is locked and return 0.0f until the mouse moves past a distance threshol
d at least once.
// NB: This is only valid if IsMousePosValid(). backends in theory should always
keep mouse position valid when dragging even outside the client window.
ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
if (lock_threshold < 0.0f)
lock_threshold = g.IO.MouseDragThreshold;
if (g.IO.MouseDown[button] || g.IO.MouseReleased[button])
if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_thresh
old)
if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseCl
ickedPos[button]))
return g.IO.MousePos - g.IO.MouseClickedPos[button];
return ImVec2(0.0f, 0.0f);
}
void ImGui::ResetMouseDragDelta(ImGuiMouseButton button)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
// NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
g.IO.MouseClickedPos[button] = g.IO.MousePos;
}
ImGuiMouseCursor ImGui::GetMouseCursor()
{
ImGuiContext& g = *GImGui;
return g.MouseCursor;
}
void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type)
{
ImGuiContext& g = *GImGui;
g.MouseCursor = cursor_type;
}
void ImGui::CaptureKeyboardFromApp(bool capture)
{
ImGuiContext& g = *GImGui;
g.WantCaptureKeyboardNextFrame = capture ? 1 : 0;
}
void ImGui::CaptureMouseFromApp(bool capture)
{
ImGuiContext& g = *GImGui;
g.WantCaptureMouseNextFrame = capture ? 1 : 0;
}
static const char* GetInputSourceName(ImGuiInputSource source)
{
const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad",
"Nav", "Clipboard" };
IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT && sour
ce >= 0 && source < ImGuiInputSource_COUNT);
return input_source_names[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 (successiv
e 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_i
nputed = false;
int mouse_button_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(eve
nt_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 h
andled a mouse button change
if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_w
heeled || key_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 multi
ple 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 multi
ple action on the event
if (trickle_fast_inputs && (mouse_wheeled || mouse_button_change
d != 0))
break;
io.MouseWheelH += e->MouseWheel.WheelX;
io.MouseWheel += e->MouseWheel.WheelY;
mouse_wheeled = true;
}
}
else if (e->Type == ImGuiInputEventType_Key)
{
ImGuiKey key = e->Key.Key;
IM_ASSERT(key != ImGuiKey_None);
const int keydata_index = (key - ImGuiKey_KeysData_OFFSET);
ImGuiKeyData* keydata = &io.KeysData[keydata_index];
if (keydata->Down != e->Key.Down || keydata->AnalogValue != e->Key.A
nalogValue)
{
// Trickling Rule: Stop processing queued events if we got multi
ple action on the same button
if (trickle_fast_inputs && keydata->Down != e->Key.Down && (key_
changed_mask.TestBit(keydata_index) || text_inputed || mouse_button_changed != 0
))
break;
keydata->Down = e->Key.Down;
keydata->AnalogValue = e->Key.AnalogValue;
key_changed = true;
key_changed_mask.SetBit(keydata_index);
if (key == ImGuiKey_ModCtrl || key == ImGuiKey_ModShift || key =
= ImGuiKey_ModAlt || key == ImGuiKey_ModSuper)
{
if (key == ImGuiKey_ModCtrl) { io.KeyCtrl = keydata->Down; }
if (key == ImGuiKey_ModShift) { io.KeyShift = keydata->Down;
}
if (key == ImGuiKey_ModAlt) { io.KeyAlt = keydata->Down; }
if (key == ImGuiKey_ModSuper) { io.KeySuper = keydata->Down;
}
io.KeyMods = GetMergedKeyModFlags();
}
}
}
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 ? (I
mWchar)c : IM_UNICODE_CODEPOINT_INVALID);
text_inputed = true;
}
else if (e->Type == ImGuiInputEventType_Focus)
{
// We intentionally overwrite this and process lower, in order to gi
ve a chance
// to multi-viewports backends to queue AddFocusEvent(false) + AddFo
cusEvent(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 precis
e trail)
//if (event_n != 0) IMGUI_DEBUG_LOG("Processed: %d / Remaining: %d\n", event
_n, g.InputEventsQueue.Size - event_n);
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.Dat
a + 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 // [SECTION] ERROR CHECKING
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui. // Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui.
// Verify that the type sizes are matching between the calling file's compilatio n unit and imgui.cpp's compilation unit // Verify that the type sizes are matching between the calling file's compilatio n unit and imgui.cpp's compilation unit
// If the user has inconsistent compilation settings, imgui configuration #defin e, packing pragma, etc. your user code // If the user has inconsistent compilation settings, imgui configuration #defin e, packing pragma, etc. your user code
// may see different structures than what imgui.cpp sees, which is problematic. // may see different structures than what imgui.cpp sees, which is problematic.
// We usually require settings to be in imconfig.h to make sure that they are ac cessible to all compilation units involved with Dear ImGui. // We usually require settings to be in imconfig.h to make sure that they are ac cessible to all compilation units involved with Dear ImGui.
bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, si ze_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx) bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, si ze_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx)
{ {
skipping to change at line 7491 skipping to change at line 7933
IM_ASSERT(g.Initialized); IM_ASSERT(g.Initialized);
IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!"); IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0) && "Need a positive DeltaTime!");
IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forg ot to call Render() or EndFrame() at the end of the previous frame?"); IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forg ot to call Render() or EndFrame() at the end of the previous frame?");
IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Inva lid DisplaySize value!"); IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Inva lid DisplaySize value!");
IM_ASSERT(g.IO.Fonts->IsBuilt() && "Font Atlas not built! Make sure you called ImGui_ImplXXXX_NewFrame() function for re nderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsA lpha8()"); IM_ASSERT(g.IO.Fonts->IsBuilt() && "Font Atlas not built! Make sure you called ImGui_ImplXXXX_NewFrame() function for re nderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsA lpha8()");
IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Inva lid style setting!"); IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Inva lid style setting!");
IM_ASSERT(g.Style.CircleTessellationMaxError > 0.0f && "Inva lid style setting!"); IM_ASSERT(g.Style.CircleTessellationMaxError > 0.0f && "Inva lid style setting!");
IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Inva lid style setting!"); // Allows us to avoid a few clamps in color computations IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Inva lid style setting!"); // Allows us to avoid a few clamps in color computations
IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting."); IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting.");
IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.Windo wMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGu iDir_Right); IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.Windo wMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGu iDir_Right);
for (int n = 0; n < ImGuiKey_COUNT; n++) #ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.Key for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_COUNT; n++)
sDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.Key
for unmapped key)"); sDown) && "io.KeyMap[] contains an out of bound value (need to be 0..511, or -1
for unmapped key)");
// Check: required key mapping (we intentionally do NOT check all keys to no t pressure user into setting up everything, but Space is required and was only a dded in 1.60 WIP) // Check: required key mapping (we intentionally do NOT check all keys to no t pressure user into setting up everything, but Space is required and was only a dded in 1.60 WIP)
if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && g.IO.BackendU singLegacyKeyArrays == 1)
IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not ma pped, required for keyboard navigation."); IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not ma pped, required for keyboard navigation.");
#endif
// Check: the io.ConfigWindowsResizeFromEdges option requires backend to hon or mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accor dingly. // Check: the io.ConfigWindowsResizeFromEdges option requires backend to hon or mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accor dingly.
if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendF lags_HasMouseCursors)) if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendF lags_HasMouseCursors))
g.IO.ConfigWindowsResizeFromEdges = false; g.IO.ConfigWindowsResizeFromEdges = false;
} }
static void ImGui::ErrorCheckEndFrameSanityChecks() static void ImGui::ErrorCheckEndFrameSanityChecks()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
skipping to change at line 8747 skipping to change at line 9191
bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for perfor mance if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for perfor mance
{ {
g.NextWindowData.ClearFlags(); // We behave like Begin() and need to con sume those values g.NextWindowData.ClearFlags(); // We behave like Begin() and need to con sume those values
return false; return false;
} }
flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | I mGuiWindowFlags_NoSavedSettings; flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | I mGuiWindowFlags_NoSavedSettings;
return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags); ImGuiID id = g.CurrentWindow->GetID(str_id);
return BeginPopupEx(id, flags);
} }
// If 'p_open' is specified for a modal popup window, the popup will have a regu lar close button which will close the popup. // If 'p_open' is specified for a modal popup window, the popup will have a regu lar close button which will close the popup.
// Note that popup visibility status is owned by Dear ImGui (and manipulated wit h e.g. OpenPopup) so the actual value of *p_open is meaningless here. // Note that popup visibility status is owned by Dear ImGui (and manipulated wit h e.g. OpenPopup) so the actual value of *p_open is meaningless here.
bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla gs) bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla gs)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
const ImGuiID id = window->GetID(name); const ImGuiID id = window->GetID(name);
if (!IsPopupOpen(id, ImGuiPopupFlags_None)) if (!IsPopupOpen(id, ImGuiPopupFlags_None))
skipping to change at line 8826 skipping to change at line 9271
} }
// This is a helper to handle the simplest case of associating one named popup t o one given widget. // This is a helper to handle the simplest case of associating one named popup t o one given widget.
// - To create a popup associated to the last item, you generally want to pass a NULL value to str_id. // - To create a popup associated to the last item, you generally want to pass a NULL value to str_id.
// - To create a popup with a specific identifier, pass it in str_id. // - To create a popup with a specific identifier, pass it in str_id.
// - This is useful when using using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call. // - This is useful when using using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call.
// - This is useful when multiple code locations may want to manipulate/open the same popup, given an explicit id. // - This is useful when multiple code locations may want to manipulate/open the same popup, given an explicit id.
// - You may want to handle the whole on user side if you have specific needs (e .g. tweaking IsItemHovered() parameters). // - You may want to handle the whole on user side if you have specific needs (e .g. tweaking IsItemHovered() parameters).
// This is essentially the same as: // This is essentially the same as:
// id = str_id ? GetID(str_id) : GetItemID(); // id = str_id ? GetID(str_id) : GetItemID();
// OpenPopupOnItemClick(str_id); // OpenPopupOnItemClick(str_id, ImGuiPopupFlags_MouseButtonRight);
// return BeginPopup(id); // return BeginPopup(id);
// Which is essentially the same as: // Which is essentially the same as:
// id = str_id ? GetID(str_id) : GetItemID(); // id = str_id ? GetID(str_id) : GetItemID();
// if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right)) // if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
// OpenPopup(id); // OpenPopup(id);
// return BeginPopup(id); // return BeginPopup(id);
// The main difference being that this is tweaked to avoid computing the ID tw ice. // The main difference being that this is tweaked to avoid computing the ID tw ice.
bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flag s) bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flag s)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
skipping to change at line 8987 skipping to change at line 9432
float horizontal_overlap = g.Style.ItemInnerSpacing.x; // We want some o verlap to convey the relative depth of each menu (currently the amount of overla p is hard-coded to style.ItemSpacing.x). float horizontal_overlap = g.Style.ItemInnerSpacing.x; // We want some o verlap to convey the relative depth of each menu (currently the amount of overla p is hard-coded to style.ItemSpacing.x).
ImRect r_avoid; ImRect r_avoid;
if (parent_window->DC.MenuBarAppending) if (parent_window->DC.MenuBarAppending)
r_avoid = ImRect(-FLT_MAX, parent_window->ClipRect.Min.y, FLT_MAX, p arent_window->ClipRect.Max.y); // Avoid parent menu-bar. If we wanted multi-line menu-bar, we may instead want to have the calling window setup e.g. a NextWindo wData.PosConstraintAvoidRect field r_avoid = ImRect(-FLT_MAX, parent_window->ClipRect.Min.y, FLT_MAX, p arent_window->ClipRect.Max.y); // Avoid parent menu-bar. If we wanted multi-line menu-bar, we may instead want to have the calling window setup e.g. a NextWindo wData.PosConstraintAvoidRect field
else else
r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX , parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_win dow->ScrollbarSizes.x, FLT_MAX); r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX , parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_win dow->ScrollbarSizes.x, FLT_MAX);
return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->A utoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default); return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->A utoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default);
} }
if (window->Flags & ImGuiWindowFlags_Popup) if (window->Flags & ImGuiWindowFlags_Popup)
{ {
ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Po return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->A
s.x + 1, window->Pos.y + 1); utoPosLastDirection, r_outer, ImRect(window->Pos, window->Pos), ImGuiPopupPositi
return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->A onPolicy_Default); // Ideally we'd disable r_avoid here
utoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default);
} }
if (window->Flags & ImGuiWindowFlags_Tooltip) if (window->Flags & ImGuiWindowFlags_Tooltip)
{ {
// Position tooltip (always follows mouse) // Position tooltip (always follows mouse)
float sc = g.Style.MouseCursorScale; float sc = g.Style.MouseCursorScale;
ImVec2 ref_pos = NavCalcPreferredRefPos(); ImVec2 ref_pos = NavCalcPreferredRefPos();
ImRect r_avoid; ImRect r_avoid;
if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFla gs & ImGuiConfigFlags_NavEnableSetMousePos)) if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFla gs & ImGuiConfigFlags_NavEnableSetMousePos))
r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_ pos.y + 8); r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_ pos.y + 8);
else else
skipping to change at line 9497 skipping to change at line 9941
} }
} }
static ImVec2 ImGui::NavCalcPreferredRefPos() static ImVec2 ImGui::NavCalcPreferredRefPos()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.NavWindow; ImGuiWindow* window = g.NavWindow;
if (g.NavDisableHighlight || !g.NavDisableMouseHover || !window) if (g.NavDisableHighlight || !g.NavDisableMouseHover || !window)
{ {
// Mouse (we need a fallback in case the mouse becomes invalid after bei ng used) // Mouse (we need a fallback in case the mouse becomes invalid after bei ng used)
if (IsMousePosValid(&g.IO.MousePos)) // The +1.0f offset when stored by OpenPopupEx() allows reopening this o
return g.IO.MousePos; r another popup (same or another mouse button) while not moving the mouse, it is
return g.MouseLastValidPos; pretty standard.
// In theory we could move that +1.0f offset in OpenPopupEx()
ImVec2 p = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : g.MouseLast
ValidPos;
return ImVec2(p.x + 1.0f, p.y);
} }
else else
{ {
// When navigation is active and mouse is disabled, pick a position arou nd the bottom left of the currently navigated item // When navigation is active and mouse is disabled, pick a position arou nd the bottom left of the currently navigated item
// Take account of upcoming scrolling (maybe set mouse pos should be don e in EndFrame?) // Take account of upcoming scrolling (maybe set mouse pos should be don e in EndFrame?)
ImRect rect_rel = WindowRectRelToAbs(window, window->NavRectRel[g.NavLay er]); ImRect rect_rel = WindowRectRelToAbs(window, window->NavRectRel[g.NavLay er]);
if (window->LastFrameActive != g.FrameCount && (window->ScrollTarget.x ! = FLT_MAX || window->ScrollTarget.y != FLT_MAX)) if (window->LastFrameActive != g.FrameCount && (window->ScrollTarget.x ! = FLT_MAX || window->ScrollTarget.y != FLT_MAX))
{ {
ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window); ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);
rect_rel.Translate(window->Scroll - next_scroll); rect_rel.Translate(window->Scroll - next_scroll);
} }
ImVec2 pos = ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x * 4, r ect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.Get Height())); ImVec2 pos = ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x * 4, r ect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.Get Height()));
ImGuiViewport* viewport = GetMainViewport(); ImGuiViewport* viewport = GetMainViewport();
return ImFloor(ImClamp(pos, viewport->Pos, viewport->Pos + viewport->Siz e)); // ImFloor() is important because non-integer mouse position application in backend might be lossy and result in undesirable non-zero delta. return ImFloor(ImClamp(pos, viewport->Pos, viewport->Pos + viewport->Siz e)); // ImFloor() is important because non-integer mouse position application in backend might be lossy and result in undesirable non-zero delta.
} }
} }
const char* ImGui::GetNavInputName(ImGuiNavInput n)
{
static const char* names[] =
{
"Activate", "Cancel", "Input", "Menu", "DpadLeft", "DpadRight", "DpadUp"
, "DpadDown", "LStickLeft", "LStickRight", "LStickUp", "LStickDown",
"FocusPrev", "FocusNext", "TweakSlow", "TweakFast", "KeyLeft", "KeyRight
", "KeyUp", "KeyDown"
};
IM_ASSERT(IM_ARRAYSIZE(names) == ImGuiNavInput_COUNT);
IM_ASSERT(n >= 0 && n < ImGuiNavInput_COUNT);
return names[n];
}
float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode) float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (mode == ImGuiInputReadMode_Down) if (mode == ImGuiInputReadMode_Down)
return g.IO.NavInputs[n]; // Instant, read analo g input (0.0f..1.0f, as provided by user) return g.IO.NavInputs[n]; // Instant, read analo g input (0.0f..1.0f, as provided by user)
const float t = g.IO.NavInputsDownDuration[n]; const float t = g.IO.NavInputsDownDuration[n];
if (t < 0.0f && mode == ImGuiInputReadMode_Released) // Return 1.0f when ju st released, no repeat, ignore analog input. if (t < 0.0f && mode == ImGuiInputReadMode_Released) // Return 1.0f when ju st released, no repeat, ignore analog input.
return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f); return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f);
if (t < 0.0f) if (t < 0.0f)
skipping to change at line 9543 skipping to change at line 10000
return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyR epeatDelay * 1.25f, g.IO.KeyRepeatRate * 2.00f); return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyR epeatDelay * 1.25f, g.IO.KeyRepeatRate * 2.00f);
if (mode == ImGuiInputReadMode_RepeatFast) if (mode == ImGuiInputReadMode_RepeatFast)
return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyR epeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.30f); return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyR epeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.30f);
return 0.0f; return 0.0f;
} }
ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInput ReadMode mode, float slow_factor, float fast_factor) ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInput ReadMode mode, float slow_factor, float fast_factor)
{ {
ImVec2 delta(0.0f, 0.0f); ImVec2 delta(0.0f, 0.0f);
if (dir_sources & ImGuiNavDirSourceFlags_RawKeyboard) if (dir_sources & ImGuiNavDirSourceFlags_RawKeyboard)
delta += ImVec2((float)IsKeyDown(GetKeyIndex(ImGuiKey_RightArrow)) - (fl oat)IsKeyDown(GetKeyIndex(ImGuiKey_LeftArrow)), (float)IsKeyDown(GetKeyIndex(ImG uiKey_DownArrow)) - (float)IsKeyDown(GetKeyIndex(ImGuiKey_UpArrow))); delta += ImVec2((float)IsKeyDown(ImGuiKey_RightArrow) - (float)IsKeyDown (ImGuiKey_LeftArrow), (float)IsKeyDown(ImGuiKey_DownArrow) - (float)IsKeyDown(Im GuiKey_UpArrow));
if (dir_sources & ImGuiNavDirSourceFlags_Keyboard) if (dir_sources & ImGuiNavDirSourceFlags_Keyboard)
delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode) - Get NavInputAmount(ImGuiNavInput_KeyLeft_, mode), GetNavInputAmount(ImGuiNavInput_ KeyDown_, mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_, mode)); delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode) - Get NavInputAmount(ImGuiNavInput_KeyLeft_, mode), GetNavInputAmount(ImGuiNavInput_ KeyDown_, mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_, mode));
if (dir_sources & ImGuiNavDirSourceFlags_PadDPad) if (dir_sources & ImGuiNavDirSourceFlags_PadDPad)
delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode) - Get NavInputAmount(ImGuiNavInput_DpadLeft, mode), GetNavInputAmount(ImGuiNavInput_ DpadDown, mode) - GetNavInputAmount(ImGuiNavInput_DpadUp, mode)); delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode) - Get NavInputAmount(ImGuiNavInput_DpadLeft, mode), GetNavInputAmount(ImGuiNavInput_ DpadDown, mode) - GetNavInputAmount(ImGuiNavInput_DpadUp, mode));
if (dir_sources & ImGuiNavDirSourceFlags_PadLStick) if (dir_sources & ImGuiNavDirSourceFlags_PadLStick)
delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - Get NavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_ LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode)); delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - Get NavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_ LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode));
if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow)) if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow))
delta *= slow_factor; delta *= slow_factor;
if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast)) if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast))
delta *= fast_factor; delta *= fast_factor;
skipping to change at line 9565 skipping to change at line 10022
} }
static void ImGui::NavUpdate() static void ImGui::NavUpdate()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO; ImGuiIO& io = g.IO;
io.WantSetMousePos = false; io.WantSetMousePos = false;
//if (g.NavScoringDebugCount > 0) IMGUI_DEBUG_LOG("NavScoringDebugCount %d f or '%s' layer %d (Init:%d, Move:%d)\n", g.NavScoringDebugCount, g.NavWindow ? g. NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0 , g.NavMoveRequest); //if (g.NavScoringDebugCount > 0) IMGUI_DEBUG_LOG("NavScoringDebugCount %d f or '%s' layer %d (Init:%d, Move:%d)\n", g.NavScoringDebugCount, g.NavWindow ? g. NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0 , g.NavMoveRequest);
// Update Gamepad->Nav inputs mapping
// Set input source as Gamepad when buttons are pressed (as some features di ffers when used with Gamepad vs Keyboard) // Set input source as Gamepad when buttons are pressed (as some features di ffers when used with Gamepad vs Keyboard)
// (do it before we map Keyboard input!)
const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnabl
eKeyboard) != 0;
const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnable Gamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0; const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnable Gamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_Gamepad) if (nav_gamepad_active && g.IO.BackendUsingLegacyNavInputArray == false)
{ {
if (io.NavInputs[ImGuiNavInput_Activate] > 0.0f || io.NavInputs[ImGuiNav for (int n = 0; n < ImGuiNavInput_COUNT; n++)
Input_Input] > 0.0f || io.NavInputs[ImGuiNavInput_Cancel] > 0.0f || io.NavInputs IM_ASSERT(io.NavInputs[n] == 0.0f && "Backend needs to either only u
[ImGuiNavInput_Menu] > 0.0f se io.AddKeyEvent()/io.AddKeyAnalogEvent(), either only fill legacy io.NavInputs
|| io.NavInputs[ImGuiNavInput_DpadLeft] > 0.0f || io.NavInputs[ImGui []. Not both!");
NavInput_DpadRight] > 0.0f || io.NavInputs[ImGuiNavInput_DpadUp] > 0.0f || io.Na #define NAV_MAP_KEY(_KEY, _NAV_INPUT, _ACTIVATE_NAV) do { io.NavInputs[
vInputs[ImGuiNavInput_DpadDown] > 0.0f) _NAV_INPUT] = io.KeysData[_KEY - ImGuiKey_KeysData_OFFSET].AnalogValue; if (_ACT
g.NavInputSource = ImGuiInputSource_Gamepad; IVATE_NAV && io.NavInputs[_NAV_INPUT] > 0.0f) { g.NavInputSource = ImGuiInputSou
rce_Gamepad; } } while (0)
NAV_MAP_KEY(ImGuiKey_GamepadFaceDown, ImGuiNavInput_Activate, true);
NAV_MAP_KEY(ImGuiKey_GamepadFaceRight, ImGuiNavInput_Cancel, true);
NAV_MAP_KEY(ImGuiKey_GamepadFaceLeft, ImGuiNavInput_Menu, true);
NAV_MAP_KEY(ImGuiKey_GamepadFaceUp, ImGuiNavInput_Input, true);
NAV_MAP_KEY(ImGuiKey_GamepadDpadLeft, ImGuiNavInput_DpadLeft, true);
NAV_MAP_KEY(ImGuiKey_GamepadDpadRight, ImGuiNavInput_DpadRight, true);
NAV_MAP_KEY(ImGuiKey_GamepadDpadUp, ImGuiNavInput_DpadUp, true);
NAV_MAP_KEY(ImGuiKey_GamepadDpadDown, ImGuiNavInput_DpadDown, true);
NAV_MAP_KEY(ImGuiKey_GamepadL1, ImGuiNavInput_FocusPrev, false);
NAV_MAP_KEY(ImGuiKey_GamepadR1, ImGuiNavInput_FocusNext, false);
NAV_MAP_KEY(ImGuiKey_GamepadL1, ImGuiNavInput_TweakSlow, false);
NAV_MAP_KEY(ImGuiKey_GamepadR1, ImGuiNavInput_TweakFast, false);
NAV_MAP_KEY(ImGuiKey_GamepadLStickLeft, ImGuiNavInput_LStickLeft, false)
;
NAV_MAP_KEY(ImGuiKey_GamepadLStickRight, ImGuiNavInput_LStickRight, fals
e);
NAV_MAP_KEY(ImGuiKey_GamepadLStickUp, ImGuiNavInput_LStickUp, false);
NAV_MAP_KEY(ImGuiKey_GamepadLStickDown, ImGuiNavInput_LStickDown, false)
;
#undef NAV_MAP_KEY
} }
// Update Keyboard->Nav inputs mapping // Update Keyboard->Nav inputs mapping
const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnabl eKeyboard) != 0;
if (nav_keyboard_active) if (nav_keyboard_active)
{ {
#define NAV_MAP_KEY(_KEY, _NAV_INPUT) do { if (IsKeyDown(io.KeyMap[_KEY ])) { io.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_Keybo ard; } } while (0) #define NAV_MAP_KEY(_KEY, _NAV_INPUT) do { if (IsKeyDown(_KEY)) { io.Na vInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_Keyboard; } } wh ile (0)
NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate ); NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate );
NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input ); NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input );
NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel ); NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel );
NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ ); NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ );
NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_); NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_);
NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ ); NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ );
NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ ); NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ );
if (io.KeyCtrl) if (io.KeyCtrl)
io.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f; io.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
if (io.KeyShift) if (io.KeyShift)
skipping to change at line 9797 skipping to change at line 10271
if (window && g.NavMoveDir == ImGuiDir_None && nav_keyboard_active) if (window && g.NavMoveDir == ImGuiDir_None && nav_keyboard_active)
scoring_rect_offset_y = NavUpdatePageUpPageDown(); scoring_rect_offset_y = NavUpdatePageUpPageDown();
if (scoring_rect_offset_y != 0.0f) if (scoring_rect_offset_y != 0.0f)
{ {
g.NavScoringNoClipRect = window->InnerRect; g.NavScoringNoClipRect = window->InnerRect;
g.NavScoringNoClipRect.TranslateY(scoring_rect_offset_y); g.NavScoringNoClipRect.TranslateY(scoring_rect_offset_y);
} }
// [DEBUG] Always send a request // [DEBUG] Always send a request
#if IMGUI_DEBUG_NAV_SCORING #if IMGUI_DEBUG_NAV_SCORING
if (io.KeyCtrl && IsKeyPressedMap(ImGuiKey_C)) if (io.KeyCtrl && IsKeyPressed(ImGuiKey_C))
g.NavMoveDirForDebug = (ImGuiDir)((g.NavMoveDirForDebug + 1) & 3); g.NavMoveDirForDebug = (ImGuiDir)((g.NavMoveDirForDebug + 1) & 3);
if (io.KeyCtrl && g.NavMoveDir == ImGuiDir_None) if (io.KeyCtrl && g.NavMoveDir == ImGuiDir_None)
{ {
g.NavMoveDir = g.NavMoveDirForDebug; g.NavMoveDir = g.NavMoveDirForDebug;
g.NavMoveFlags |= ImGuiNavMoveFlags_DebugNoResult; g.NavMoveFlags |= ImGuiNavMoveFlags_DebugNoResult;
} }
#endif #endif
// Submit // Submit
g.NavMoveForwardToNextFrame = false; g.NavMoveForwardToNextFrame = false;
skipping to change at line 9823 skipping to change at line 10297
{ {
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", lay er=%d\n", g.NavWindow->Name, g.NavLayer); IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", lay er=%d\n", g.NavWindow->Name, g.NavLayer);
g.NavInitRequest = g.NavInitRequestFromMove = true; g.NavInitRequest = g.NavInitRequestFromMove = true;
g.NavInitResultId = 0; g.NavInitResultId = 0;
g.NavDisableHighlight = false; g.NavDisableHighlight = false;
} }
// When using gamepad, we project the reference nav bounding box into window visible area. // When using gamepad, we project the reference nav bounding box into window visible area.
// This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative // This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative
// (can't focus a visible object like we can with the mouse). // (can't focus a visible object like we can with the mouse).
if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g. NavLayer == ImGuiNavLayer_Main && window != NULL) if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g. NavLayer == ImGuiNavLayer_Main && window != NULL)// && (g.NavMoveFlags & ImGuiNa vMoveFlags_Forwarded))
{ {
ImRect window_rect_rel = WindowRectAbsToRel(window, ImRect(window->Inner bool clamp_x = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopX | ImGuiNavMove
Rect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1))); Flags_WrapX)) == 0;
if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer])) bool clamp_y = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopY | ImGuiNavMove
{ Flags_WrapY)) == 0;
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel\n"); ImRect inner_rect_rel = WindowRectAbsToRel(window, ImRect(window->InnerR
float pad = window->CalcFontSize() * 0.5f; ect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)));
window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad if ((clamp_x || clamp_y) && !inner_rect_rel.Contains(window->NavRectRel[
), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the g.NavLayer]))
intent of starting navigation from first fully visible item {
window->NavRectRel[g.NavLayer].ClipWithFull(window_rect_rel); IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel for game
pad move\n");
float pad_x = ImMin(inner_rect_rel.GetWidth(), window->CalcFontSize(
) * 0.5f);
float pad_y = ImMin(inner_rect_rel.GetHeight(), window->CalcFontSize
() * 0.5f); // Terrible approximation for the intent of starting navigation from
first fully visible item
inner_rect_rel.Min.x = clamp_x ? (inner_rect_rel.Min.x + pad_x) : -F
LT_MAX;
inner_rect_rel.Max.x = clamp_x ? (inner_rect_rel.Max.x - pad_x) : +F
LT_MAX;
inner_rect_rel.Min.y = clamp_y ? (inner_rect_rel.Min.y + pad_y) : -F
LT_MAX;
inner_rect_rel.Max.y = clamp_y ? (inner_rect_rel.Max.y - pad_y) : +F
LT_MAX;
window->NavRectRel[g.NavLayer].ClipWithFull(inner_rect_rel);
g.NavId = g.NavFocusScopeId = 0; g.NavId = g.NavFocusScopeId = 0;
} }
} }
// For scoring we use a single segment on the left side our current item bou nding box (not touching the edge to avoid box overlap with zero-spaced items) // For scoring we use a single segment on the left side our current item bou nding box (not touching the edge to avoid box overlap with zero-spaced items)
ImRect scoring_rect; ImRect scoring_rect;
if (window != NULL) if (window != NULL)
{ {
ImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? win dow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0); ImRect nav_rect_rel = !window->NavRectRel[g.NavLayer].IsInverted() ? win dow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
scoring_rect = WindowRectRelToAbs(window, nav_rect_rel); scoring_rect = WindowRectRelToAbs(window, nav_rect_rel);
skipping to change at line 9861 skipping to change at line 10341
} }
void ImGui::NavUpdateCreateTabbingRequest() void ImGui::NavUpdateCreateTabbingRequest()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.NavWindow; ImGuiWindow* window = g.NavWindow;
IM_ASSERT(g.NavMoveDir == ImGuiDir_None); IM_ASSERT(g.NavMoveDir == ImGuiDir_None);
if (window == NULL || g.NavWindowingTarget != NULL || (window->Flags & ImGui WindowFlags_NoNavInputs)) if (window == NULL || g.NavWindowingTarget != NULL || (window->Flags & ImGui WindowFlags_NoNavInputs))
return; return;
const bool tab_pressed = IsKeyPressedMap(ImGuiKey_Tab, true) && !IsActiveIdU singKey(ImGuiKey_Tab) && !g.IO.KeyCtrl && !g.IO.KeyAlt; const bool tab_pressed = IsKeyPressed(ImGuiKey_Tab, true) && !IsActiveIdUsin gKey(ImGuiKey_Tab) && !g.IO.KeyCtrl && !g.IO.KeyAlt;
if (!tab_pressed) if (!tab_pressed)
return; return;
// Initiate tabbing request // Initiate tabbing request
// (this is ALWAYS ENABLED, regardless of ImGuiConfigFlags_NavEnableKeyboard flag!) // (this is ALWAYS ENABLED, regardless of ImGuiConfigFlags_NavEnableKeyboard flag!)
// Initially this was designed to use counters and modulo arithmetic, but th at could not work with unsubmitted items (list clipper). Instead we use a strate gy close to other move requests. // Initially this was designed to use counters and modulo arithmetic, but th at could not work with unsubmitted items (list clipper). Instead we use a strate gy close to other move requests.
// See NavProcessItemForTabbingRequest() for a description of the various fo rward/backward tabbing cases with and without wrapping. // See NavProcessItemForTabbingRequest() for a description of the various fo rward/backward tabbing cases with and without wrapping.
//// FIXME: We use (g.ActiveId == 0) but (g.NavDisableHighlight == false) mi ght be righter once we can tab through anything //// FIXME: We use (g.ActiveId == 0) but (g.NavDisableHighlight == false) mi ght be righter once we can tab through anything
g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.ActiveId == 0) ? 0 : +1; g.NavTabbingDir = g.IO.KeyShift ? -1 : (g.ActiveId == 0) ? 0 : +1;
ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVis ibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY; ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVis ibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY;
skipping to change at line 10022 skipping to change at line 10502
} }
} }
// Handle PageUp/PageDown/Home/End keys // Handle PageUp/PageDown/Home/End keys
// Called from NavUpdateCreateMoveRequest() which will use our output to create a move request // Called from NavUpdateCreateMoveRequest() which will use our output to create a move request
// FIXME-NAV: This doesn't work properly with NavFlattened siblings as we use Na vWindow rectangle for reference // FIXME-NAV: This doesn't work properly with NavFlattened siblings as we use Na vWindow rectangle for reference
// FIXME-NAV: how to get Home/End to aim at the beginning/end of a 2D grid? // FIXME-NAV: how to get Home/End to aim at the beginning/end of a 2D grid?
static float ImGui::NavUpdatePageUpPageDown() static float ImGui::NavUpdatePageUpPageDown()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO;
ImGuiWindow* window = g.NavWindow; ImGuiWindow* window = g.NavWindow;
if ((window->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget ! = NULL) if ((window->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget ! = NULL)
return 0.0f; return 0.0f;
const bool page_up_held = IsKeyDown(io.KeyMap[ImGuiKey_PageUp]) && !IsActive const bool page_up_held = IsKeyDown(ImGuiKey_PageUp) && !IsActiveIdUsingKey(
IdUsingKey(ImGuiKey_PageUp); ImGuiKey_PageUp);
const bool page_down_held = IsKeyDown(io.KeyMap[ImGuiKey_PageDown]) && !IsAc const bool page_down_held = IsKeyDown(ImGuiKey_PageDown) && !IsActiveIdUsing
tiveIdUsingKey(ImGuiKey_PageDown); Key(ImGuiKey_PageDown);
const bool home_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_Home]) && !IsActiv const bool home_pressed = IsKeyPressed(ImGuiKey_Home) && !IsActiveIdUsingKey
eIdUsingKey(ImGuiKey_Home); (ImGuiKey_Home);
const bool end_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_End]) && !IsActiveI const bool end_pressed = IsKeyPressed(ImGuiKey_End) && !IsActiveIdUsingKey(I
dUsingKey(ImGuiKey_End); mGuiKey_End);
if (page_up_held == page_down_held && home_pressed == end_pressed) // Procee d if either (not both) are pressed, otherwise early out if (page_up_held == page_down_held && home_pressed == end_pressed) // Procee d if either (not both) are pressed, otherwise early out
return 0.0f; return 0.0f;
if (g.NavLayer != ImGuiNavLayer_Main) if (g.NavLayer != ImGuiNavLayer_Main)
NavRestoreLayer(ImGuiNavLayer_Main); NavRestoreLayer(ImGuiNavLayer_Main);
if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll) if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll)
{ {
// Fallback manual-scroll when window has no navigable item // Fallback manual-scroll when window has no navigable item
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true)) if (IsKeyPressed(ImGuiKey_PageUp, true))
SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight()) ; SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight()) ;
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true)) else if (IsKeyPressed(ImGuiKey_PageDown, true))
SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight()) ; SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight()) ;
else if (home_pressed) else if (home_pressed)
SetScrollY(window, 0.0f); SetScrollY(window, 0.0f);
else if (end_pressed) else if (end_pressed)
SetScrollY(window, window->ScrollMax.y); SetScrollY(window, window->ScrollMax.y);
} }
else else
{ {
ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer]; ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight()); const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
float nav_scoring_rect_offset_y = 0.0f; float nav_scoring_rect_offset_y = 0.0f;
if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true)) if (IsKeyPressed(ImGuiKey_PageUp, true))
{ {
nav_scoring_rect_offset_y = -page_offset_y; nav_scoring_rect_offset_y = -page_offset_y;
g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item) g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item)
g.NavMoveClipDir = ImGuiDir_Up; g.NavMoveClipDir = ImGuiDir_Up;
g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveF lags_AlsoScoreVisibleSet; g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveF lags_AlsoScoreVisibleSet;
} }
else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true)) else if (IsKeyPressed(ImGuiKey_PageDown, true))
{ {
nav_scoring_rect_offset_y = +page_offset_y; nav_scoring_rect_offset_y = +page_offset_y;
g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset do wn, we request the up direction (so we can always land on the last item) g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset do wn, we request the up direction (so we can always land on the last item)
g.NavMoveClipDir = ImGuiDir_Down; g.NavMoveClipDir = ImGuiDir_Down;
g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveF lags_AlsoScoreVisibleSet; g.NavMoveFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveF lags_AlsoScoreVisibleSet;
} }
else if (home_pressed) else if (home_pressed)
{ {
// FIXME-NAV: handling of Home/End is assuming that the top/bottom m ost item will be visible with Scroll.y == 0/ScrollMax.y // FIXME-NAV: handling of Home/End is assuming that the top/bottom m ost item will be visible with Scroll.y == 0/ScrollMax.y
// Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdgeY flag, we don't scroll immediately to avoid scrolling happening before nav resul t. // Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdgeY flag, we don't scroll immediately to avoid scrolling happening before nav resul t.
skipping to change at line 10227 skipping to change at line 10705
// Fade out // Fade out
if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL) if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL)
{ {
g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - io.D eltaTime * 10.0f, 0.0f); g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - io.D eltaTime * 10.0f, 0.0f);
if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f) if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
g.NavWindowingTargetAnim = NULL; g.NavWindowingTargetAnim = NULL;
} }
// Start CTRL+Tab or Square+L/R window selection // Start CTRL+Tab or Square+L/R window selection
const bool start_windowing_with_gamepad = allow_windowing && !g.NavWindowing Target && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed); const bool start_windowing_with_gamepad = allow_windowing && !g.NavWindowing Target && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed);
const bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowin gTarget && io.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab); const bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowin gTarget && io.KeyCtrl && IsKeyPressed(ImGuiKey_Tab);
if (start_windowing_with_gamepad || start_windowing_with_keyboard) if (start_windowing_with_gamepad || start_windowing_with_keyboard)
if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocus able(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1)) if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocus able(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))
{ {
g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow ; g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow ;
g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f; g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f;
g.NavWindowingToggleLayer = start_windowing_with_gamepad ? true : fa lse; // Gamepad starts toggling layer g.NavWindowingToggleLayer = start_windowing_with_gamepad ? true : fa lse; // Gamepad starts toggling layer
g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_ Keyboard : ImGuiInputSource_Gamepad; g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_ Keyboard : ImGuiInputSource_Gamepad;
} }
// Gamepad update // Gamepad update
skipping to change at line 10269 skipping to change at line 10747
apply_focus_window = g.NavWindowingTarget; apply_focus_window = g.NavWindowingTarget;
g.NavWindowingTarget = NULL; g.NavWindowingTarget = NULL;
} }
} }
// Keyboard: Focus // Keyboard: Focus
if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Keyboard) if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Keyboard)
{ {
// Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise
g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSat urate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSat urate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f
if (IsKeyPressedMap(ImGuiKey_Tab, true)) if (IsKeyPressed(ImGuiKey_Tab, true))
NavUpdateWindowingHighlightWindow(io.KeyShift ? +1 : -1); NavUpdateWindowingHighlightWindow(io.KeyShift ? +1 : -1);
if (!io.KeyCtrl) if (!io.KeyCtrl)
apply_focus_window = g.NavWindowingTarget; apply_focus_window = g.NavWindowingTarget;
} }
// Keyboard: Press and Release ALT to toggle menu layer // Keyboard: Press and Release ALT to toggle menu layer
// - Testing that only Alt is tested prevents Alt+Shift or AltGR from toggli ng menu layer. // - Testing that only Alt is tested prevents Alt+Shift or AltGR from toggli ng menu layer.
// - AltGR is normally Alt+Ctrl but we can't reliably detect it (not all bac kends/systems/layout emit it as Alt+Ctrl). But even on keyboards without AltGR w e don't want Alt+Ctrl to open menu anyway. // - AltGR is normally Alt+Ctrl but we can't reliably detect it (not all bac kends/systems/layout emit it as Alt+Ctrl). But even on keyboards without AltGR w e don't want Alt+Ctrl to open menu anyway.
const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEn ableKeyboard) != 0; const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEn ableKeyboard) != 0;
if (nav_keyboard_active && io.KeyMods == ImGuiKeyModFlags_Alt && (io.KeyMods Prev & ImGuiKeyModFlags_Alt) == 0) if (nav_keyboard_active && io.KeyMods == ImGuiKeyModFlags_Alt && (io.KeyMods Prev & ImGuiKeyModFlags_Alt) == 0)
skipping to change at line 10610 skipping to change at line 11088
memcpy(payload.Data, data, data_size); memcpy(payload.Data, data, data_size);
} }
else else
{ {
payload.Data = NULL; payload.Data = NULL;
} }
payload.DataSize = (int)data_size; payload.DataSize = (int)data_size;
} }
payload.DataFrameCount = g.FrameCount; payload.DataFrameCount = g.FrameCount;
// Return whether the payload has been accepted
return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFram eCount == g.FrameCount - 1); return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFram eCount == g.FrameCount - 1);
} }
bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id) bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (!g.DragDropActive) if (!g.DragDropActive)
return false; return false;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
skipping to change at line 11463 skipping to change at line 11942
#endif #endif
// Win32 API IME support (for Asian languages, etc.) // Win32 API IME support (for Asian languages, etc.)
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI _DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI _DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
#include <imm.h> #include <imm.h>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma comment(lib, "imm32") #pragma comment(lib, "imm32")
#endif #endif
static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y) static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatf ormImeData* data)
{ {
// Notify OS Input Method Editor of text input position // Notify OS Input Method Editor of text input position
ImGuiIO& io = ImGui::GetIO(); HWND hwnd = (HWND)viewport->PlatformHandleRaw;
if (HWND hwnd = (HWND)io.ImeWindowHandle) #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
if (HIMC himc = ::ImmGetContext(hwnd)) if (hwnd == 0)
{ hwnd = (HWND)ImGui::GetIO().ImeWindowHandle;
COMPOSITIONFORM cf; #endif
cf.ptCurrentPos.x = x; if (hwnd == 0)
cf.ptCurrentPos.y = y; return;
cf.dwStyle = CFS_FORCE_POSITION;
::ImmSetCompositionWindow(himc, &cf); ::ImmAssociateContextEx(hwnd, NULL, data->WantVisible ? IACE_DEFAULT : 0);
::ImmReleaseContext(hwnd, himc);
} if (HIMC himc = ::ImmGetContext(hwnd))
{
COMPOSITIONFORM composition_form = {};
composition_form.ptCurrentPos.x = (LONG)data->InputPos.x;
composition_form.ptCurrentPos.y = (LONG)data->InputPos.y;
composition_form.dwStyle = CFS_FORCE_POSITION;
::ImmSetCompositionWindow(himc, &composition_form);
CANDIDATEFORM candidate_form = {};
candidate_form.dwStyle = CFS_CANDIDATEPOS;
candidate_form.ptCurrentPos.x = (LONG)data->InputPos.x;
candidate_form.ptCurrentPos.y = (LONG)data->InputPos.y;
::ImmSetCandidateWindow(himc, &candidate_form);
::ImmReleaseContext(hwnd, himc);
}
} }
#else #else
static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {} static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport*, ImGuiPlatformImeDat a*) {}
#endif #endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// [SECTION] METRICS/DEBUGGER WINDOW // [SECTION] METRICS/DEBUGGER WINDOW
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// - RenderViewportThumbnail() [Internal] // - RenderViewportThumbnail() [Internal]
// - RenderViewportsThumbnails() [Internal] // - RenderViewportsThumbnails() [Internal]
// - MetricsHelpMarker() [Internal] // - MetricsHelpMarker() [Internal]
// - ShowMetricsWindow() // - ShowMetricsWindow()
skipping to change at line 11877 skipping to change at line 12369
{ {
InputTextMultiline("##Ini", (char*)(void*)g.SettingsIniData.c_str(), g.SettingsIniData.Buf.Size, ImVec2(-FLT_MIN, GetTextLineHeight() * 20), ImGuiIn putTextFlags_ReadOnly); InputTextMultiline("##Ini", (char*)(void*)g.SettingsIniData.c_str(), g.SettingsIniData.Buf.Size, ImVec2(-FLT_MIN, GetTextLineHeight() * 20), ImGuiIn putTextFlags_ReadOnly);
TreePop(); TreePop();
} }
TreePop(); TreePop();
} }
// Misc Details // Misc Details
if (TreeNode("Internal state")) if (TreeNode("Internal state"))
{ {
const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamep
ad", "Nav", "Clipboard" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiIn
putSource_COUNT);
Text("WINDOWING"); Text("WINDOWING");
Indent(); Indent();
Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "N ULL"); Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "N ULL");
Text("HoveredWindow->Root: '%s'", g.HoveredWindow ? g.HoveredWindow->Roo tWindow->Name : "NULL"); Text("HoveredWindow->Root: '%s'", g.HoveredWindow ? g.HoveredWindow->Roo tWindow->Name : "NULL");
Text("HoveredWindowUnderMovingWindow: '%s'", g.HoveredWindowUnderMovingW indow ? g.HoveredWindowUnderMovingWindow->Name : "NULL"); Text("HoveredWindowUnderMovingWindow: '%s'", g.HoveredWindowUnderMovingW indow ? g.HoveredWindowUnderMovingWindow->Name : "NULL");
Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL "); Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL ");
Unindent(); Unindent();
Text("ITEMS"); Text("ITEMS");
Indent(); Indent();
Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, i nput_source_names[g.ActiveIdSource]); Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, G etInputSourceName(g.ActiveIdSource));
Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL"); Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
Text("ActiveIdUsing: Wheel: %d, NavDirMask: %X, NavInputMask: %X, KeyInp
utMask: %llX", g.ActiveIdUsingMouseWheel, g.ActiveIdUsingNavDirMask, g.ActiveIdU int active_id_using_key_input_count = 0;
singNavInputMask, g.ActiveIdUsingKeyInputMask); for (int n = 0; n < ImGuiKey_NamedKey_COUNT; n++)
active_id_using_key_input_count += g.ActiveIdUsingKeyInputMask[n] ?
1 : 0;
Text("ActiveIdUsing: Wheel: %d, NavDirMask: %X, NavInputMask: %X, KeyInp
utMask: %d key(s)", g.ActiveIdUsingMouseWheel, g.ActiveIdUsingNavDirMask, g.Acti
veIdUsingNavInputMask, active_id_using_key_input_count);
Text("HoveredId: 0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredIdPrevio usFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Not displaying g.Hovered Id as it is update mid-frame Text("HoveredId: 0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredIdPrevio usFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Not displaying g.Hovered Id as it is update mid-frame
Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.Dra gDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropP ayload.DataSize); Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.Dra gDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropP ayload.DataSize);
Unindent(); Unindent();
Text("NAV,FOCUS"); Text("NAV,FOCUS");
Indent(); Indent();
Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL"); Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL");
Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer); Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer);
Text("NavInputSource: %s", input_source_names[g.NavInputSource]); Text("NavInputSource: %s", GetInputSourceName(g.NavInputSource));
Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible); Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible);
Text("NavActivateId/DownId/PressedId/InputId: %08X/%08X/%08X/%08X", g.Na vActivateId, g.NavActivateDownId, g.NavActivatePressedId, g.NavActivateInputId); Text("NavActivateId/DownId/PressedId/InputId: %08X/%08X/%08X/%08X", g.Na vActivateId, g.NavActivateDownId, g.NavActivatePressedId, g.NavActivateInputId);
Text("NavActivateFlags: %04X", g.NavActivateFlags); Text("NavActivateFlags: %04X", g.NavActivateFlags);
Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHi ghlight, g.NavDisableMouseHover); Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHi ghlight, g.NavDisableMouseHover);
Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId); Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId);
Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTa rget->Name : "NULL"); Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTa rget->Name : "NULL");
Unindent(); Unindent();
TreePop(); TreePop();
} }
skipping to change at line 12409 skipping to change at line 12903
// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visu ally select an item and break into its call-stack. // [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visu ally select an item and break into its call-stack.
void ImGui::UpdateDebugToolItemPicker() void ImGui::UpdateDebugToolItemPicker()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.DebugItemPickerBreakId = 0; g.DebugItemPickerBreakId = 0;
if (!g.DebugItemPickerActive) if (!g.DebugItemPickerActive)
return; return;
const ImGuiID hovered_id = g.HoveredIdPreviousFrame; const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
SetMouseCursor(ImGuiMouseCursor_Hand); SetMouseCursor(ImGuiMouseCursor_Hand);
if (IsKeyPressedMap(ImGuiKey_Escape)) if (IsKeyPressed(ImGuiKey_Escape))
g.DebugItemPickerActive = false; g.DebugItemPickerActive = false;
if (IsMouseClicked(0) && hovered_id) if (IsMouseClicked(0) && hovered_id)
{ {
g.DebugItemPickerBreakId = hovered_id; g.DebugItemPickerBreakId = hovered_id;
g.DebugItemPickerActive = false; g.DebugItemPickerActive = false;
} }
SetNextWindowBgAlpha(0.60f); SetNextWindowBgAlpha(0.60f);
BeginTooltip(); BeginTooltip();
Text("HoveredId: 0x%08X", hovered_id); Text("HoveredId: 0x%08X", hovered_id);
Text("Press ESC to abort picking."); Text("Press ESC to abort picking.");
 End of changes. 107 change blocks. 
481 lines changed or deleted 1094 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)