From 4dee919bc0decdfc1f4f2c46ac0225ff276c8d18 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 28 Jun 2023 13:47:57 +0200 Subject: [PATCH] (Breaking) Internals: added ImGuiItemFlags param to ItemHoverable(), so it can be called from ButtonBehavior() not following an ItemAdd(). This also allow moving AllowOverlap logic from ButtonBehavior() to ItemHoverable(), allowing other widgets to honor it. (#6512, #3909, #517) --- imgui.cpp | 6 +++--- imgui_internal.h | 2 +- imgui_tables.cpp | 2 +- imgui_widgets.cpp | 33 +++++++++++++++++---------------- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 87d8911a5..cb61b31e7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4038,7 +4038,8 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags) } // Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered(). -bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) +// (this does not rely on LastItemData it can be called from a ButtonBehavior() call not following an ItemAdd() call) +bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; @@ -4053,7 +4054,6 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id) return false; // Done with rectangle culling so we can perform heavier checks now. - ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); if (!(item_flags & ImGuiItemFlags_NoWindowHoverableCheck) && !IsWindowContentHoverable(window, ImGuiHoveredFlags_None)) { g.HoveredIdDisabled = true; @@ -12360,7 +12360,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags) // Rely on keeping other window->LastItemXXX fields intact. source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect); KeepAliveID(source_id); - bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id); + bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id, g.LastItemData.InFlags); if (is_hovered && g.IO.MouseClicked[mouse_button]) { SetActiveID(source_id, window); diff --git a/imgui_internal.h b/imgui_internal.h index 79aeff1cd..cb1d1b12f 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2876,7 +2876,7 @@ namespace ImGui IMGUI_API void ItemSize(const ImVec2& size, float text_baseline_y = -1.0f); inline void ItemSize(const ImRect& bb, float text_baseline_y = -1.0f) { ItemSize(bb.GetSize(), text_baseline_y); } // FIXME: This is a misleading API since we expect CursorPos to be bb.Min. IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL, ImGuiItemFlags extra_flags = 0); - IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id); + IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flags); IMGUI_API bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags = 0); IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id); IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index e4c5269c6..c8059ec33 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -976,7 +976,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) const ImRect mouse_hit_rect(table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.Max.x, ImMax(table->OuterRect.Max.y, table->OuterRect.Min.y + table_instance->LastOuterHeight)); const ImGuiID backup_active_id = g.ActiveId; g.ActiveId = 0; - const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0); + const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0, ImGuiItemFlags_None); g.ActiveId = backup_active_id; // [Part 6] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index ba5d89830..2476a160f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -493,11 +493,12 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool flags |= ImGuiButtonFlags_PressedOnDefault_; // Default behavior inherited from item flags - const ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); - if (item_flags & ImGuiItemFlags_ButtonRepeat) - flags |= ImGuiButtonFlags_Repeat; - if (item_flags & ImGuiItemflags_AllowOverlap) - flags |= ImGuiButtonFlags_AllowOverlap; + // Note that _both_ ButtonFlags and ItemFlags are valid sources, so copy one into the item_flags and only check that. + ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); + if (flags & ImGuiButtonFlags_AllowOverlap) + item_flags |= ImGuiItemflags_AllowOverlap; + if (flags & ImGuiButtonFlags_Repeat) + item_flags |= ImGuiItemFlags_ButtonRepeat; ImGuiWindow* backup_hovered_window = g.HoveredWindow; const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindow == window; @@ -511,7 +512,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool #endif bool pressed = false; - bool hovered = ItemHoverable(bb, id); + bool hovered = ItemHoverable(bb, id, item_flags); // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button if (g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) @@ -531,7 +532,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool g.HoveredWindow = backup_hovered_window; // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one. - if (flags & ImGuiButtonFlags_AllowOverlap) + if (item_flags & ImGuiItemflags_AllowOverlap) { if (hovered && g.HoveredIdPreviousFrame != id) hovered = false; @@ -587,7 +588,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool { if (mouse_button_released != -1) { - const bool has_repeated_at_least_once = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay; // Repeat mode trumps on release behavior + const bool has_repeated_at_least_once = (item_flags & ImGuiItemFlags_ButtonRepeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay; // Repeat mode trumps on release behavior if (!has_repeated_at_least_once) pressed = true; if (!(flags & ImGuiButtonFlags_NoNavFocus)) @@ -598,7 +599,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above). // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings. - if (g.ActiveId == id && (flags & ImGuiButtonFlags_Repeat)) + if (g.ActiveId == id && (item_flags & ImGuiItemFlags_ButtonRepeat)) if (g.IO.MouseDownDuration[g.ActiveIdMouseButton] > 0.0f && IsMouseClicked(g.ActiveIdMouseButton, test_owner_id, ImGuiInputFlags_Repeat)) pressed = true; } @@ -616,7 +617,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool { bool nav_activated_by_code = (g.NavActivateId == id); bool nav_activated_by_inputs = (g.NavActivatePressedId == id); - if (!nav_activated_by_inputs && (flags & ImGuiButtonFlags_Repeat)) + if (!nav_activated_by_inputs && (item_flags & ImGuiItemFlags_ButtonRepeat)) { // Avoid pressing multiple keys from triggering excessive amount of repeat events const ImGuiKeyData* key1 = GetKeyData(ImGuiKey_Space); @@ -663,7 +664,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool { // Report as pressed when releasing the mouse (this is the most common path) bool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseReleased[mouse_button] && g.IO.MouseClickedLastCount[mouse_button] == 2; - bool is_repeating_already = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps + bool is_repeating_already = (item_flags & ImGuiItemFlags_ButtonRepeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps bool is_button_avail_or_owned = TestKeyOwner(MouseButtonToKey(mouse_button), test_owner_id); if (!is_double_click_release && !is_repeating_already && is_button_avail_or_owned) pressed = true; @@ -2421,7 +2422,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - const bool hovered = ItemHoverable(frame_bb, id); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { @@ -3014,7 +3015,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - const bool hovered = ItemHoverable(frame_bb, id); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id); if (!temp_input_is_active) { @@ -3181,7 +3182,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d if (format == NULL) format = DataTypeGetInfo(data_type)->PrintFmt; - const bool hovered = ItemHoverable(frame_bb, id); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); const bool clicked = hovered && IsMouseClicked(0, id); if (clicked || g.NavActivateId == id) { @@ -4147,7 +4148,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ return false; item_status_flags = g.LastItemData.StatusFlags; } - const bool hovered = ItemHoverable(frame_bb, id); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); if (hovered) g.MouseCursor = ImGuiMouseCursor_TextInput; @@ -6714,7 +6715,7 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, 0, &frame_bb)) return -1; - const bool hovered = ItemHoverable(frame_bb, id); + const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags); // Determine scale from values if not specified if (scale_min == FLT_MAX || scale_max == FLT_MAX)