1
0
mirror of https://github.com/ocornut/imgui.git synced 2025-01-31 12:03:49 +01:00

Merge branch 'master' into docking

This commit is contained in:
ocornut 2022-09-01 20:53:36 +02:00
commit bc2002ab92
8 changed files with 258 additions and 79 deletions

View File

@ -21,6 +21,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. // 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2022-09-01: Inputs: Honor GLFW_CURSOR_DISABLED by not setting mouse position.
// 2022-04-30: Inputs: Fixed ImGui_ImplGlfw_TranslateUntranslatedKey() for lower case letters on OSX. // 2022-04-30: Inputs: Fixed ImGui_ImplGlfw_TranslateUntranslatedKey() for lower case letters on OSX.
// 2022-03-23: Inputs: Fixed a regression in 1.87 which resulted in keyboard modifiers events being reported incorrectly on Linux/X11. // 2022-03-23: Inputs: Fixed a regression in 1.87 which resulted in keyboard modifiers events being reported incorrectly on Linux/X11.
// 2022-02-07: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing callbacks after initializing backend. // 2022-02-07: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing callbacks after initializing backend.
@ -394,6 +395,8 @@ void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y)
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackCursorPos != NULL && window == bd->Window) if (bd->PrevUserCallbackCursorPos != NULL && window == bd->Window)
bd->PrevUserCallbackCursorPos(window, x, y); bd->PrevUserCallbackCursorPos(window, x, y);
if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
return;
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
@ -414,6 +417,8 @@ void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackCursorEnter != NULL && window == bd->Window) if (bd->PrevUserCallbackCursorEnter != NULL && window == bd->Window)
bd->PrevUserCallbackCursorEnter(window, entered); bd->PrevUserCallbackCursorEnter(window, entered);
if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
return;
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
if (entered) if (entered)
@ -597,6 +602,12 @@ static void ImGui_ImplGlfw_UpdateMouseData()
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
if (glfwGetInputMode(bd->Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
{
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
return;
}
ImGuiID mouse_viewport_id = 0; ImGuiID mouse_viewport_id = 0;
const ImVec2 mouse_pos_prev = io.MousePos; const ImVec2 mouse_pos_prev = io.MousePos;
for (int n = 0; n < platform_io.Viewports.Size; n++) for (int n = 0; n < platform_io.Viewports.Size; n++)

View File

@ -134,6 +134,11 @@ Other Changes:
Enter keep the input active and select all text. Enter keep the input active and select all text.
- InputText: numerical fields automatically accept full-width characters (U+FF01..U+FF5E) - InputText: numerical fields automatically accept full-width characters (U+FF01..U+FF5E)
by converting them to half-width (U+0021..U+007E). by converting them to half-width (U+0021..U+007E).
- IsItemHovered: Added ImGuiHoveredFlags_DelayNormal and ImGuiHoveredFlags_DelayShort flags,
allowing to introduce a shared delay for tooltip idioms. The delays are respectively
io.HoverDelayNormal (default to 0.30f) and io.HoverDelayFast (default to 0.10f). (#1485)
- IsItemHovered: Added ImGuiHoveredFlags_NoSharedDelay to disable sharing delays between itemm,
so moving from one item to a nearby one will requires delay to elapse again. (#1485)
- Tables,Columns: fixed a layout issue where SameLine() prior to a row change would set the - Tables,Columns: fixed a layout issue where SameLine() prior to a row change would set the
next row in such state where subsequent SameLine() would move back to previous row. next row in such state where subsequent SameLine() would move back to previous row.
- Tabs: Fixed a crash when closing multiple windows (possible with docking only) with an - Tabs: Fixed a crash when closing multiple windows (possible with docking only) with an
@ -141,14 +146,24 @@ Other Changes:
- Window: Fixed a potential crash when appending to a child window. (#5515, #3496, #4797) [@rokups] - Window: Fixed a potential crash when appending to a child window. (#5515, #3496, #4797) [@rokups]
- IO: Added ImGuiKey_MouseXXX aliases for mouse buttons/wheel so all operations done on ImGuiKey - IO: Added ImGuiKey_MouseXXX aliases for mouse buttons/wheel so all operations done on ImGuiKey
can apply to mouse data as well. (#4921) can apply to mouse data as well. (#4921)
- Menus: Fixed incorrect sub-menu parent association when opening a menu by closing another.
Among other things, it would accidentally break part of the closing heuristic logic when moving
towards a sub-menu. (#2517, #5614). [@rokups]
- Menus: Fixed gaps in closing logic which would make child-menu erroneously close when crossing
the gap between a menu item inside a window and a child-menu in a secondary viewport. (#5614)
- Nav: Fixed moving/resizing window with gamepad or keyboard when running at very high framerate. - Nav: Fixed moving/resizing window with gamepad or keyboard when running at very high framerate.
- Nav: Pressing Space/GamepadFaceDown on a repeating button uses the same repeating rate as a mouse hold. - Nav: Pressing Space/GamepadFaceDown on a repeating button uses the same repeating rate as a mouse hold.
- Nav: Fixed an issue opening a menu with Right key from a non-menu window.
- Platform IME: [Windows] Removed call to ImmAssociateContextEx() leading to freeze on some setups. - Platform IME: [Windows] Removed call to ImmAssociateContextEx() leading to freeze on some setups.
(#2589, #5535, #5264, #4972) (#2589, #5535, #5264, #4972)
- Misc: better error reporting for PopStyleColor()/PopStyleVar() + easier to recover. (#1651)
- Misc: io.Framerate moving average now converge in 60 frames instead of 120. (#5236, #4138) - Misc: io.Framerate moving average now converge in 60 frames instead of 120. (#5236, #4138)
- Debug Tools: Debug Log: Added 'IO' and 'Clipper' events logging. - Debug Tools: Debug Log: Added 'IO' and 'Clipper' events logging.
- Debug Tools: Item Picker: Mouse button can be changed by holding Ctrl+Shift, making it easier - Debug Tools: Item Picker: Mouse button can be changed by holding Ctrl+Shift, making it easier
to use the Item Picker in e.g. menus. (#2673) to use the Item Picker in e.g. menus. (#2673)
- Demo: Improved "Constrained-resizing window" example, more clearly showcase aspect-ratio. (#5627)
- Demo: Added more explicit "Center window" mode to "Overlay example". (#5618)
- Backends: GLFW: Honor GLFW_CURSOR_DISABLED by not setting mouse position. (#5625) [@scorpion-26]
- Backends: Metal: Use __bridge for ARC based systems. (#5403) [@stack] - Backends: Metal: Use __bridge for ARC based systems. (#5403) [@stack]
- Backends: Metal: Add dispatch synchronization. (#5447) [@luigifcruz] - Backends: Metal: Add dispatch synchronization. (#5447) [@luigifcruz]
- Backends: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount'. (#5603) [@dcvz] - Backends: Metal: Update deprecated property 'sampleCount'->'rasterSampleCount'. (#5603) [@dcvz]

View File

@ -1171,6 +1171,8 @@ ImGuiIO::ImGuiIO()
#endif #endif
KeyRepeatDelay = 0.275f; KeyRepeatDelay = 0.275f;
KeyRepeatRate = 0.050f; KeyRepeatRate = 0.050f;
HoverDelayNormal = 0.30f;
HoverDelayShort = 0.10f;
UserData = NULL; UserData = NULL;
Fonts = NULL; Fonts = NULL;
@ -2907,6 +2909,11 @@ void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col)
void ImGui::PopStyleColor(int count) void ImGui::PopStyleColor(int count)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.ColorStack.Size < count)
{
IM_ASSERT_USER_ERROR(g.ColorStack.Size > count, "Calling PopStyleColor() too many times: stack underflow.");
count = g.ColorStack.Size;
}
while (count > 0) while (count > 0)
{ {
ImGuiColorMod& backup = g.ColorStack.back(); ImGuiColorMod& backup = g.ColorStack.back();
@ -2996,6 +3003,11 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)
void ImGui::PopStyleVar(int count) void ImGui::PopStyleVar(int count)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.StyleVarStack.Size < count)
{
IM_ASSERT_USER_ERROR(g.StyleVarStack.Size > count, "Calling PopStyleVar() too many times: stack underflow.");
count = g.StyleVarStack.Size;
}
while (count > 0) while (count > 0)
{ {
// We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it. // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it.
@ -3643,6 +3655,24 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
return false; return false;
} }
// Handle hover delay
// (some ideas: https://www.nngroup.com/articles/timing-exposing-content)
float delay;
if (flags & ImGuiHoveredFlags_DelayNormal)
delay = g.IO.HoverDelayNormal;
else if (flags & ImGuiHoveredFlags_DelayShort)
delay = g.IO.HoverDelayShort;
else
delay = 0.0f;
if (delay > 0.0f)
{
ImGuiID hover_delay_id = (g.LastItemData.ID != 0) ? g.LastItemData.ID : window->GetIDFromRectangle(g.LastItemData.Rect);
if ((flags & ImGuiHoveredFlags_NoSharedDelay) && (g.HoverDelayIdPreviousFrame != hover_delay_id))
g.HoverDelayTimer = 0.0f;
g.HoverDelayId = hover_delay_id;
return g.HoverDelayTimer >= delay;
}
return true; return true;
} }
@ -4631,6 +4661,23 @@ void ImGui::NewFrame()
} }
#endif #endif
// Update hover delay for IsItemHovered() with delays and tooltips
g.HoverDelayIdPreviousFrame = g.HoverDelayId;
if (g.HoverDelayId != 0)
{
//if (g.IO.MouseDelta.x == 0.0f && g.IO.MouseDelta.y == 0.0f) // Need design/flags
g.HoverDelayTimer += g.IO.DeltaTime;
g.HoverDelayClearTimer = 0.0f;
g.HoverDelayId = 0;
}
else if (g.HoverDelayTimer > 0.0f)
{
// This gives a little bit of leeway before clearing the hover timer, allowing mouse to cross gaps
g.HoverDelayClearTimer += g.IO.DeltaTime;
if (g.HoverDelayClearTimer >= ImMax(0.20f, g.IO.DeltaTime * 2.0f)) // ~6 frames at 30 Hz + allow for low framerate
g.HoverDelayTimer = g.HoverDelayClearTimer = 0.0f; // May want a decaying timer, in which case need to clamp at max first, based on max of caller last requested timer.
}
// Drag and drop // Drag and drop
g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr; g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr;
g.DragDropAcceptIdCurr = 0; g.DragDropAcceptIdCurr = 0;
@ -8378,6 +8425,8 @@ int ImGui::GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float repeat_ra
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
const ImGuiKeyData* key_data = GetKeyData(key); const ImGuiKeyData* key_data = GetKeyData(key);
if (!key_data->Down) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitate eating mechanism (until we finish work on input ownership)
return 0;
const float t = key_data->DownDuration; const float t = key_data->DownDuration;
return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate); return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate);
} }
@ -8410,6 +8459,8 @@ bool ImGui::IsKeyPressed(ImGuiKey key, bool repeat)
bool ImGui::IsKeyPressedEx(ImGuiKey key, ImGuiInputFlags flags) bool ImGui::IsKeyPressedEx(ImGuiKey key, ImGuiInputFlags flags)
{ {
const ImGuiKeyData* key_data = GetKeyData(key); const ImGuiKeyData* key_data = GetKeyData(key);
if (!key_data->Down) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitate eating mechanism (until we finish work on input ownership)
return false;
const float t = key_data->DownDuration; const float t = key_data->DownDuration;
if (t < 0.0f) if (t < 0.0f)
return false; return false;
@ -8446,6 +8497,8 @@ bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown)); IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
if (!g.IO.MouseDown[button]) // In theory this should already be encoded as (DownDuration < 0.0f), but testing this facilitate eating mechanism (until we finish work on input ownership)
return false;
const float t = g.IO.MouseDownDuration[button]; const float t = g.IO.MouseDownDuration[button];
if (t == 0.0f) if (t == 0.0f)
return true; return true;
@ -9925,7 +9978,7 @@ void ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags)
ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack. ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
popup_ref.PopupId = id; popup_ref.PopupId = id;
popup_ref.Window = NULL; popup_ref.Window = NULL;
popup_ref.SourceWindow = g.NavWindow; popup_ref.BackupNavWindow = g.NavWindow; // When popup closes focus may be restored to NavWindow (depend on window type).
popup_ref.OpenFrameCount = g.FrameCount; popup_ref.OpenFrameCount = g.FrameCount;
popup_ref.OpenParentId = parent_window->IDStack.back(); popup_ref.OpenParentId = parent_window->IDStack.back();
popup_ref.OpenPopupPos = NavCalcPreferredRefPos(); popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
@ -10028,12 +10081,13 @@ void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_
IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size); IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size);
// Trim open popup stack // Trim open popup stack
ImGuiWindow* focus_window = g.OpenPopupStack[remaining].SourceWindow;
ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window; ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window;
ImGuiWindow* popup_backup_nav_window = g.OpenPopupStack[remaining].BackupNavWindow;
g.OpenPopupStack.resize(remaining); g.OpenPopupStack.resize(remaining);
if (restore_focus_to_window_under_popup) if (restore_focus_to_window_under_popup)
{ {
ImGuiWindow* focus_window = (popup_window && popup_window->Flags & ImGuiWindowFlags_ChildMenu) ? popup_window->ParentWindow : popup_backup_nav_window;
if (focus_window && !focus_window->WasActive && popup_window) if (focus_window && !focus_window->WasActive && popup_window)
{ {
// Fallback // Fallback
@ -17842,7 +17896,7 @@ void ImGui::DebugTextEncoding(const char* str)
static void MetricsHelpMarker(const char* desc) static void MetricsHelpMarker(const char* desc)
{ {
ImGui::TextDisabled("(?)"); ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort))
{ {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
@ -18133,8 +18187,12 @@ void ImGui::ShowMetricsWindow(bool* p_open)
{ {
for (int i = 0; i < g.OpenPopupStack.Size; i++) for (int i = 0; i < g.OpenPopupStack.Size; i++)
{ {
ImGuiWindow* window = g.OpenPopupStack[i].Window; // As it's difficult to interact with tree nodes while popups are open, we display everything inline.
BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : ""); const ImGuiPopupData* popup_data = &g.OpenPopupStack[i];
ImGuiWindow* window = popup_data->Window;
BulletText("PopupID: %08x, Window: '%s' (%s%s), BackupNavWindow '%s', ParentWindow '%s'",
popup_data->PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? "Child;" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? "Menu;" : "",
popup_data->BackupNavWindow ? popup_data->BackupNavWindow->Name : "NULL", window && window->ParentWindow ? window->ParentWindow->Name : "NULL");
} }
TreePop(); TreePop();
} }
@ -18289,6 +18347,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
active_id_using_key_input_count += g.ActiveIdUsingKeyInputMask[n] ? 1 : 0; active_id_using_key_input_count += g.ActiveIdUsingKeyInputMask[n] ? 1 : 0;
Text("ActiveIdUsing: NavDirMask: %X, KeyInputMask: %d key(s)", g.ActiveIdUsingNavDirMask, active_id_using_key_input_count); Text("ActiveIdUsing: NavDirMask: %X, KeyInputMask: %d key(s)", g.ActiveIdUsingNavDirMask, active_id_using_key_input_count);
Text("HoveredId: 0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Not displaying g.HoveredId as it is update mid-frame Text("HoveredId: 0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Not displaying g.HoveredId as it is update mid-frame
Text("HoverDelayId: 0x%08X, Timer: %.2f, ClearTimer: %.2f", g.HoverDelayId, g.HoverDelayTimer, g.HoverDelayClearTimer);
Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize); Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);
Unindent(); Unindent();

27
imgui.h
View File

@ -65,7 +65,7 @@ Index of this file:
// Version // Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens)
#define IMGUI_VERSION "1.89 WIP" #define IMGUI_VERSION "1.89 WIP"
#define IMGUI_VERSION_NUM 18810 #define IMGUI_VERSION_NUM 18813
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx))
#define IMGUI_HAS_TABLE #define IMGUI_HAS_TABLE
#define IMGUI_HAS_VIEWPORT // Viewport WIP branch #define IMGUI_HAS_VIEWPORT // Viewport WIP branch
@ -1328,6 +1328,11 @@ enum ImGuiHoveredFlags_
ImGuiHoveredFlags_NoNavOverride = 1 << 10, // Disable using gamepad/keyboard navigation state when active, always query mouse. ImGuiHoveredFlags_NoNavOverride = 1 << 10, // Disable using gamepad/keyboard navigation state when active, always query mouse.
ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped, ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped,
ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows, ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows,
// Hovering delays (for tooltips)
ImGuiHoveredFlags_DelayNormal = 1 << 11, // Return true after io.HoverDelayNormal elapsed (~0.30 sec)
ImGuiHoveredFlags_DelayShort = 1 << 12, // Return true after io.HoverDelayShort elapsed (~0.10 sec)
ImGuiHoveredFlags_NoSharedDelay = 1 << 13, // Disable shared delay system where moving from one item to the next keeps the previous timer for a short time (standard for tooltips with long delays)
}; };
// Flags for ImGui::DockSpace(), shared/inherited by child nodes. // Flags for ImGui::DockSpace(), shared/inherited by child nodes.
@ -1789,7 +1794,7 @@ enum ImGuiMouseCursor_
enum ImGuiCond_ enum ImGuiCond_
{ {
ImGuiCond_None = 0, // No condition (always set the variable), same as _Always ImGuiCond_None = 0, // No condition (always set the variable), same as _Always
ImGuiCond_Always = 1 << 0, // No condition (always set the variable) ImGuiCond_Always = 1 << 0, // No condition (always set the variable), same as _None
ImGuiCond_Once = 1 << 1, // Set the variable once per runtime session (only the first call will succeed) ImGuiCond_Once = 1 << 1, // Set the variable once per runtime session (only the first call will succeed)
ImGuiCond_FirstUseEver = 1 << 2, // Set the variable if the object/window has no persistently saved data (no entry in .ini file) ImGuiCond_FirstUseEver = 1 << 2, // Set the variable if the object/window has no persistently saved data (no entry in .ini file)
ImGuiCond_Appearing = 1 << 3, // Set the variable if the object/window is appearing after being hidden/inactive (or the first time) ImGuiCond_Appearing = 1 << 3, // Set the variable if the object/window is appearing after being hidden/inactive (or the first time)
@ -1841,7 +1846,7 @@ struct ImVector
// Constructors, destructor // Constructors, destructor
inline ImVector() { Size = Capacity = 0; Data = NULL; } inline ImVector() { Size = Capacity = 0; Data = NULL; }
inline ImVector(const ImVector<T>& src) { Size = Capacity = 0; Data = NULL; operator=(src); } inline ImVector(const ImVector<T>& src) { Size = Capacity = 0; Data = NULL; operator=(src); }
inline ImVector<T>& operator=(const ImVector<T>& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; } inline ImVector<T>& operator=(const ImVector<T>& src) { clear(); resize(src.Size); if (src.Data) memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; }
inline ~ImVector() { if (Data) IM_FREE(Data); } // Important: does not destruct anything inline ~ImVector() { if (Data) IM_FREE(Data); } // Important: does not destruct anything
inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } } // Important: does not destruct anything inline void clear() { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } } // Important: does not destruct anything
@ -1981,6 +1986,8 @@ struct ImGuiIO
float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging. float MouseDragThreshold; // = 6.0f // Distance threshold before considering we are dragging.
float KeyRepeatDelay; // = 0.275f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.). float KeyRepeatDelay; // = 0.275f // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.).
float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds. float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds.
float HoverDelayNormal; // = 0.30 sec // Delay on hovering before IsItemHovered(ImGuiHoveredFlags_DelayNormal) returns true.
float HoverDelayShort; // = 0.10 sec // Delay on hovering before IsItemHovered(ImGuiHoveredFlags_DelayShort) returns true.
void* UserData; // = NULL // Store your own data for retrieval by callbacks. void* UserData; // = NULL // Store your own data for retrieval by callbacks.
ImFontAtlas*Fonts; // <auto> // Font atlas: load, rasterize and pack one or more fonts into a single texture. ImFontAtlas*Fonts; // <auto> // Font atlas: load, rasterize and pack one or more fonts into a single texture.
@ -2181,7 +2188,7 @@ struct ImGuiInputTextCallbackData
// NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough. // NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough.
struct ImGuiSizeCallbackData struct ImGuiSizeCallbackData
{ {
void* UserData; // Read-only. What user passed to SetNextWindowSizeConstraints() void* UserData; // Read-only. What user passed to SetNextWindowSizeConstraints(). Generally store an integer or float in here (need reinterpret_cast<>).
ImVec2 Pos; // Read-only. Window position, for reference. ImVec2 Pos; // Read-only. Window position, for reference.
ImVec2 CurrentSize; // Read-only. Current window size. ImVec2 CurrentSize; // Read-only. Current window size.
ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing. ImVec2 DesiredSize; // Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing.
@ -3254,6 +3261,18 @@ namespace ImGui
//static inline bool IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) //static inline bool IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)
//static inline void SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) //static inline void SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)
//static inline float GetItemsLineHeightWithSpacing() { return GetFrameHeightWithSpacing(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017) //static inline float GetItemsLineHeightWithSpacing() { return GetFrameHeightWithSpacing(); } // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)
//IMGUI_API bool Begin(char* name, bool* p_open, ImVec2 size_first_use, float bg_alpha = -1.0f, ImGuiWindowFlags flags=0); // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017): Equivalent of using SetNextWindowSize(size, ImGuiCond_FirstUseEver) and SetNextWindowBgAlpha().
//static inline bool IsRootWindowOrAnyChildHovered() { return IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); } // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017)
//static inline void AlignFirstTextHeightToWidgets() { AlignTextToFramePadding(); } // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017)
//static inline void SetNextWindowPosCenter(ImGuiCond c=0) { SetNextWindowPos(GetMainViewport()->GetCenter(), c, ImVec2(0.5f,0.5f)); } // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017)
//static inline bool IsItemHoveredRect() { return IsItemHovered(ImGuiHoveredFlags_RectOnly); } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017)
//static inline bool IsPosHoveringAnyWindow(const ImVec2&) { IM_ASSERT(0); return false; } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017): This was misleading and partly broken. You probably want to use the io.WantCaptureMouse flag instead.
//static inline bool IsMouseHoveringAnyWindow() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017)
//static inline bool IsMouseHoveringWindow() { return IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); } // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017)
//static inline bool CollapsingHeader(char* label, const char* str_id, bool framed = true, bool default_open = false) { return CollapsingHeader(label, (default_open ? (1 << 5) : 0)); } // OBSOLETED in 1.49
//static inline ImFont*GetWindowFont() { return GetFont(); } // OBSOLETED in 1.48
//static inline float GetWindowFontSize() { return GetFontSize(); } // OBSOLETED in 1.48
//static inline void SetScrollPosHere() { SetScrollHere(); } // OBSOLETED in 1.42
} }
// OBSOLETED in 1.82 (from Mars 2021): flags for AddRect(), AddRectFilled(), AddImageRounded(), PathRect() // OBSOLETED in 1.82 (from Mars 2021): flags for AddRect(), AddRectFilled(), AddImageRounded(), PathRect()

View File

@ -193,7 +193,7 @@ static void ShowExampleMenuFile();
static void HelpMarker(const char* desc) static void HelpMarker(const char* desc)
{ {
ImGui::TextDisabled("(?)"); ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort))
{ {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
@ -691,22 +691,6 @@ static void ShowDemoWindowWidgets()
ImGui::SameLine(); ImGui::SameLine();
ImGui::Text("%d", counter); ImGui::Text("%d", counter);
IMGUI_DEMO_MARKER("Widgets/Basic/Tooltips");
ImGui::Text("Hover over me");
if (ImGui::IsItemHovered())
ImGui::SetTooltip("I am a tooltip");
ImGui::SameLine();
ImGui::Text("- or me");
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("I am a fancy tooltip");
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
ImGui::EndTooltip();
}
ImGui::Separator(); ImGui::Separator();
ImGui::LabelText("label", "Value"); ImGui::LabelText("label", "Value");
@ -830,6 +814,40 @@ static void ShowDemoWindowWidgets()
"Using the simplified one-liner ListBox API here.\nRefer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API."); "Using the simplified one-liner ListBox API here.\nRefer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.");
} }
{
// Tooltips
IMGUI_DEMO_MARKER("Widgets/Basic/Tooltips");
ImGui::AlignTextToFramePadding();
ImGui::Text("Tooltips:");
ImGui::SameLine();
ImGui::Button("Button");
if (ImGui::IsItemHovered())
ImGui::SetTooltip("I am a tooltip");
ImGui::SameLine();
ImGui::Button("Fancy");
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("I am a fancy tooltip");
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime()));
ImGui::EndTooltip();
}
ImGui::SameLine();
ImGui::Button("Delayed");
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal)) // Delay best used on items that highlight on hover, so this not a great example!
ImGui::SetTooltip("I am a tooltip with a delay.");
ImGui::SameLine();
HelpMarker(
"Tooltip are created by using the IsItemHovered() function over any kind of item.");
}
ImGui::TreePop(); ImGui::TreePop();
} }
@ -2404,6 +2422,10 @@ static void ShowDemoWindowWidgets()
if (item_type == 14){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", &current, items, IM_ARRAYSIZE(items)); } if (item_type == 14){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", &current, items, IM_ARRAYSIZE(items)); }
if (item_type == 15){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } if (item_type == 15){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
bool hovered_delay_none = ImGui::IsItemHovered();
bool hovered_delay_short = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort);
bool hovered_delay_normal = ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal);
// Display the values of IsItemHovered() and other common item state functions. // Display the values of IsItemHovered() and other common item state functions.
// Note that the ImGuiHoveredFlags_XXX flags can be combined. // Note that the ImGuiHoveredFlags_XXX flags can be combined.
// Because BulletText is an item itself and that would affect the output of IsItemXXX functions, // Because BulletText is an item itself and that would affect the output of IsItemXXX functions,
@ -2448,6 +2470,8 @@ static void ShowDemoWindowWidgets()
ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y, ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y,
ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y
); );
ImGui::BulletText(
"w/ Hovering Delay: None = %d, Fast %d, Normal = %d", hovered_delay_none, hovered_delay_short, hovered_delay_normal);
if (item_disabled) if (item_disabled)
ImGui::EndDisabled(); ImGui::EndDisabled();
@ -7359,53 +7383,84 @@ static void ShowExampleAppAutoResize(bool* p_open)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Demonstrate creating a window with custom resize constraints. // Demonstrate creating a window with custom resize constraints.
// Note that size constraints currently don't work on a docked window (when in 'docking' branch)
static void ShowExampleAppConstrainedResize(bool* p_open) static void ShowExampleAppConstrainedResize(bool* p_open)
{ {
struct CustomConstraints struct CustomConstraints
{ {
// Helper functions to demonstrate programmatic constraints // Helper functions to demonstrate programmatic constraints
static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y); } // FIXME: This doesn't take account of decoration size (e.g. title bar), library should make this easier.
static void Step(ImGuiSizeCallbackData* data) { float step = (float)(int)(intptr_t)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); } static void AspectRatio(ImGuiSizeCallbackData* data) { float aspect_ratio = *(float*)data->UserData; data->DesiredSize.x = IM_MAX(data->CurrentSize.x, data->CurrentSize.y); data->DesiredSize.y = (float)(int)(data->DesiredSize.x / aspect_ratio); }
static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->CurrentSize.x, data->CurrentSize.y); }
static void Step(ImGuiSizeCallbackData* data) { float step = *(float*)data->UserData; data->DesiredSize = ImVec2((int)(data->CurrentSize.x / step + 0.5f) * step, (int)(data->CurrentSize.y / step + 0.5f) * step); }
}; };
const char* test_desc[] = const char* test_desc[] =
{ {
"Between 100x100 and 500x500",
"At least 100x100",
"Resize vertical only", "Resize vertical only",
"Resize horizontal only", "Resize horizontal only",
"Width > 100, Height > 100", "Width Between 400 and 500",
"Width 400-500", "Custom: Aspect Ratio 16:9",
"Height 400-500",
"Custom: Always Square", "Custom: Always Square",
"Custom: Fixed Steps (100)", "Custom: Fixed Steps (100)",
}; };
// Options
static bool auto_resize = false; static bool auto_resize = false;
static int type = 0; static bool window_padding = true;
static int type = 5; // Aspect Ratio
static int display_lines = 10; static int display_lines = 10;
if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only
if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only
if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width 400-500
if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500)); // Height 400-500
if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square
if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step
ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0; // Submit constraint
if (ImGui::Begin("Example: Constrained Resize", p_open, flags)) float aspect_ratio = 16.0f / 9.0f;
float fixed_step = 100.0f;
if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(500, 500)); // Between 100x100 and 500x500
if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX)); // Vertical only
if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1)); // Horizontal only
if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1)); // Width Between and 400 and 500
if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, (void*)&aspect_ratio); // Aspect ratio
if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square); // Always Square
if (type == 7) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)&fixed_step); // Fixed Step
// Submit window
if (!window_padding)
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
const ImGuiWindowFlags window_flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
const bool window_open = ImGui::Begin("Example: Constrained Resize", p_open, window_flags);
if (!window_padding)
ImGui::PopStyleVar();
if (window_open)
{ {
IMGUI_DEMO_MARKER("Examples/Constrained Resizing window"); IMGUI_DEMO_MARKER("Examples/Constrained Resizing window");
if (ImGui::IsWindowDocked()) if (ImGui::GetIO().KeyShift)
ImGui::Text("Warning: Sizing Constraints won't work if the window is docked!"); {
if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine(); // Display a dummy viewport (in your real app you would likely use ImageButton() to display a texture.
if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine(); ImVec2 avail_size = ImGui::GetContentRegionAvail();
if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); } ImVec2 pos = ImGui::GetCursorScreenPos();
ImGui::SetNextItemWidth(200); ImGui::ColorButton("viewport", ImVec4(0.5f, 0.2f, 0.5f, 1.0f), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop, avail_size);
ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc)); ImGui::SetCursorScreenPos(ImVec2(pos.x + 10, pos.y + 10));
ImGui::SetNextItemWidth(200); ImGui::Text("%.2f x %.2f", avail_size.x, avail_size.y);
ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100); }
ImGui::Checkbox("Auto-resize", &auto_resize); else
for (int i = 0; i < display_lines; i++) {
ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, ""); ImGui::Text("(Hold SHIFT to display a dummy viewport)");
if (ImGui::IsWindowDocked())
ImGui::Text("Warning: Sizing Constraints won't work if the window is docked!");
if (ImGui::Button("Set 200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
if (ImGui::Button("Set 500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
if (ImGui::Button("Set 800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc));
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 20);
ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100);
ImGui::Checkbox("Auto-resize", &auto_resize);
ImGui::Checkbox("Window padding", &window_padding);
for (int i = 0; i < display_lines; i++)
ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, "");
}
} }
ImGui::End(); ImGui::End();
} }
@ -7418,29 +7473,35 @@ static void ShowExampleAppConstrainedResize(bool* p_open)
// + a context-menu to choose which corner of the screen to use. // + a context-menu to choose which corner of the screen to use.
static void ShowExampleAppSimpleOverlay(bool* p_open) static void ShowExampleAppSimpleOverlay(bool* p_open)
{ {
static int corner = 0; static int location = 0;
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav; ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
if (corner != -1) if (location >= 0)
{ {
const float PAD = 10.0f; const float PAD = 10.0f;
const ImGuiViewport* viewport = ImGui::GetMainViewport(); const ImGuiViewport* viewport = ImGui::GetMainViewport();
ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any! ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any!
ImVec2 work_size = viewport->WorkSize; ImVec2 work_size = viewport->WorkSize;
ImVec2 window_pos, window_pos_pivot; ImVec2 window_pos, window_pos_pivot;
window_pos.x = (corner & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD); window_pos.x = (location & 1) ? (work_pos.x + work_size.x - PAD) : (work_pos.x + PAD);
window_pos.y = (corner & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD); window_pos.y = (location & 2) ? (work_pos.y + work_size.y - PAD) : (work_pos.y + PAD);
window_pos_pivot.x = (corner & 1) ? 1.0f : 0.0f; window_pos_pivot.x = (location & 1) ? 1.0f : 0.0f;
window_pos_pivot.y = (corner & 2) ? 1.0f : 0.0f; window_pos_pivot.y = (location & 2) ? 1.0f : 0.0f;
ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot); ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
ImGui::SetNextWindowViewport(viewport->ID); ImGui::SetNextWindowViewport(viewport->ID);
window_flags |= ImGuiWindowFlags_NoMove; window_flags |= ImGuiWindowFlags_NoMove;
} }
else if (location == -2)
{
// Center window
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
window_flags |= ImGuiWindowFlags_NoMove;
}
ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
if (ImGui::Begin("Example: Simple overlay", p_open, window_flags)) if (ImGui::Begin("Example: Simple overlay", p_open, window_flags))
{ {
IMGUI_DEMO_MARKER("Examples/Simple Overlay"); IMGUI_DEMO_MARKER("Examples/Simple Overlay");
ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)"); ImGui::Text("Simple overlay\n" "(right-click to change position)");
ImGui::Separator(); ImGui::Separator();
if (ImGui::IsMousePosValid()) if (ImGui::IsMousePosValid())
ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y); ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
@ -7448,11 +7509,12 @@ static void ShowExampleAppSimpleOverlay(bool* p_open)
ImGui::Text("Mouse Position: <invalid>"); ImGui::Text("Mouse Position: <invalid>");
if (ImGui::BeginPopupContextWindow()) if (ImGui::BeginPopupContextWindow())
{ {
if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1; if (ImGui::MenuItem("Custom", NULL, location == -1)) location = -1;
if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0; if (ImGui::MenuItem("Center", NULL, location == -2)) location = -2;
if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1; if (ImGui::MenuItem("Top-left", NULL, location == 0)) location = 0;
if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2; if (ImGui::MenuItem("Top-right", NULL, location == 1)) location = 1;
if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3; if (ImGui::MenuItem("Bottom-left", NULL, location == 2)) location = 2;
if (ImGui::MenuItem("Bottom-right", NULL, location == 3)) location = 3;
if (p_open && ImGui::MenuItem("Close")) *p_open = false; if (p_open && ImGui::MenuItem("Close")) *p_open = false;
ImGui::EndPopup(); ImGui::EndPopup();
} }

View File

@ -1058,7 +1058,7 @@ struct ImGuiPopupData
{ {
ImGuiID PopupId; // Set on OpenPopup() ImGuiID PopupId; // Set on OpenPopup()
ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup() ImGuiWindow* Window; // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup()
ImGuiWindow* SourceWindow; // Set on OpenPopup() copy of NavWindow at the time of opening the popup ImGuiWindow* BackupNavWindow;// Set on OpenPopup(), a NavWindow that will be restored on popup close
int ParentNavLayer; // Resolved on BeginPopup(). Actually a ImGuiNavLayer type (declared down below), initialized to -1 which is not part of an enum, but serves well-enough as "not any of layers" value int ParentNavLayer; // Resolved on BeginPopup(). Actually a ImGuiNavLayer type (declared down below), initialized to -1 which is not part of an enum, but serves well-enough as "not any of layers" value
int OpenFrameCount; // Set on OpenPopup() int OpenFrameCount; // Set on OpenPopup()
ImGuiID OpenParentId; // Set on OpenPopup(), we need this to differentiate multiple menu sets from each others (e.g. inside menu bar vs loose menu items) ImGuiID OpenParentId; // Set on OpenPopup(), we need this to differentiate multiple menu sets from each others (e.g. inside menu bar vs loose menu items)
@ -1971,6 +1971,12 @@ struct ImGuiContext
ImVector<ImGuiPtrOrIndex> CurrentTabBarStack; ImVector<ImGuiPtrOrIndex> CurrentTabBarStack;
ImVector<ImGuiShrinkWidthItem> ShrinkWidthBuffer; ImVector<ImGuiShrinkWidthItem> ShrinkWidthBuffer;
// Hover Delay system
ImGuiID HoverDelayId;
ImGuiID HoverDelayIdPreviousFrame;
float HoverDelayTimer; // Currently used IsItemHovered(), generally inferred from g.HoveredIdTimer but kept uncleared until clear timer elapse.
float HoverDelayClearTimer; // Currently used IsItemHovered(): grace time before g.TooltipHoverTimer gets cleared.
// Widget state // Widget state
ImVec2 MouseLastValidPos; ImVec2 MouseLastValidPos;
ImGuiInputTextState InputTextState; ImGuiInputTextState InputTextState;
@ -1992,7 +1998,6 @@ struct ImGuiContext
float DisabledAlphaBackup; // Backup for style.Alpha for BeginDisabled() float DisabledAlphaBackup; // Backup for style.Alpha for BeginDisabled()
short DisabledStackSize; short DisabledStackSize;
short TooltipOverrideCount; short TooltipOverrideCount;
float TooltipSlowDelay; // Time before slow tooltips appears (FIXME: This is temporary until we merge in tooltip timer+priority work)
ImVector<char> ClipboardHandlerData; // If no custom clipboard handler is defined ImVector<char> ClipboardHandlerData; // If no custom clipboard handler is defined
ImVector<ImGuiID> MenusIdSubmittedThisFrame; // A list of menu IDs that were rendered at least once ImVector<ImGuiID> MenusIdSubmittedThisFrame; // A list of menu IDs that were rendered at least once
@ -2165,6 +2170,9 @@ struct ImGuiContext
TablesTempDataStacked = 0; TablesTempDataStacked = 0;
CurrentTabBar = NULL; CurrentTabBar = NULL;
HoverDelayId = HoverDelayIdPreviousFrame = 0;
HoverDelayTimer = HoverDelayClearTimer = 0.0f;
TempInputId = 0; TempInputId = 0;
ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_; ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_;
ColorEditLastHue = ColorEditLastSat = 0.0f; ColorEditLastHue = ColorEditLastSat = 0.0f;
@ -2175,11 +2183,10 @@ struct ImGuiContext
DragCurrentAccumDirty = false; DragCurrentAccumDirty = false;
DragCurrentAccum = 0.0f; DragCurrentAccum = 0.0f;
DragSpeedDefaultRatio = 1.0f / 100.0f; DragSpeedDefaultRatio = 1.0f / 100.0f;
ScrollbarClickDeltaToGrabCenter = 0.0f;
DisabledAlphaBackup = 0.0f; DisabledAlphaBackup = 0.0f;
DisabledStackSize = 0; DisabledStackSize = 0;
ScrollbarClickDeltaToGrabCenter = 0.0f;
TooltipOverrideCount = 0; TooltipOverrideCount = 0;
TooltipSlowDelay = 0.50f;
PlatformImeData.InputPos = ImVec2(0.0f, 0.0f); PlatformImeData.InputPos = ImVec2(0.0f, 0.0f);
PlatformImeDataPrev.InputPos = ImVec2(-1.0f, -1.0f); // Different to ensure initial submission PlatformImeDataPrev.InputPos = ImVec2(-1.0f, -1.0f); // Different to ensure initial submission

View File

@ -2994,7 +2994,7 @@ void ImGui::TableHeader(const char* label)
RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, label_pos.y + label_height + g.Style.FramePadding.y), ellipsis_max, ellipsis_max, label, label_end, &label_size); RenderTextEllipsis(window->DrawList, label_pos, ImVec2(ellipsis_max, label_pos.y + label_height + g.Style.FramePadding.y), ellipsis_max, ellipsis_max, label, label_end, &label_size);
const bool text_clipped = label_size.x > (ellipsis_max - label_pos.x); const bool text_clipped = label_size.x > (ellipsis_max - label_pos.x);
if (text_clipped && hovered && g.HoveredIdNotActiveTimer > g.TooltipSlowDelay) if (text_clipped && hovered && g.ActiveId == 0 && IsItemHovered(ImGuiHoveredFlags_DelayNormal))
SetTooltip("%.*s", (int)(label_end - label), label); SetTooltip("%.*s", (int)(label_end - label), label);
// We don't use BeginPopupContextItem() because we want the popup to stay up even after the column is hidden // We don't use BeginPopupContextItem() because we want the popup to stay up even after the column is hidden

View File

@ -7120,26 +7120,30 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
// Close menu when not hovering it anymore unless we are moving roughly in the direction of the menu // Close menu when not hovering it anymore unless we are moving roughly in the direction of the menu
// Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive. // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive.
bool moving_toward_child_menu = false; bool moving_toward_child_menu = false;
ImGuiWindow* child_menu_window = (g.BeginPopupStack.Size < g.OpenPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].SourceWindow == window) ? g.OpenPopupStack[g.BeginPopupStack.Size].Window : NULL; ImGuiPopupData* child_popup = (g.BeginPopupStack.Size < g.OpenPopupStack.Size) ? &g.OpenPopupStack[g.BeginPopupStack.Size] : NULL; // Popup candidate (testing below)
if (g.HoveredWindow == window && child_menu_window != NULL && !(window->Flags & ImGuiWindowFlags_MenuBar)) ImGuiWindow* child_menu_window = (child_popup && child_popup->Window && child_popup->Window->ParentWindow == window) ? child_popup->Window : NULL;
if (g.HoveredWindow == window && child_menu_window != NULL)
{ {
float ref_unit = g.FontSize; // FIXME-DPI float ref_unit = g.FontSize; // FIXME-DPI
float child_dir = (window->Pos.x < child_menu_window->Pos.x) ? 1.0f : -1.0f;
ImRect next_window_rect = child_menu_window->Rect(); ImRect next_window_rect = child_menu_window->Rect();
ImVec2 ta = (g.IO.MousePos - g.IO.MouseDelta); ImVec2 ta = (g.IO.MousePos - g.IO.MouseDelta);
ImVec2 tb = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR(); ImVec2 tb = (child_dir > 0.0f) ? next_window_rect.GetTL() : next_window_rect.GetTR();
ImVec2 tc = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR(); ImVec2 tc = (child_dir > 0.0f) ? next_window_rect.GetBL() : next_window_rect.GetBR();
float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, ref_unit * 0.5f, ref_unit * 2.5f); // add a bit of extra slack. float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, ref_unit * 0.5f, ref_unit * 2.5f); // add a bit of extra slack.
ta.x += (window->Pos.x < child_menu_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues (FIXME: ??) ta.x += child_dir * -0.5f;
tb.x += child_dir * ref_unit;
tc.x += child_dir * ref_unit;
tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -ref_unit * 8.0f); // triangle has maximum height to limit the slope and the bias toward large sub-menus tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -ref_unit * 8.0f); // triangle has maximum height to limit the slope and the bias toward large sub-menus
tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +ref_unit * 8.0f); tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +ref_unit * 8.0f);
moving_toward_child_menu = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos); moving_toward_child_menu = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos);
//GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_toward_other_child_menu ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); // [DEBUG] //GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_toward_child_menu ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); // [DEBUG]
} }
// The 'HovereWindow == window' check creates an inconsistency (e.g. moving away from menu slowly tends to hit same window, whereas moving away fast does not) // The 'HovereWindow == window' check creates an inconsistency (e.g. moving away from menu slowly tends to hit same window, whereas moving away fast does not)
// But we also need to not close the top-menu menu when moving over void. Perhaps we should extend the triangle check to a larger polygon. // But we also need to not close the top-menu menu when moving over void. Perhaps we should extend the triangle check to a larger polygon.
// (Remember to test this on BeginPopup("A")->BeginMenu("B") sequence which behaves slightly differently as B isn't a Child of A and hovering isn't shared.) // (Remember to test this on BeginPopup("A")->BeginMenu("B") sequence which behaves slightly differently as B isn't a Child of A and hovering isn't shared.)
if (menu_is_open && !hovered && g.HoveredWindow == window && !moving_toward_child_menu) if (menu_is_open && !hovered && g.HoveredWindow == window && !moving_toward_child_menu && !g.NavDisableMouseHover)
want_close = true; want_close = true;
// Open // Open
@ -7216,6 +7220,7 @@ void ImGui::EndMenu()
// Nav: When a left move request _within our child menu_ failed, close ourselves (the _parent_ menu). // Nav: When a left move request _within our child menu_ failed, close ourselves (the _parent_ menu).
// A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs. // A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs.
// However, it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction. // However, it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction.
// FIXME: This doesn't work if the parent BeginMenu() is not on a menu.
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
if (g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical) if (g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical)
@ -8419,9 +8424,10 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
// (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores) // (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores)
// FIXME: This is a mess. // FIXME: This is a mess.
// FIXME: We may want disabled tab to still display the tooltip? // FIXME: We may want disabled tab to still display the tooltip?
if (text_clipped && g.HoveredId == id && !held && g.HoveredIdNotActiveTimer > g.TooltipSlowDelay && IsItemHovered()) if (text_clipped && g.HoveredId == id && !held)
if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip)) if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip))
SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label); if (IsItemHovered(ImGuiHoveredFlags_DelayNormal))
SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label);
IM_ASSERT(!is_tab_button || !(tab_bar->SelectedTabId == tab->ID && is_tab_button)); // TabItemButton should not be selected IM_ASSERT(!is_tab_button || !(tab_bar->SelectedTabId == tab->ID && is_tab_button)); // TabItemButton should not be selected
if (is_tab_button) if (is_tab_button)