MultiSelect: Maintain NavIdSelected for user. Simplify deletion demo.

This commit is contained in:
ocornut 2023-06-02 15:17:01 +02:00
parent 9223ffc255
commit df1eeb9a20
4 changed files with 27 additions and 51 deletions

View File

@ -2784,6 +2784,7 @@ struct ImGuiMultiSelectIO
bool RangeSelected; // / / ms:w, app:r // End: parameter from RequestSetRange request. true = Select Range, false = Unselect Range.
bool RangeSrcPassedBy; // / ms:rw app:w / ms:r // (If using clipper) Need to be set by app/user if RangeSrcItem was part of the clipped set before submitting the visible items. Ignore if not clipping.
bool RangeSrcReset; // / app:w / ms:r // (If using deletion) Set before EndMultiSelect() to reset ResetSrcItem (e.g. if deleted selection).
bool NavIdSelected; // ms:w, app:r / / // (If using deletion) Last known selection state for NavId (if part of submitted items).
void* NavIdItem; // ms:w, app:r / / ms:w app:r // (If using deletion) Last known SetNextItemSelectionUserData() value for NavId (if part of submitted items)
ImGuiMultiSelectIO() { Clear(); }

View File

@ -2821,8 +2821,7 @@ struct ExampleSelection
template<typename ITEM_TYPE>
int CalcNextFocusIdxForBeforeDeletion(ImGuiMultiSelectIO* ms_io, ImVector<ITEM_TYPE>& items)
{
// FIXME-MULTISELECT: Need to avoid auto-select, aka SetKeyboardFocusHere() into public facing FocusItem() that doesn't activate.
if (!GetSelected((int)(intptr_t)ms_io->NavIdItem))
if (ms_io->NavIdSelected == false)
return (int)(intptr_t)ms_io->NavIdItem;
// Return first unselected item after RangeSrcItem
@ -2996,6 +2995,7 @@ static void ShowDemoWindowMultiSelect()
// FIXME-MULTISELECT: Shortcut(). Hard to demo this? May be helpful to send a helper/optional "delete" signal.
// FIXME-MULTISELECT: may turn into 'ms_io->RequestDelete' -> need HasSelection passed.
// FIXME-MULTISELECT: Test with intermediary modal dialog.
// FIXME-MULTISELECT: If pressing Delete + another key we have slightly ambiguous behavior.
const bool want_delete = (selection.GetSize() > 0) && ImGui::IsWindowFocused() && ImGui::IsKeyPressed(ImGuiKey_Delete);
const int next_focus_item_idx = want_delete ? selection.CalcNextFocusIdxForBeforeDeletion(ms_io, items) : -1;
//if (want_delete) { IMGUI_DEBUG_LOG("next_focus_item_idx = %d\n", next_focus_item_idx); }
@ -3017,34 +3017,13 @@ static void ShowDemoWindowMultiSelect()
ImGui::SetKeyboardFocusHere(-1); // FIXME-MULTISELECT: Need to avoid selection.
}
#if 0
bool nav_id_was_selected = selection.GetSelected((int)(intptr_t)ms_io->NavIdData);
if (want_delete && !nav_id_was_selected) // FIXME: would work without '&& !nav_id_was_selected' just take an extra frame to recover RangeSrc
// Apply multi-select requests
if (want_delete && ms_io->NavIdSelected == false) // FIXME: would work without '&& !NavIdSelected' just take an extra frame to recover RangeSrc
ms_io->RangeSrcReset = true;
ms_io = ImGui::EndMultiSelect();
selection.ApplyRequests(ms_io, items.Size);
if (want_delete)
selection.ApplyDeletion(ms_io, items, nav_id_was_selected ? next_focus_item_idx : -1);
#else
// Apply multi-select requests
if (want_delete)
{
// When deleting: this handle details for scrolling/focus/selection to be updated correctly without any glitches.
bool nav_id_was_selected = selection.GetSelected((int)(intptr_t)ms_io->NavIdItem);
if (!nav_id_was_selected) // FIXME: would work without '&& !nav_id_was_selected' just take an extra frame to recover RangeSrc
ms_io->RangeSrcReset = true;
ms_io = ImGui::EndMultiSelect();
selection.ApplyRequests(ms_io, items.Size);
selection.ApplyDeletion(ms_io, items, nav_id_was_selected ? next_focus_item_idx : -1);
}
else
{
// Simple version
ms_io = ImGui::EndMultiSelect();
selection.ApplyRequests(ms_io, items.Size);
}
#endif
selection.ApplyDeletion(ms_io, items, ms_io->NavIdSelected ? next_focus_item_idx : -1);
ImGui::EndListBox();
}
@ -3267,21 +3246,12 @@ static void ShowDemoWindowMultiSelect()
}
// Apply multi-select requests
#if 1
// full correct
bool nav_id_was_selected = selection.GetSelected((int)(intptr_t)ms_io->NavIdItem);
if (want_delete && !nav_id_was_selected)
if (want_delete && ms_io->NavIdSelected == false)
ms_io->RangeSrcReset = true;
ms_io = ImGui::EndMultiSelect();
selection.ApplyRequests(ms_io, items.Size);
if (want_delete)
selection.ApplyDeletion(ms_io, items, nav_id_was_selected ? next_focus_item_idx : -1);
#else
ms_io = ImGui::EndMultiSelect();
selection.ApplyRequests(ms_io, items.Size);
if (want_delete)
selection.ApplyDeletion(ms_io, items, nav_id_was_selected ? next_focus_item_idx : -1);
#endif
selection.ApplyDeletion(ms_io, items, ms_io->NavIdSelected ? next_focus_item_idx : -1);
if (widget_type == WidgetType_TreeNode)
ImGui::PopStyleVar();

View File

@ -1740,11 +1740,12 @@ struct IMGUI_API ImGuiMultiSelectState
ImGuiID ID;
int LastFrameActive; // Last used frame-count, for GC.
ImS8 RangeSelected; // -1 (don't have) or true/false
ImS8 NavIdSelected; // -1 (don't have) or true/false
void* RangeSrcItem; //
void* NavIdItem; // SetNextItemSelectionUserData() value for NavId (if part of submitted items)
ImGuiMultiSelectState() { Init(0); }
void Init(ImGuiID id) { Window = NULL; ID = id; LastFrameActive = 0; RangeSelected = -1; RangeSrcItem = NavIdItem = (void*)-1; }
void Init(ImGuiID id) { Window = NULL; ID = id; LastFrameActive = 0; RangeSelected = NavIdSelected = -1; RangeSrcItem = NavIdItem = (void*)-1; }
};
#endif // #ifdef IMGUI_HAS_MULTI_SELECT

View File

@ -7160,8 +7160,10 @@ ImGuiMultiSelectIO* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags)
// FIXME-MULTISELECT: Set for the purpose of user calling RangeSrcPassedBy
// FIXME-MULTISELECT: Index vs Pointers.
ms->BeginIO.RangeSrcItem = storage->RangeSrcItem;
ms->BeginIO.NavIdItem = storage->NavIdItem;
// We want EndIO's NavIdItem/NavIdSelected to match BeginIO's one, so the value never changes after EndMultiSelect()
ms->BeginIO.RangeSrcItem = ms->EndIO.RangeSrcItem = storage->RangeSrcItem;
ms->BeginIO.NavIdItem = ms->EndIO.NavIdItem = storage->NavIdItem;
ms->BeginIO.NavIdSelected = ms->EndIO.NavIdSelected = (storage->NavIdSelected == 1) ? true : false;
if (!ms->IsFocused)
return &ms->BeginIO; // This is cleared at this point.
@ -7216,13 +7218,14 @@ ImGuiMultiSelectIO* ImGui::EndMultiSelect()
{
if (ms->BeginIO.RangeSrcReset || (ms->BeginIO.RangeSrcPassedBy == false && ms->BeginIO.RangeSrcItem != (void*)-1))
{
IMGUI_DEBUG_LOG_SELECTION("[selection] EndMultiSelect: Reset RangeSrc.\n"); // Will set be to NavId.
IMGUI_DEBUG_LOG_SELECTION("[selection] EndMultiSelect: Reset RangeSrcItem.\n"); // Will set be to NavId.
ms->Storage->RangeSrcItem = (void*)-1;
}
if (ms->NavIdPassedBy == false && ms->Storage->NavIdItem != (void*)-1)
{
IMGUI_DEBUG_LOG_SELECTION("[selection] EndMultiSelect: Reset NavIdData.\n");
IMGUI_DEBUG_LOG_SELECTION("[selection] EndMultiSelect: Reset NavIdItem.\n");
ms->Storage->NavIdItem = (void*)-1;
ms->Storage->NavIdSelected = -1;
}
}
@ -7328,11 +7331,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
ImGuiMultiSelectTempData* ms = g.CurrentMultiSelect;
ImGuiMultiSelectState* storage = ms->Storage;
if (pressed)
{
ms->IsFocused = true;
//if (storage->Id != ms->FocusScopeId)
// storage->Init(ms->FocusScopeId);
}
if (!ms->IsFocused)
return;
@ -7342,15 +7341,11 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
bool is_ctrl = (ms->KeyMods & ImGuiMod_Ctrl) != 0;
bool is_shift = (ms->KeyMods & ImGuiMod_Shift) != 0;
if (g.NavId == id)
storage->NavIdItem = item_data;
if (g.NavId == id && storage->RangeSrcItem == (void*)-1)
{
storage->RangeSrcItem = item_data;
storage->RangeSelected = selected; // Will be updated at the end of this function anyway.
}
if (storage->NavIdItem == item_data)
ms->NavIdPassedBy = true;
// Auto-select as you navigate a list
if (g.NavJustMovedToId == id)
@ -7446,6 +7441,15 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
ms->EndIO.RangeSelected = selected;
}
// Update/store the selection state of focused item
if (g.NavId == id)
{
storage->NavIdItem = item_data;
storage->NavIdSelected = selected ? 1 : 0;
}
if (storage->NavIdItem == item_data)
ms->NavIdPassedBy = true;
*p_selected = selected;
*p_pressed = pressed;
}
@ -7461,7 +7465,7 @@ void ImGui::DebugNodeMultiSelectState(ImGuiMultiSelectState* storage)
return;
Text("ID = 0x%08X", storage->ID);
Text("RangeSrcItem = %p, RangeSelected = %d", storage->RangeSrcItem, storage->RangeSelected);
Text("NavIdItem = %p", storage->NavIdItem);
Text("NavIdData = %p, NavIdSelected = %d", storage->NavIdItem, storage->NavIdSelected);
TreePop();
#else
IM_UNUSED(storage);