Merge branch 'master' into docking

# Conflicts:
#	examples/imgui_impl_opengl3.cpp
#	imgui.cpp
#	imgui_draw.cpp
#	imgui_internal.h
This commit is contained in:
omar
2019-09-17 16:35:50 +02:00
20 changed files with 338 additions and 246 deletions

262
imgui.cpp
View File

@ -373,12 +373,12 @@ CODE
(Docking/Viewport Branch)
- 2019/XX/XX (1.XX) - when multi-viewports are enabled, all positions will be in your natural OS coordinates space. It means that:
- reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are probably not what you want anymore.
- reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are probably not what you want anymore.
you may use GetMainViewport()->Pos to offset hard-coded positions, e.g. SetNextWindowPos(GetMainViewport()->Pos)
- likewise io.MousePos and GetMousePos() will use OS coordinates.
- likewise io.MousePos and GetMousePos() will use OS coordinates.
If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos.
- 2019/XX/XX (1.XX) - Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api.
- 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete).
- 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete).
@ -586,17 +586,17 @@ CODE
Q: Where is the documentation?
A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
- Run the examples/ and explore them.
- See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
- The demo covers most features of Dear ImGui, so you can read the code and see its output.
- See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
- The demo covers most features of Dear ImGui, so you can read the code and see its output.
- See documentation and comments at the top of imgui.cpp + effectively imgui.h.
- Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/
- Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/
folder to explain how to integrate Dear ImGui with your own engine/application.
- Your programming IDE is your friend, find the type or function declaration to find comments
- Your programming IDE is your friend, find the type or function declaration to find comments
associated to it.
Q: Which version should I get?
A: I occasionally tag Releases (https://github.com/ocornut/imgui/releases) but it is generally safe
and recommended to sync to master/latest. The library is fairly stable and regressions tend to be
A: I occasionally tag Releases (https://github.com/ocornut/imgui/releases) but it is generally safe
and recommended to sync to master/latest. The library is fairly stable and regressions tend to be
fixed fast when reported. You may also peak at the 'docking' branch which includes:
- Docking/Merging features (https://github.com/ocornut/imgui/issues/2109)
- Multi-viewport features (https://github.com/ocornut/imgui/issues/1542)
@ -608,11 +608,11 @@ CODE
for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
Q: Why the odd dual naming, "Dear ImGui" vs "ImGui"?
A: The library started its life as "ImGui" due to the fact that I didn't give it a proper name when
when I released 1.0, and had no particular expectation that it would take off. However, the term IMGUI
(immediate-mode graphical user interface) was coined before and is being used in variety of other
situations (e.g. Unity uses it own implementation of the IMGUI paradigm).
To reduce the ambiguity without affecting existing code bases, I have decided on an alternate,
A: The library started its life as "ImGui" due to the fact that I didn't give it a proper name when
when I released 1.0, and had no particular expectation that it would take off. However, the term IMGUI
(immediate-mode graphical user interface) was coined before and is being used in variety of other
situations (e.g. Unity uses it own implementation of the IMGUI paradigm).
To reduce the ambiguity without affecting existing code bases, I have decided on an alternate,
longer name "Dear ImGui" that people can use to refer to this specific library.
Please try to refer to this library as "Dear ImGui".
@ -1090,7 +1090,7 @@ static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2&
// Navigation
static void NavUpdate();
static void NavUpdateWindowing();
static void NavUpdateWindowingList();
static void NavUpdateWindowingOverlay();
static void NavUpdateMoveResult();
static float NavUpdatePageUpPageDown(int allowed_dir_flags);
static inline void NavUpdateAnyRequestFlag();
@ -2532,14 +2532,18 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons
// Another overly complex function until we reorganize everything into a nice all-in-one helper.
// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display.
// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move.
void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known)
// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move.
void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known)
{
ImGuiContext& g = *GImGui;
if (text_end_full == NULL)
text_end_full = FindRenderedTextEnd(text);
const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f);
//draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255));
//draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y-2), ImVec2(ellipsis_max_x, pos_max.y+2), IM_COL32(0, 255, 0, 255));
//draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255));
// FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels.
if (text_size.x > pos_max.x - pos_min.x)
{
// Hello wo...
@ -2547,15 +2551,33 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min,
// min max ellipsis_max
// <-> this is generally some padding value
// FIXME-STYLE: RenderPixelEllipsis() style should use actual font data.
const ImFont* font = draw_list->_Data->Font;
const float font_size = draw_list->_Data->FontSize;
const int ellipsis_dot_count = 3;
const float ellipsis_width = (1.0f + 1.0f) * ellipsis_dot_count - 1.0f;
const char* text_end_ellipsis = NULL;
float text_width = ImMax((pos_max.x - ellipsis_width) - pos_min.x, 1.0f);
float text_size_clipped_x = font->CalcTextSizeA(font_size, text_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
ImWchar ellipsis_char = font->EllipsisChar;
int ellipsis_char_count = 1;
if (ellipsis_char == (ImWchar)-1)
{
ellipsis_char = (ImWchar)'.';
ellipsis_char_count = 3;
}
const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char);
float ellipsis_glyph_width = glyph->X1; // Width of the glyph with no padding on either side
float ellipsis_total_width = ellipsis_glyph_width; // Full width of entire ellipsis
if (ellipsis_char_count > 1)
{
// Full ellipsis size without free spacing after it.
const float spacing_between_dots = 1.0f * (draw_list->_Data->FontSize / font->FontSize);
ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots;
ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots;
}
// We can now claim the space between pos_max.x and ellipsis_max.x
const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f);
float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
if (text == text_end_ellipsis && text_end_ellipsis < text_end_full)
{
// Always display at least 1 character if there's no room for character + ellipsis
@ -2564,15 +2586,20 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min,
}
while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1]))
{
// Trim trailing space before ellipsis
// Trim trailing space before ellipsis (FIXME: Supporting non-ascii blanks would be nice, for this we need a function to backtrack in UTF-8 text)
text_end_ellipsis--;
text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte
}
RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
const float ellipsis_x = pos_min.x + text_size_clipped_x + 1.0f;
if (ellipsis_x + ellipsis_width - 1.0f <= ellipsis_max_x)
RenderPixelEllipsis(draw_list, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_dot_count);
// Render text, render ellipsis
RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
float ellipsis_x = pos_min.x + text_size_clipped_x;
if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x)
for (int i = 0; i < ellipsis_char_count; i++)
{
font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char);
ellipsis_x += ellipsis_glyph_width;
}
}
else
{
@ -3059,8 +3086,8 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
{
// Navigation processing runs prior to clipping early-out
// (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
// (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
// unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
// (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
// unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
// thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
// We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able
// to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
@ -3505,7 +3532,7 @@ void ImGui::UpdateMouseMovingWindowNewFrame()
}
else
{
// Try to merge the window back into the main viewport.
// Try to merge the window back into the main viewport.
// This works because MouseViewport should be != MovingWindow->Viewport on release (as per code in UpdateViewports)
if (g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable)
UpdateTryMergeWindowIntoHostViewport(moving_window, g.MouseViewport);
@ -3830,7 +3857,7 @@ static void NewFrameSanityChecks()
IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!");
IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting. Alpha cannot be negative (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.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right);
IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right);
for (int n = 0; n < ImGuiKey_COUNT; n++)
IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)");
@ -4291,7 +4318,7 @@ static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* d
return;
}
// Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
// Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
// 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->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
@ -4300,7 +4327,7 @@ static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* d
// Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
// If this assert triggers because you are drawing lots of stuff manually:
// - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds.
// - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds.
// Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics window to inspect draw list contents.
// - If you want large meshes with more than 64K vertices, you can either:
// (A) Handle the ImDrawCmd::VtxOffset value in your renderer back-end, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'.
@ -4309,9 +4336,9 @@ static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* d
// (B) Or handle 32-bits indices in your renderer back-end, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h.
// Most example back-ends already support this. For example, the OpenGL example code detect index size at compile-time:
// glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
// Your own engine or render API may use different parameters or function calls to specify index sizes.
// Your own engine or render API may use different parameters or function calls to specify index sizes.
// 2 and 4 bytes indices are generally supported by most graphics API.
// - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching
// - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching
// the 64K limit to split your draw commands in multiple draw lists.
if (sizeof(ImDrawIdx) == 2)
IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
@ -4493,8 +4520,8 @@ void ImGui::EndFrame()
EndFrameDrawDimmedBackgrounds();
// Show CTRL+TAB list window
if (g.NavWindowingTarget)
NavUpdateWindowingList();
if (g.NavWindowingTarget != NULL)
NavUpdateWindowingOverlay();
SetCurrentViewport(NULL, NULL);
@ -4560,7 +4587,7 @@ void ImGui::Render()
EndFrame();
g.FrameCountRendered = g.FrameCount;
g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = g.IO.MetricsRenderWindows = 0;
// Add background ImDrawList (for each active viewport)
for (int n = 0; n != g.Viewports.Size; n++)
{
@ -4683,7 +4710,7 @@ static void FindHoveredWindow()
if (hole_bb.Contains(g.IO.MousePos - window->Pos))
continue;
}
if (hovered_window == NULL)
hovered_window = window;
if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow))
@ -4731,7 +4758,7 @@ int ImGui::GetKeyIndex(ImGuiKey imgui_key)
// Note that imgui doesn't know the semantic of each entry of io.KeysDown[]. Use your own indices/enums according to how your back-end/engine stored them into io.KeysDown[]!
bool ImGui::IsKeyDown(int user_key_index)
{
if (user_key_index < 0)
if (user_key_index < 0)
return false;
ImGuiContext& g = *GImGui;
IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
@ -4963,7 +4990,7 @@ bool ImGui::IsItemFocused()
if (g.NavId == 0 || g.NavDisableHighlight || g.NavId != window->DC.LastItemId)
return false;
// Special handling for the dummy item after Begin() which represent the title bar or tab.
// Special handling for the dummy item after Begin() which represent the title bar or tab.
// When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case.
if (window->DC.LastItemId == window->ID && window->WriteAccessed)
return false;
@ -5650,7 +5677,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
}
// Title bar
// (when docked, DockNode are drawing their own title bar. Individual windows however do NOT set the _NoTitleBar flag,
// (when docked, DockNode are drawing their own title bar. Individual windows however do NOT set the _NoTitleBar flag,
// in order for their pos/size to be matching their undocking state.)
if (!(flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive)
{
@ -5718,7 +5745,7 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
ImGuiWindowFlags flags = window->Flags;
const bool has_close_button = (p_open != NULL);
const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse);
const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None);
// Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)
const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
@ -6195,7 +6222,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// For popups and menus that may be protruding out of their parent viewport, we enable _NoFocusOnClick so that clicking on them
// won't steal the OS focus away from their parent window (which may be reflected in OS the title bar decoration).
// Setting _NoFocusOnClick would technically prevent us from bringing back to front in case they are being covered by an OS window from a different app,
// Setting _NoFocusOnClick would technically prevent us from bringing back to front in case they are being covered by an OS window from a different app,
// but it shouldn't be much of a problem considering those are already popups that are closed when clicking elsewhere.
if (is_short_lived_floating_window && (flags & ImGuiWindowFlags_Modal) == 0)
viewport_flags |= ImGuiViewportFlags_NoFocusOnAppearing | ImGuiViewportFlags_NoFocusOnClick;
@ -6321,7 +6348,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->OuterRectClipped.ClipWith(host_rect);
// Inner rectangle
// Not affected by window border size. Used by:
// Not affected by window border size. Used by:
// - InnerClipRect
// - ScrollToBringRectIntoView()
// - NavUpdatePageUpPageDown()
@ -6586,7 +6613,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// When we are about to select this tab (which will only be visible on the _next frame_), flag it with a non-zero HiddenFramesCannotSkipItems.
// This will have the important effect of actually returning true in Begin() and not setting SkipItems, allowing an earlier submission of the window contents.
// This is analogous to regular windows being hidden from one frame.
// This is analogous to regular windows being hidden from one frame.
// It is especially important as e.g. nested TabBars would otherwise generate flicker in the form of one empty frame, or focus requests won't be processed.
if (window->DockIsActive && !window->DockTabIsVisible)
{
@ -6787,7 +6814,7 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind
if (window != ignore_window && window->WasActive && !(window->Flags & ImGuiWindowFlags_ChildWindow))
if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs))
{
// FIXME-DOCKING: This is failing (lagging by one frame) for docked windows.
// FIXME-DOCKING: This is failing (lagging by one frame) for docked windows.
// If A and B are docked into window and B disappear, at the NewFrame() call site window->NavLastChildNavWindow will still point to B.
// We might leverage the tab order implicitly stored in window->DockNodeAsHost->TabBar (essentially the 'most_recently_selected_tab' code in tab bar will do that but on next update)
// to tell which is the "previous" window. Or we may leverage 'LastFrameFocused/LastFrameJustFocused' and have this function handle child window itself?
@ -7410,11 +7437,11 @@ void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pi
}
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
void ImGui::SetNextWindowPosCenter(ImGuiCond cond)
{
ImGuiViewport* viewport = ImGui::GetMainViewport();
SetNextWindowPos(viewport->Pos + viewport->Size * 0.5f, cond, ImVec2(0.5f, 0.5f));
SetNextWindowViewport(viewport->ID);
void ImGui::SetNextWindowPosCenter(ImGuiCond cond)
{
ImGuiViewport* viewport = ImGui::GetMainViewport();
SetNextWindowPos(viewport->Pos + viewport->Size * 0.5f, cond, ImVec2(0.5f, 0.5f));
SetNextWindowViewport(viewport->ID);
}
#endif
@ -8818,7 +8845,7 @@ void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const Im
{
ImGuiContext& g = *GImGui;
IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None);
ImGui::NavMoveRequestCancel();
NavMoveRequestCancel();
g.NavMoveDir = move_dir;
g.NavMoveClipDir = clip_dir;
g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
@ -9159,10 +9186,10 @@ static void ImGui::NavUpdate()
g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
{
if ((allowed_dir_flags & (1<<ImGuiDir_Left)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadLeft, ImGuiNavInput_KeyLeft_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Left;
if ((allowed_dir_flags & (1<<ImGuiDir_Right)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadRight,ImGuiNavInput_KeyRight_,ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Right;
if ((allowed_dir_flags & (1<<ImGuiDir_Up)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadUp, ImGuiNavInput_KeyUp_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Up;
if ((allowed_dir_flags & (1<<ImGuiDir_Down)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadDown, ImGuiNavInput_KeyDown_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Down;
if ((allowed_dir_flags & (1 << ImGuiDir_Left)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadLeft, ImGuiNavInput_KeyLeft_, ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Left; }
if ((allowed_dir_flags & (1 << ImGuiDir_Right)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadRight,ImGuiNavInput_KeyRight_,ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Right; }
if ((allowed_dir_flags & (1 << ImGuiDir_Up)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadUp, ImGuiNavInput_KeyUp_, ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Up; }
if ((allowed_dir_flags & (1 << ImGuiDir_Down)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadDown, ImGuiNavInput_KeyDown_, ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Down; }
}
g.NavMoveClipDir = g.NavMoveDir;
}
@ -9175,7 +9202,8 @@ static void ImGui::NavUpdate()
g.NavMoveRequestForward = ImGuiNavForward_ForwardActive;
}
// Update PageUp/PageDown scroll
// Update PageUp/PageDown/Home/End scroll
// FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
float nav_scoring_rect_offset_y = 0.0f;
if (nav_keyboard_active)
nav_scoring_rect_offset_y = NavUpdatePageUpPageDown(allowed_dir_flags);
@ -9294,8 +9322,18 @@ static void ImGui::NavUpdateMoveResult()
// Scroll to keep newly navigated item fully into view.
if (g.NavLayer == 0)
{
ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos);
ImVec2 delta_scroll = ScrollToBringRectIntoView(result->Window, rect_abs);
ImVec2 delta_scroll;
if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_ScrollToEdge)
{
float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f;
delta_scroll.y = result->Window->Scroll.y - scroll_target;
SetScrollY(result->Window, scroll_target);
}
else
{
ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos);
delta_scroll = ScrollToBringRectIntoView(result->Window, rect_abs);
}
// Offset our result position so mouse position can be applied immediately after in NavUpdate()
result->RectRel.TranslateX(-delta_scroll.x);
@ -9314,6 +9352,7 @@ static void ImGui::NavUpdateMoveResult()
g.NavMoveFromClampedRefRect = false;
}
// Handle PageUp/PageDown/Home/End keys
static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags)
{
ImGuiContext& g = *GImGui;
@ -9323,9 +9362,11 @@ static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags)
return 0.0f;
ImGuiWindow* window = g.NavWindow;
bool page_up_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageUp]) && (allowed_dir_flags & (1 << ImGuiDir_Up));
bool page_down_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageDown]) && (allowed_dir_flags & (1 << ImGuiDir_Down));
if (page_up_held != page_down_held) // If either (not both) are pressed
const bool page_up_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageUp]) && (allowed_dir_flags & (1 << ImGuiDir_Up));
const bool page_down_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageDown]) && (allowed_dir_flags & (1 << ImGuiDir_Down));
const bool home_pressed = IsKeyPressed(g.IO.KeyMap[ImGuiKey_Home]) && (allowed_dir_flags & (1 << ImGuiDir_Up));
const bool end_pressed = IsKeyPressed(g.IO.KeyMap[ImGuiKey_End]) && (allowed_dir_flags & (1 << ImGuiDir_Down));
if (page_up_held != page_down_held || home_pressed != end_pressed) // If either (not both) are pressed
{
if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll)
{
@ -9334,26 +9375,49 @@ static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags)
SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true))
SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
else if (home_pressed)
SetScrollY(window, 0.0f);
else if (end_pressed)
SetScrollY(window, window->ScrollMax.y);
}
else
{
const 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());
float nav_scoring_rect_offset_y = 0.0f;
if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true))
{
nav_scoring_rect_offset_y = -page_offset_y;
g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset, we intentionally request the opposite 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.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
}
else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true))
{
nav_scoring_rect_offset_y = +page_offset_y;
g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset, we intentionally request the opposite direction (so we can always land on the last item)
g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item)
g.NavMoveClipDir = ImGuiDir_Down;
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
}
else if (home_pressed)
{
// FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y
// Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdge flag, we don't scroll immediately to avoid scrolling happening before nav result.
// Preserve current horizontal position if we have any.
nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y;
if (nav_rect_rel.IsInverted())
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
g.NavMoveDir = ImGuiDir_Down;
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
}
else if (end_pressed)
{
nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y;
if (nav_rect_rel.IsInverted())
nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
g.NavMoveDir = ImGuiDir_Up;
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
}
return nav_scoring_rect_offset_y;
}
}
@ -9559,7 +9623,7 @@ static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window)
}
// Overlay displayed when using CTRL+TAB. Called by EndFrame().
void ImGui::NavUpdateWindowingList()
void ImGui::NavUpdateWindowingOverlay()
{
ImGuiContext& g = *GImGui;
IM_ASSERT(g.NavWindowingTarget != NULL);
@ -10471,7 +10535,7 @@ void ImGui::TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& o
// 1) We test if ImGuiConfigFlags_ViewportsEnable was just toggled, which allows us to conveniently
// translate imgui windows from OS-window-local to absolute coordinates or vice-versa.
// 2) If it's not going to fit into the new size, keep it at same absolute position.
// One problem with this is that most Win32 applications doesn't update their render while dragging,
// One problem with this is that most Win32 applications doesn't update their render while dragging,
// and so the window will appear to teleport when releasing the mouse.
const bool translate_all_windows = (g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable) != (g.ConfigFlagsLastFrame & ImGuiConfigFlags_ViewportsEnable);
ImRect test_still_fit_rect(old_pos, old_pos + viewport->Size);
@ -10498,7 +10562,7 @@ void ImGui::ScaleWindowsInViewport(ImGuiViewportP* viewport, float scale)
}
// If the back-end doesn't set MouseLastHoveredViewport or doesn't honor ImGuiViewportFlags_NoInputs, we do a search ourselves.
// A) It won't take account of the possibility that non-imgui windows may be in-between our dragged window and our target window.
// A) It won't take account of the possibility that non-imgui windows may be in-between our dragged window and our target window.
// B) It requires Platform_GetWindowFocus to be implemented by back-end.
static ImGuiViewportP* FindHoveredViewportFromPlatformWindowStack(const ImVec2 mouse_platform_pos)
{
@ -10566,7 +10630,7 @@ static void ImGui::UpdateViewportsNewFrame()
g.Windows[window_n]->Viewport = NULL;
g.Windows[window_n]->ViewportOwned = false;
}
if (viewport == g.MouseLastHoveredViewport)
if (viewport == g.MouseLastHoveredViewport)
g.MouseLastHoveredViewport = NULL;
g.Viewports.erase(g.Viewports.Data + n);
@ -10582,7 +10646,7 @@ static void ImGui::UpdateViewportsNewFrame()
const bool platform_funcs_available = viewport->PlatformWindowCreated;
if ((g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable))
{
// Update Position and Size (from Platform Window to ImGui) if requested.
// Update Position and Size (from Platform Window to ImGui) if requested.
// We do it early in the frame instead of waiting for UpdatePlatformWindows() to avoid a frame of lag when moving/resizing using OS facilities.
if (!(viewport->Flags & ImGuiViewportFlags_Minimized) && platform_funcs_available)
{
@ -10652,7 +10716,7 @@ static void ImGui::UpdateViewportsNewFrame()
else
{
// If the back-end doesn't know how to honor ImGuiViewportFlags_NoInputs, we do a search ourselves. Note that this search:
// A) won't take account of the possibility that non-imgui windows may be in-between our dragged window and our target window.
// A) won't take account of the possibility that non-imgui windows may be in-between our dragged window and our target window.
// B) uses LastFrameAsRefViewport as a flawed replacement for the last time a window was focused (we could/should fix that by introducing Focus functions in PlatformIO)
viewport_hovered = FindHoveredViewportFromPlatformWindowStack(g.IO.MousePos);
}
@ -10664,11 +10728,11 @@ static void ImGui::UpdateViewportsNewFrame()
// Update mouse reference viewport
// (when moving a window we aim at its viewport, but this will be overwritten below if we go in drag and drop mode)
if (g.MovingWindow)
g.MouseViewport = g.MovingWindow->Viewport;
g.MouseViewport = g.MovingWindow->Viewport;
else
g.MouseViewport = g.MouseLastHoveredViewport;
// When dragging something, always refer to the last hovered viewport.
// When dragging something, always refer to the last hovered viewport.
// - when releasing a moving window we will revert to aiming behind (at viewport_hovered)
// - when we are between viewports, our dragged preview will tend to show in the last viewport _even_ if we don't have tooltips in their viewports (when lacking monitor info)
// - consider the case of holding on a menu item to browse child menus: even thou a mouse button is held, there's no active id because menu items only react on mouse release.
@ -10909,7 +10973,7 @@ void ImGui::UpdatePlatformWindows()
{
ImGuiViewportP* viewport = g.Viewports[i];
// Destroy platform window if the viewport hasn't been submitted or if it is hosting a hidden window
// Destroy platform window if the viewport hasn't been submitted or if it is hosting a hidden window
// (the implicit/fallback Debug##Default window will be registering its viewport then be disabled, causing a dummy DestroyPlatformWindow to be made each frame)
bool destroy_platform_window = false;
destroy_platform_window |= (viewport->LastFrameActive < g.FrameCount - 1);
@ -10982,7 +11046,7 @@ void ImGui::UpdatePlatformWindows()
// Show window
g.PlatformIO.Platform_ShowWindow(viewport);
// Even without focus, we assume the window becomes front-most.
// Even without focus, we assume the window becomes front-most.
// This is useful for our platform z-order heuristic when io.MouseHoveredViewport is not available.
if (viewport->LastFrontMostStampCount != g.ViewportFrontMostStampCount)
viewport->LastFrontMostStampCount = ++g.ViewportFrontMostStampCount;
@ -10993,7 +11057,7 @@ void ImGui::UpdatePlatformWindows()
}
// Update our implicit z-order knowledge of platform windows, which is used when the back-end cannot provide io.MouseHoveredViewport.
// When setting Platform_GetWindowFocus, it is expected that the platform back-end can handle calls without crashing if it doesn't have data stored.
// When setting Platform_GetWindowFocus, it is expected that the platform back-end can handle calls without crashing if it doesn't have data stored.
if (g.PlatformIO.Platform_GetWindowFocus != NULL)
{
ImGuiViewportP* focused_viewport = NULL;
@ -11061,7 +11125,7 @@ static int ImGui::FindPlatformMonitorForPos(const ImVec2& pos)
// Search for the monitor with the largest intersection area with the given rectangle
// We generally try to avoid searching loops but the monitor count should be very small here
// FIXME-OPT: We could test the last monitor used for that viewport first, and early
// FIXME-OPT: We could test the last monitor used for that viewport first, and early
static int ImGui::FindPlatformMonitorForRect(const ImRect& rect)
{
ImGuiContext& g = *GImGui;
@ -11070,7 +11134,7 @@ static int ImGui::FindPlatformMonitorForRect(const ImRect& rect)
if (monitor_count <= 1)
return monitor_count - 1;
// Use a minimum threshold of 1.0f so a zero-sized rect won't false positive, and will still find the correct monitor given its position.
// Use a minimum threshold of 1.0f so a zero-sized rect won't false positive, and will still find the correct monitor given its position.
// This is necessary for tooltips which always resize down to zero at first.
const float surface_threshold = ImMax(rect.GetWidth() * rect.GetHeight() * 0.5f, 1.0f);
int best_monitor_n = -1;
@ -11121,12 +11185,12 @@ void ImGui::DestroyPlatformWindow(ImGuiViewportP* viewport)
void ImGui::DestroyPlatformWindows()
{
// We call the destroy window on every viewport (including the main viewport, index 0) to give a chance to the back-end
// to clear any data they may have stored in e.g. PlatformUserData, RendererUserData.
// It is convenient for the platform back-end code to store something in the main viewport, in order for e.g. the mouse handling
// We call the destroy window on every viewport (including the main viewport, index 0) to give a chance to the back-end
// to clear any data they may have stored in e.g. PlatformUserData, RendererUserData.
// It is convenient for the platform back-end code to store something in the main viewport, in order for e.g. the mouse handling
// code to operator a consistent manner.
// It is expected that the back-end can handle calls to Renderer_DestroyWindow/Platform_DestroyWindow without
// crashing if it doesn't have data stored.
// crashing if it doesn't have data stored.
ImGuiContext& g = *GImGui;
for (int i = 0; i < g.Viewports.Size; i++)
DestroyPlatformWindow(g.Viewports[i]);
@ -11172,7 +11236,7 @@ struct ImGuiDockRequest
{
ImGuiDockRequestType Type;
ImGuiWindow* DockTargetWindow; // Destination/Target Window to dock into (may be a loose window or a DockNode, might be NULL in which case DockTargetNode cannot be NULL)
ImGuiDockNode* DockTargetNode; // Destination/Target Node to dock into
ImGuiDockNode* DockTargetNode; // Destination/Target Node to dock into
ImGuiWindow* DockPayload; // Source/Payload window to dock (may be a loose window or a DockNode), [Optional]
ImGuiDir DockSplitDir;
float DockSplitRatio;
@ -11397,7 +11461,7 @@ void ImGui::DockContextUpdateUndocking(ImGuiContext* ctx)
DockBuilderRemoveNodeChildNodes(node->ID);
//dc->WantFullRebuild = true;
}
// Process full rebuild
#if 0
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C)))
@ -11999,7 +12063,7 @@ static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, b
{
DockNodeAddTabBar(node);
node->TabBar->SelectedTabId = node->TabBar->NextSelectedTabId = node->SelectedTabID;
// Add existing windows
for (int n = 0; n < node->Windows.Size - 1; n++)
TabBarAddTab(node->TabBar, ImGuiTabItemFlags_None, node->Windows[n]);
@ -12367,7 +12431,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
// N+2: DockNodeUpdate(): node can create host window / Begin(): window becomes visible
// We could remove this frame if we could reliably calculate the expected window size during node update, before the Begin() code.
// It would require a generalization of CalcWindowExpectedSize(), probably extracting code away from Begin().
// In reality it isn't very important as user quickly ends up with size data in .ini file.
// In reality it isn't very important as user quickly ends up with size data in .ini file.
if (node->IsVisible && node->HostWindow == NULL && node->IsFloatingNode() && node->IsLeafNode())
{
IM_ASSERT(node->Windows.Size > 0);
@ -12459,7 +12523,7 @@ static void ImGui::DockNodeUpdate(ImGuiDockNode* node)
// We set ImGuiWindowFlags_NoFocusOnAppearing because we don't want the host window to take full focus (e.g. steal NavWindow)
// But we still it bring it to the front of display. There's no way to choose this precise behavior via window flags.
// One simple case to ponder if: window A has a toggle to create windows B/C/D. Dock B/C/D together, clear the toggle and enable it again.
// When reappearing B/C/D will request focus and be moved to the top of the display pile, but they are not linked to the dock host window
// When reappearing B/C/D will request focus and be moved to the top of the display pile, but they are not linked to the dock host window
// during the frame they appear. The dock host window would keep its old display order, and the sorting in EndFrame would move B/C/D back
// after the dock host window, losing their top-most status.
if (node->HostWindow->Appearing)
@ -13035,7 +13099,7 @@ static void ImGui::DockNodePreviewDockCalc(ImGuiWindow* host_window, ImGuiDockNo
ImGuiContext& g = *GImGui;
// There is an edge case when docking into a dockspace which only has inactive nodes.
// In this case DockNodeTreeFindNodeByPos() will have selected a leaf node which is inactive.
// In this case DockNodeTreeFindNodeByPos() will have selected a leaf node which is inactive.
// Because the inactive leaf node doesn't have proper pos/size yet, we'll use the root node as reference.
ImGuiDockNode* ref_node_for_rect = (host_node && !host_node->IsVisible) ? DockNodeGetRootNode(host_node) : host_node;
if (ref_node_for_rect)
@ -13206,7 +13270,7 @@ static void ImGui::DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDock
overlay_draw_lists[overlay_n]->AddLine(ImVec2(draw_r_in.Min.x, center.y), ImVec2(draw_r_in.Max.x, center.y), overlay_col_lines);
}
}
// Stop after ImGuiDir_None
if ((host_node && (host_node->GetMergedFlags() & ImGuiDockNodeFlags_NoSplit)) || g.IO.ConfigDockingNoSplit)
return;
@ -13552,7 +13616,7 @@ ImGuiDockNode* ImGui::DockNodeTreeFindNodeByPos(ImGuiDockNode* node, ImVec2 pos)
return node->CentralNode;
return DockNodeTreeFindFallbackLeafNode(node);
}
return NULL;
}
@ -13684,7 +13748,7 @@ void ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags fla
}
// Tips: Use with ImGuiDockNodeFlags_PassthruCentralNode!
// The limitation with this call is that your window won't have a menu bar.
// The limitation with this call is that your window won't have a menu bar.
// Even though we could pass window flags, it would also require the user to be able to call BeginMenuBar() somehow meaning we can't Begin/End in a single function.
// So if you want a menu bar you need to repeat this code manually ourselves. As with advanced other Docking API, we may change this function signature.
ImGuiID ImGui::DockSpaceOverViewport(ImGuiViewport* viewport, ImGuiDockNodeFlags dockspace_flags, const ImGuiWindowClass* window_class)
@ -13933,7 +13997,7 @@ void ImGui::DockBuilderRemoveNodeDockedWindows(ImGuiID root_id, bool clear_persi
// If 'out_id_at_dir' or 'out_id_at_opposite_dir' are non NULL, the function will write out the ID of the two new nodes created.
// Return value is ID of the node at the specified direction, so same as (*out_id_at_dir) if that pointer is set.
// FIXME-DOCK: We are not exposing nor using split_outer.
// FIXME-DOCK: We are not exposing nor using split_outer.
ImGuiID ImGui::DockBuilderSplitNode(ImGuiID id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID* out_id_at_dir, ImGuiID* out_id_at_opposite_dir)
{
ImGuiContext* ctx = GImGui;
@ -14081,7 +14145,7 @@ void ImGui::DockBuilderCopyDockSpace(ImGuiID src_dockspace_id, ImGuiID dst_docks
if (dst_dock_id != 0)
{
// Docked windows gets redocked into the new node hierarchy.
// Docked windows gets redocked into the new node hierarchy.
IMGUI_DEBUG_LOG_DOCKING("Remap live window '%s' 0x%08X -> '%s' 0x%08X\n", src_window_name, src_dock_id, dst_window_name, dst_dock_id);
DockBuilderDockWindow(dst_window_name, dst_dock_id);
}
@ -14107,7 +14171,7 @@ void ImGui::DockBuilderCopyDockSpace(ImGuiID src_dockspace_id, ImGuiID dst_docks
if (src_windows.contains(window->ID))
continue;
// Docked windows gets redocked into the new node hierarchy.
// Docked windows gets redocked into the new node hierarchy.
IMGUI_DEBUG_LOG_DOCKING("Remap window '%s' %08X -> %08X\n", window->Name, src_dock_id, dst_dock_id);
DockBuilderDockWindow(window->Name, dst_dock_id);
}
@ -14360,7 +14424,7 @@ void ImGui::BeginAsDockableDragDropTarget(ImGuiWindow* window)
const bool is_explicit_target = g.IO.ConfigDockingWithShift || IsMouseHoveringRect(explicit_target_rect.Min, explicit_target_rect.Max);
// Preview docking request and find out split direction/ratio
//const bool do_preview = true; // Ignore testing for payload->IsPreview() which removes one frame of delay, but breaks overlapping drop targets within the same window.
//const bool do_preview = true; // Ignore testing for payload->IsPreview() which removes one frame of delay, but breaks overlapping drop targets within the same window.
const bool do_preview = payload->IsPreview() || payload->IsDelivery();
if (do_preview && (node != NULL || allow_null_target_node))
{
@ -14692,7 +14756,7 @@ static const char* GetClipboardTextFn_DefaultImpl(void*)
ItemCount item_count = 0;
PasteboardGetItemCount(main_clipboard, &item_count);
for (int i = 0; i < item_count; i++)
for (ItemCount i = 0; i < item_count; i++)
{
PasteboardItemID item_id = 0;
PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id);
@ -15096,8 +15160,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
for (int i = 0; i < g.PlatformIO.Monitors.Size; i++)
{
const ImGuiPlatformMonitor& mon = g.PlatformIO.Monitors[i];
ImGui::BulletText("Monitor #%d: DPI %.0f%%\n MainMin (%.0f,%.0f), MainMax (%.0f,%.0f), MainSize (%.0f,%.0f)\n WorkMin (%.0f,%.0f), WorkMax (%.0f,%.0f), WorkSize (%.0f,%.0f)",
i, mon.DpiScale * 100.0f,
ImGui::BulletText("Monitor #%d: DPI %.0f%%\n MainMin (%.0f,%.0f), MainMax (%.0f,%.0f), MainSize (%.0f,%.0f)\n WorkMin (%.0f,%.0f), WorkMax (%.0f,%.0f), WorkSize (%.0f,%.0f)",
i, mon.DpiScale * 100.0f,
mon.MainPos.x, mon.MainPos.y, mon.MainPos.x + mon.MainSize.x, mon.MainPos.y + mon.MainSize.y, mon.MainSize.x, mon.MainSize.y,
mon.WorkPos.x, mon.WorkPos.y, mon.WorkPos.x + mon.WorkSize.x, mon.WorkPos.y + mon.WorkSize.y, mon.WorkSize.x, mon.WorkSize.y);
}