Internals: moved LastItem data to a shared structure (instead of one per window)

(should be a no-op as we are restoring things in Begin/End. Toward faciliate backup/restore of LastItemData and favor pulling from here instead of CurrentItemFlags, toward #211)
This commit is contained in:
ocornut
2021-07-19 21:08:22 +02:00
parent 1ad153056a
commit 6b8a059fc9
5 changed files with 159 additions and 165 deletions

View File

@ -502,7 +502,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
g.HoveredWindow = window;
#ifdef IMGUI_ENABLE_TEST_ENGINE
if (id != 0 && window->DC.LastItemId != id)
if (id != 0 && g.LastItemData.ID != id)
IMGUI_TEST_ENGINE_ITEM_ADD(bb, id);
#endif
@ -699,7 +699,7 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags
//if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
// CloseCurrentPopup();
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return pressed;
}
@ -1076,7 +1076,7 @@ bool ImGui::Checkbox(const char* label, bool* v)
ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, id))
{
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return false;
}
@ -1112,7 +1112,7 @@ bool ImGui::Checkbox(const char* label, bool* v)
if (label_size.x > 0.0f)
RenderText(label_pos, label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return pressed;
}
@ -1214,7 +1214,7 @@ bool ImGui::RadioButton(const char* label, bool active)
if (label_size.x > 0.0f)
RenderText(label_pos, label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return pressed;
}
@ -1438,7 +1438,7 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float
bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f));
ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap);
if (hovered)
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb
if (g.ActiveId != id)
SetItemAllowOverlap();
@ -1696,9 +1696,9 @@ bool ImGui::BeginComboPreview()
ImGuiWindow* window = g.CurrentWindow;
ImGuiComboPreviewData* preview_data = &g.ComboPreviewData;
if (window->SkipItems || !window->ClipRect.Overlaps(window->DC.LastItemRect)) // FIXME: Because we don't have a ImGuiItemStatusFlags_Visible flag to test last ItemAdd() result
if (window->SkipItems || !window->ClipRect.Overlaps(g.LastItemData.Rect)) // FIXME: Because we don't have a ImGuiItemStatusFlags_Visible flag to test last ItemAdd() result
return false;
IM_ASSERT(window->DC.LastItemRect.Min.x == preview_data->PreviewRect.Min.x && window->DC.LastItemRect.Min.y == preview_data->PreviewRect.Min.y); // Didn't call after BeginCombo/EndCombo block or forgot to pass ImGuiComboFlags_CustomPreview flag?
IM_ASSERT(g.LastItemData.Rect.Min.x == preview_data->PreviewRect.Min.x && g.LastItemData.Rect.Min.y == preview_data->PreviewRect.Min.y); // Didn't call after BeginCombo/EndCombo block or forgot to pass ImGuiComboFlags_CustomPreview flag?
if (!window->ClipRect.Contains(preview_data->PreviewRect)) // Narrower test (optional)
return false;
@ -1807,8 +1807,9 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
}
EndCombo();
if (value_changed)
MarkItemEdited(g.CurrentWindow->DC.LastItemId);
MarkItemEdited(g.LastItemData.ID);
return value_changed;
}
@ -2398,7 +2399,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
if (!temp_input_is_active)
{
const bool focus_requested = temp_input_allowed && (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Focused) != 0;
const bool focus_requested = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Focused) != 0;
const bool clicked = (hovered && g.IO.MouseClicked[0]);
const bool double_clicked = (hovered && g.IO.MouseDoubleClicked[0]);
if (focus_requested || clicked || double_clicked || g.NavActivateId == id || g.NavInputId == id)
@ -2447,7 +2448,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return value_changed;
}
@ -3014,7 +3015,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
if (!temp_input_is_active)
{
const bool focus_requested = temp_input_allowed && (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Focused) != 0;
const bool focus_requested = temp_input_allowed && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Focused) != 0;
const bool clicked = (hovered && g.IO.MouseClicked[0]);
if (focus_requested || clicked || g.NavActivateId == id || g.NavInputId == id)
{
@ -3059,7 +3060,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return value_changed;
}
@ -3471,7 +3472,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format);
}
if (value_changed)
MarkItemEdited(window->DC.LastItemId);
MarkItemEdited(g.LastItemData.ID);
return value_changed;
}
@ -4005,8 +4006,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
// We are only allowed to access the state if we are already the active widget.
ImGuiInputTextState* state = GetInputTextState(id);
const bool focus_requested_by_code = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_FocusedByCode) != 0;
const bool focus_requested_by_tabbing = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0;
const bool focus_requested_by_code = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByCode) != 0;
const bool focus_requested_by_tabbing = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_FocusedByTabbing) != 0;
const bool user_clicked = hovered && io.MouseClicked[0];
const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_Keyboard));
@ -4725,7 +4726,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited))
MarkItemEdited(id);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0)
return enter_pressed;
else
@ -4908,7 +4909,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
// Store current color and open a picker
g.ColorPickerRef = col_v4;
OpenPopup("picker");
SetNextWindowPos(window->DC.LastItemRect.GetBL() + ImVec2(-1, style.ItemSpacing.y));
SetNextWindowPos(g.LastItemData.Rect.GetBL() + ImVec2(-1, style.ItemSpacing.y));
}
}
if (!(flags & ImGuiColorEditFlags_NoOptions))
@ -4965,7 +4966,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
// Drag and Drop Target
// NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test.
if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget())
if ((g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget())
{
bool accepted_drag_drop = false;
if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
@ -4987,10 +4988,10 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
// When picker is being actively used, use its active id so IsItemActive() will function on ColorEdit4().
if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window)
window->DC.LastItemId = g.ActiveId;
g.LastItemData.ID = g.ActiveId;
if (value_changed)
MarkItemEdited(window->DC.LastItemId);
MarkItemEdited(g.LastItemData.ID);
return value_changed;
}
@ -5386,7 +5387,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
if (value_changed && memcmp(backup_initial_col, col, components * sizeof(float)) == 0)
value_changed = false;
if (value_changed)
MarkItemEdited(window->DC.LastItemId);
MarkItemEdited(g.LastItemData.ID);
PopID();
@ -5819,14 +5820,14 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth);
bool item_add = ItemAdd(interact_bb, id);
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDisplayRect;
window->DC.LastItemDisplayRect = frame_bb;
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect;
g.LastItemData.DisplayRect = frame_bb;
if (!item_add)
{
if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
TreePushOverrideID(id);
IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.LastItemStatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
return is_open;
}
@ -5900,7 +5901,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
{
is_open = !is_open;
window->DC.StateStorage->SetInt(id, is_open);
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledOpen;
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledOpen;
}
}
if (flags & ImGuiTreeNodeFlags_AllowItemOverlap)
@ -5908,7 +5909,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
// In this branch, TreeNodeBehavior() cannot toggle the selection so this will never trigger.
if (selected != was_selected) //-V547
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
// Render
const ImU32 text_col = GetColorU32(ImGuiCol_Text);
@ -5952,7 +5953,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
TreePushOverrideID(id);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
return is_open;
}
@ -6056,14 +6057,14 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl
// FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc.
// FIXME: CloseButton can overlap into text, need find a way to clip the text somehow.
ImGuiContext& g = *GImGui;
ImGuiLastItemDataBackup last_item_backup;
ImGuiLastItemData last_item_backup = g.LastItemData;
float button_size = g.FontSize;
float button_x = ImMax(window->DC.LastItemRect.Min.x, window->DC.LastItemRect.Max.x - g.Style.FramePadding.x * 2.0f - button_size);
float button_y = window->DC.LastItemRect.Min.y;
float button_x = ImMax(g.LastItemData.Rect.Min.x, g.LastItemData.Rect.Max.x - g.Style.FramePadding.x * 2.0f - button_size);
float button_y = g.LastItemData.Rect.Min.y;
ImGuiID close_button_id = GetIDWithSeed("#CLOSE", NULL, id);
if (CloseButton(close_button_id, ImVec2(button_x, button_y)))
*p_visible = false;
last_item_backup.Restore();
g.LastItemData = last_item_backup;
}
return is_open;
@ -6206,7 +6207,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
// In this branch, Selectable() cannot toggle the selection so this will never trigger.
if (selected != was_selected) //-V547
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
// Render
if (held && (flags & ImGuiSelectableFlags_DrawHoveredWhenHeld))
@ -6232,7 +6233,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
if (disabled_item && !disabled_global)
PopDisabled();
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return pressed;
}
@ -6365,8 +6366,9 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v
PopID();
}
EndListBox();
if (value_changed)
MarkItemEdited(g.CurrentWindow->DC.LastItemId);
MarkItemEdited(g.LastItemData.ID);
return value_changed;
}
@ -6928,7 +6930,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
if (want_close && IsPopupOpen(id, ImGuiPopupFlags_None))
ClosePopupToLevel(g.BeginPopupStack.Size, true);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0));
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0));
PopID();
if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.BeginPopupStack.Size)
@ -7025,7 +7027,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
if (selected)
RenderCheckMark(window->DrawList, pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f);
}
IMGUI_TEST_ENGINE_ITEM_INFO(window->DC.LastItemId, label, window->DC.LastItemStatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0));
IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0));
if (!enabled)
PopDisabled();
PopID();
@ -7842,7 +7844,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
// If the user called us with *p_open == false, we early out and don't render.
// We make a call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID.
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.LastItemStatusFlags);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
if (p_open && !*p_open)
{
PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true);
@ -8146,12 +8148,12 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
if (close_button_visible)
{
ImGuiLastItemDataBackup last_item_backup;
ImGuiLastItemData last_item_backup = g.LastItemData;
PushStyleVar(ImGuiStyleVar_FramePadding, frame_padding);
if (CloseButton(close_button_id, button_pos))
close_button_pressed = true;
PopStyleVar();
last_item_backup.Restore();
g.LastItemData = last_item_backup;
// Close with middle mouse button
if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2))