RangeSelect/MultiSelect: Demo: Assets Browser: added deletion support. Store ID in selection. Moved QueueDeletion to local var to emphasis that this is a user extension.

features/range_select
ocornut ago%!(EXTRA string=1 year)
parent 0ce1418295
commit c2a09cb30a
  1. 1
      imgui.h
  2. 158
      imgui_demo.cpp

@ -2808,7 +2808,6 @@ struct ImGuiSelectionBasicStorage
void AddItem(ImGuiID key) { int* p_int = Storage.GetIntRef(key, 0); if (*p_int != 0) return; *p_int = 1; Size++; } void AddItem(ImGuiID key) { int* p_int = Storage.GetIntRef(key, 0); if (*p_int != 0) return; *p_int = 1; Size++; }
void RemoveItem(ImGuiID key) { int* p_int = Storage.GetIntRef(key, 0); if (*p_int == 0) return; *p_int = 0; Size--; } void RemoveItem(ImGuiID key) { int* p_int = Storage.GetIntRef(key, 0); if (*p_int == 0) return; *p_int = 0; Size--; }
void UpdateItem(ImGuiID key, bool v) { if (v) { AddItem(key); } else { RemoveItem(key); } } void UpdateItem(ImGuiID key, bool v) { if (v) { AddItem(key); } else { RemoveItem(key); } }
int GetSize() const { return Size; }
// Methods: apply selection requests (that are coming from BeginMultiSelect() and EndMultiSelect() functions) // Methods: apply selection requests (that are coming from BeginMultiSelect() and EndMultiSelect() functions)
IMGUI_API void ApplyRequests(ImGuiMultiSelectIO* ms_io, int items_count); IMGUI_API void ApplyRequests(ImGuiMultiSelectIO* ms_io, int items_count);

@ -2753,10 +2753,9 @@ static const char* ExampleNames[] =
"Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber" "Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber"
}; };
struct ExampleSelectionStorageWithDeletion : ImGuiSelectionBasicStorage // Extra functions to add deletion support to ImGuiSelectionBasicStorage
struct ExampleSelectionWithDeletion : ImGuiSelectionBasicStorage
{ {
bool QueueDeletion = false; // Track request deleting selected items
// Find which item should be Focused after deletion. // Find which item should be Focused after deletion.
// Call _before_ item submission. Retunr an index in the before-deletion item list, your item loop should call SetKeyboardFocusHere() on it. // Call _before_ item submission. Retunr an index in the before-deletion item list, your item loop should call SetKeyboardFocusHere() on it.
// The subsequent ApplyDeletionPostLoop() code will use it to apply Selection. // The subsequent ApplyDeletionPostLoop() code will use it to apply Selection.
@ -2766,7 +2765,6 @@ struct ExampleSelectionStorageWithDeletion : ImGuiSelectionBasicStorage
// FIXME-MULTISELECT: Doesn't take account of the possibility focus target will be moved during deletion. Need refocus or scroll offset. // FIXME-MULTISELECT: Doesn't take account of the possibility focus target will be moved during deletion. Need refocus or scroll offset.
int ApplyDeletionPreLoop(ImGuiMultiSelectIO* ms_io, int items_count) int ApplyDeletionPreLoop(ImGuiMultiSelectIO* ms_io, int items_count)
{ {
QueueDeletion = false;
if (Size == 0) if (Size == 0)
return -1; return -1;
@ -3012,12 +3010,13 @@ static void ShowDemoWindowMultiSelect()
ImGui::BulletText("Ctrl modifier to preserve and toggle selection."); ImGui::BulletText("Ctrl modifier to preserve and toggle selection.");
ImGui::BulletText("Shift modifier for range selection."); ImGui::BulletText("Shift modifier for range selection.");
ImGui::BulletText("CTRL+A to select all."); ImGui::BulletText("CTRL+A to select all.");
ImGui::Text("Tip: Use 'Debug Log->Selection' to see selection requests as they happen."); ImGui::BulletText("Escape to clear selection.");
ImGui::Text("Tip: Use 'Demo->Tools->Debug Log->Selection' to see selection requests as they happen.");
// Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
const int ITEMS_COUNT = 50; const int ITEMS_COUNT = 50;
static ImGuiSelectionBasicStorage selection; static ImGuiSelectionBasicStorage selection;
ImGui::Text("Selection: %d/%d", selection.GetSize(), ITEMS_COUNT); ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
// The BeginListBox() has no actual purpose for selection logic (other that offering a scrolling region). // The BeginListBox() has no actual purpose for selection logic (other that offering a scrolling region).
if (ImGui::BeginListBox("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20))) if (ImGui::BeginListBox("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20)))
@ -3054,7 +3053,7 @@ static void ShowDemoWindowMultiSelect()
ImGui::BulletText("Using ImGuiListClipper."); ImGui::BulletText("Using ImGuiListClipper.");
const int ITEMS_COUNT = 10000; const int ITEMS_COUNT = 10000;
ImGui::Text("Selection: %d/%d", selection.GetSize(), ITEMS_COUNT); ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
if (ImGui::BeginListBox("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20))) if (ImGui::BeginListBox("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20)))
{ {
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape; ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape;
@ -3096,24 +3095,26 @@ static void ShowDemoWindowMultiSelect()
IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with deletion)"); IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with deletion)");
if (ImGui::TreeNode("Multi-Select (with deletion)")) if (ImGui::TreeNode("Multi-Select (with deletion)"))
{ {
// Intentionally separating items data from selection data! // Storing items data separately from selection data.
// But you may decide to store selection data inside your item (aka intrusive storage). // (you may decide to store selection data inside your item (aka intrusive storage) if you don't need multiple views over same items)
// Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection // Use a custom selection.Adapter: store item identifier in Selection (instead of index)
static ImVector<int> items; static ImVector<ImGuiID> items;
static ExampleSelectionStorageWithDeletion selection; static ExampleSelectionWithDeletion selection;
selection.AdapterData = (void*)&items;
selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImVector<ImGuiID>* p_items = (ImVector<ImGuiID>*)self->AdapterData; return (*p_items)[idx]; }; // Index -> ID
ImGui::Text("Adding features:"); ImGui::Text("Added features:");
ImGui::BulletText("Dynamic list with Delete key support."); ImGui::BulletText("Dynamic list with Delete key support.");
ImGui::Text("Selection size: %d/%d", selection.GetSize(), items.Size); ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
// Initialize default list with 50 items + button to add/remove items. // Initialize default list with 50 items + button to add/remove items.
static int items_next_id = 0; static ImGuiID items_next_id = 0;
if (items_next_id == 0) if (items_next_id == 0)
for (int n = 0; n < 50; n++) for (ImGuiID n = 0; n < 50; n++)
items.push_back(items_next_id++); items.push_back(items_next_id++);
if (ImGui::SmallButton("Add 20 items")) { for (int n = 0; n < 20; n++) { items.push_back(items_next_id++); } } if (ImGui::SmallButton("Add 20 items")) { for (int n = 0; n < 20; n++) { items.push_back(items_next_id++); } }
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::SmallButton("Remove 20 items")) { for (int n = IM_MIN(20, items.Size); n > 0; n--) { selection.RemoveItem((ImGuiID)(items.Size - 1)); items.pop_back(); } } // This is to test if (ImGui::SmallButton("Remove 20 items")) { for (int n = IM_MIN(20, items.Size); n > 0; n--) { selection.RemoveItem(items.back()); items.pop_back(); } }
// (1) Extra to support deletion: Submit scrolling range to avoid glitches on deletion // (1) Extra to support deletion: Submit scrolling range to avoid glitches on deletion
const float items_height = ImGui::GetTextLineHeightWithSpacing(); const float items_height = ImGui::GetTextLineHeightWithSpacing();
@ -3127,18 +3128,16 @@ static void ShowDemoWindowMultiSelect()
// FIXME-MULTISELECT: Shortcut(). Hard to demo this? May be helpful to turn into 'ms_io->RequestDelete' signal -> need HasSelection passed. // FIXME-MULTISELECT: Shortcut(). Hard to demo this? May be helpful to turn into 'ms_io->RequestDelete' signal -> need HasSelection passed.
// FIXME-MULTISELECT: If pressing Delete + another key we have ambiguous behavior. // FIXME-MULTISELECT: If pressing Delete + another key we have ambiguous behavior.
const bool want_delete = selection.QueueDeletion || ((selection.Size > 0) && ImGui::IsWindowFocused() && ImGui::IsKeyPressed(ImGuiKey_Delete)); const bool want_delete = (selection.Size > 0) && ImGui::IsWindowFocused() && ImGui::IsKeyPressed(ImGuiKey_Delete);
int item_curr_idx_to_focus = -1; const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
if (want_delete)
item_curr_idx_to_focus = selection.ApplyDeletionPreLoop(ms_io, items.Size);
for (int n = 0; n < items.Size; n++) for (int n = 0; n < items.Size; n++)
{ {
const int item_id = items[n]; const ImGuiID item_id = items[n];
char label[64]; char label[64];
sprintf(label, "Object %05d: %s", item_id, ExampleNames[item_id % IM_ARRAYSIZE(ExampleNames)]); sprintf(label, "Object %05u: %s", item_id, ExampleNames[item_id % IM_ARRAYSIZE(ExampleNames)]);
bool item_is_selected = selection.Contains((ImGuiID)n); bool item_is_selected = selection.Contains(item_id);
ImGui::SetNextItemSelectionUserData(n); ImGui::SetNextItemSelectionUserData(n);
ImGui::Selectable(label, item_is_selected); ImGui::Selectable(label, item_is_selected);
if (item_curr_idx_to_focus == n) if (item_curr_idx_to_focus == n)
@ -3197,7 +3196,7 @@ static void ShowDemoWindowMultiSelect()
selection->ApplyRequests(ms_io, ITEMS_COUNT); selection->ApplyRequests(ms_io, ITEMS_COUNT);
ImGui::SeparatorText("Selection scope"); ImGui::SeparatorText("Selection scope");
ImGui::Text("Selection size: %d/%d", selection->GetSize(), ITEMS_COUNT); ImGui::Text("Selection size: %d/%d", selection->Size, ITEMS_COUNT);
for (int n = 0; n < ITEMS_COUNT; n++) for (int n = 0; n < ITEMS_COUNT; n++)
{ {
@ -3272,9 +3271,10 @@ static void ShowDemoWindowMultiSelect()
static ImVector<int> items; static ImVector<int> items;
static int items_next_id = 0; static int items_next_id = 0;
if (items_next_id == 0) { for (int n = 0; n < 1000; n++) { items.push_back(items_next_id++); } } if (items_next_id == 0) { for (int n = 0; n < 1000; n++) { items.push_back(items_next_id++); } }
static ExampleSelectionStorageWithDeletion selection; static ExampleSelectionWithDeletion selection;
static bool request_deletion_from_menu = false; // Queue deletion triggered from context menu
ImGui::Text("Selection size: %d/%d", selection.GetSize(), items.Size); ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
const float items_height = (widget_type == WidgetType_TreeNode) ? ImGui::GetTextLineHeight() : ImGui::GetTextLineHeightWithSpacing(); const float items_height = (widget_type == WidgetType_TreeNode) ? ImGui::GetTextLineHeight() : ImGui::GetTextLineHeightWithSpacing();
ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height)); ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
@ -3288,10 +3288,9 @@ static void ShowDemoWindowMultiSelect()
selection.ApplyRequests(ms_io, items.Size); selection.ApplyRequests(ms_io, items.Size);
// FIXME-MULTISELECT: Shortcut(). Hard to demo this? May be helpful to turn into 'ms_io->RequestDelete' signal -> need HasSelection passed. // FIXME-MULTISELECT: Shortcut(). Hard to demo this? May be helpful to turn into 'ms_io->RequestDelete' signal -> need HasSelection passed.
const bool want_delete = selection.QueueDeletion || ((selection.Size > 0) && ImGui::IsWindowFocused() && ImGui::IsKeyPressed(ImGuiKey_Delete)); const bool want_delete = request_deletion_from_menu || ((selection.Size > 0) && ImGui::IsWindowFocused() && ImGui::IsKeyPressed(ImGuiKey_Delete));
int item_curr_idx_to_focus = -1; const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
if (want_delete) request_deletion_from_menu = false;
item_curr_idx_to_focus = selection.ApplyDeletionPreLoop(ms_io, items.Size);
if (show_in_table) if (show_in_table)
{ {
@ -3308,7 +3307,7 @@ static void ShowDemoWindowMultiSelect()
{ {
clipper.Begin(items.Size); clipper.Begin(items.Size);
if (item_curr_idx_to_focus != -1) if (item_curr_idx_to_focus != -1)
clipper.IncludeItemByIndex(item_curr_idx_to_focus); // Ensure focused item is not clipped clipper.IncludeItemByIndex(item_curr_idx_to_focus); // Ensure focused item is not clipped.
if (ms_io->RangeSrcItem > 0) if (ms_io->RangeSrcItem > 0)
clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped. clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
} }
@ -3397,9 +3396,10 @@ static void ShowDemoWindowMultiSelect()
// Right-click: context menu // Right-click: context menu
if (ImGui::BeginPopupContextItem()) if (ImGui::BeginPopupContextItem())
{ {
ImGui::BeginDisabled(!use_deletion || selection.GetSize() == 0); ImGui::BeginDisabled(!use_deletion || selection.Size == 0);
sprintf(label, "Delete %d item(s)###DeleteSelected", selection.GetSize()); sprintf(label, "Delete %d item(s)###DeleteSelected", selection.Size);
selection.QueueDeletion |= ImGui::Selectable(label); if (ImGui::Selectable(label))
request_deletion_from_menu = true;
ImGui::EndDisabled(); ImGui::EndDisabled();
ImGui::Selectable("Close"); ImGui::Selectable("Close");
ImGui::EndPopup(); ImGui::EndPopup();
@ -9481,11 +9481,12 @@ struct ExampleAssetsBrowser
bool StretchSpacing = true; bool StretchSpacing = true;
// State // State
ImVector<ExampleAsset> Items; ImVector<ExampleAsset> Items; // Our items
ImGuiSelectionBasicStorage Selection; ExampleSelectionWithDeletion Selection; // Our selection (ImGuiSelectionBasicStorage + helper funcs to handle deletion)
ImGuiID NextItemId = 0; ImGuiID NextItemId = 0; // Unique identifier when creating new items
bool SortDirty = false; bool RequestDelete = false; // Deferred deletion request
float ZoomWheelAccum = 0.0f; bool RequestSort = false; // Deferred sort request
float ZoomWheelAccum = 0.0f; // Mouse wheel accumulator to handle smooth wheels better
// Functions // Functions
ExampleAssetsBrowser() ExampleAssetsBrowser()
@ -9499,7 +9500,7 @@ struct ExampleAssetsBrowser
Items.reserve(Items.Size + count); Items.reserve(Items.Size + count);
for (int n = 0; n < count; n++, NextItemId++) for (int n = 0; n < count; n++, NextItemId++)
Items.push_back(ExampleAsset(NextItemId, (NextItemId % 20) < 15 ? 0 : (NextItemId % 20) < 18 ? 1 : 2)); Items.push_back(ExampleAsset(NextItemId, (NextItemId % 20) < 15 ? 0 : (NextItemId % 20) < 18 ? 1 : 2));
SortDirty = true; RequestSort = true;
} }
void ClearItems() void ClearItems()
{ {
@ -9530,6 +9531,12 @@ struct ExampleAssetsBrowser
*p_open = false; *p_open = false;
ImGui::EndMenu(); ImGui::EndMenu();
} }
if (ImGui::BeginMenu("Edit"))
{
if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
RequestDelete = true;
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Options")) if (ImGui::BeginMenu("Options"))
{ {
ImGui::PushItemWidth(ImGui::GetFontSize() * 10); ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
@ -9551,22 +9558,6 @@ struct ExampleAssetsBrowser
ImGui::EndMenuBar(); ImGui::EndMenuBar();
} }
// Zooming with CTRL+Wheel
// FIXME-MULTISELECT: Try to maintain scroll.
ImGuiIO& io = ImGui::GetIO();
if (ImGui::IsWindowAppearing())
ZoomWheelAccum = 0.0f;
if (io.MouseWheel != 0.0f && ImGui::IsKeyDown(ImGuiMod_Ctrl) && ImGui::IsAnyItemActive() == false)
{
ZoomWheelAccum += io.MouseWheel;
if (fabsf(ZoomWheelAccum) >= 1.0f)
{
IconSize *= powf(1.1f, (float)(int)ZoomWheelAccum);
IconSize = IM_CLAMP(IconSize, 16.0f, 128.0f);
ZoomWheelAccum -= (int)ZoomWheelAccum;
}
}
// Show a table with ONLY one header row to showcase the idea/possibility of using this to provide a sorting UI // Show a table with ONLY one header row to showcase the idea/possibility of using this to provide a sorting UI
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
ImGuiTableFlags table_flags_for_sort_specs = ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Borders; ImGuiTableFlags table_flags_for_sort_specs = ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Borders;
@ -9576,10 +9567,10 @@ struct ExampleAssetsBrowser
ImGui::TableSetupColumn("Type"); ImGui::TableSetupColumn("Type");
ImGui::TableHeadersRow(); ImGui::TableHeadersRow();
if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs()) if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
if (sort_specs->SpecsDirty || SortDirty) if (sort_specs->SpecsDirty || RequestSort)
{ {
ExampleAsset::SortWithSortSpecs(sort_specs, Items.Data, Items.Size); ExampleAsset::SortWithSortSpecs(sort_specs, Items.Data, Items.Size);
sort_specs->SpecsDirty = SortDirty = false; sort_specs->SpecsDirty = RequestSort = false;
} }
ImGui::EndTable(); ImGui::EndTable();
} }
@ -9619,6 +9610,10 @@ struct ExampleAssetsBrowser
Selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self_, int idx) { ExampleAssetsBrowser* self = (ExampleAssetsBrowser*)self_->AdapterData; return self->Items[idx].ID; }; Selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self_, int idx) { ExampleAssetsBrowser* self = (ExampleAssetsBrowser*)self_->AdapterData; return self->Items[idx].ID; };
Selection.ApplyRequests(ms_io, Items.Size); Selection.ApplyRequests(ms_io, Items.Size);
const bool want_delete = RequestDelete || ((Selection.Size > 0) && ImGui::IsWindowFocused() && ImGui::IsKeyPressed(ImGuiKey_Delete));
const int item_curr_idx_to_focus = want_delete ? Selection.ApplyDeletionPreLoop(ms_io, Items.Size) : -1;
RequestDelete = false;
// Altering ItemSpacing may seem unnecessary as we position every items using SetCursorScreenPos()... // Altering ItemSpacing may seem unnecessary as we position every items using SetCursorScreenPos()...
// But it is necessary for two reasons: // But it is necessary for two reasons:
// - Selectables uses it by default to visually fill the space between two items. // - Selectables uses it by default to visually fill the space between two items.
@ -9635,8 +9630,10 @@ struct ExampleAssetsBrowser
const float line_height = item_size.y + item_spacing; const float line_height = item_size.y + item_spacing;
ImGuiListClipper clipper; ImGuiListClipper clipper;
clipper.Begin(line_count, line_height); clipper.Begin(line_count, line_height);
if (item_curr_idx_to_focus != -1)
clipper.IncludeItemByIndex(item_curr_idx_to_focus / column_count); // Ensure focused item line is not clipped.
if (ms_io->RangeSrcItem != -1) if (ms_io->RangeSrcItem != -1)
clipper.IncludeItemByIndex((int)(ms_io->RangeSrcItem / column_count)); clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem / column_count); // Ensure RangeSrc item line is not clipped.
while (clipper.Step()) while (clipper.Step())
{ {
for (int line_idx = clipper.DisplayStart; line_idx < clipper.DisplayEnd; line_idx++) for (int line_idx = clipper.DisplayStart; line_idx < clipper.DisplayEnd; line_idx++)
@ -9666,6 +9663,10 @@ struct ExampleAssetsBrowser
if (ImGui::IsItemToggledSelection()) if (ImGui::IsItemToggledSelection())
item_is_selected = !item_is_selected; item_is_selected = !item_is_selected;
// Focus (for after deletion)
if (item_curr_idx_to_focus == item_idx)
ImGui::SetKeyboardFocusHere(-1);
// Drag and drop // Drag and drop
if (ImGui::BeginDragDropSource()) if (ImGui::BeginDragDropSource())
{ {
@ -9679,15 +9680,6 @@ struct ExampleAssetsBrowser
ImGui::EndDragDropSource(); ImGui::EndDragDropSource();
} }
// Popup menu
if (ImGui::BeginPopupContextItem())
{
ImGui::Text("Selection: %d items", Selection.Size);
if (ImGui::Button("Close"))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
// A real app would likely display an image/thumbnail here. // A real app would likely display an image/thumbnail here.
draw_list->AddRectFilled(box_min, box_max, icon_bg_color); draw_list->AddRectFilled(box_min, box_max, icon_bg_color);
if (ShowTypeOverlay && item_data->Type != 0) if (ShowTypeOverlay && item_data->Type != 0)
@ -9710,13 +9702,41 @@ struct ExampleAssetsBrowser
clipper.End(); clipper.End();
ImGui::PopStyleVar(); // ImGuiStyleVar_ItemSpacing ImGui::PopStyleVar(); // ImGuiStyleVar_ItemSpacing
// Context menu
if (ImGui::BeginPopupContextWindow())
{
ImGui::Text("Selection: %d items", Selection.Size);
ImGui::Separator();
if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
RequestDelete = true;
ImGui::EndPopup();
}
ms_io = ImGui::EndMultiSelect(); ms_io = ImGui::EndMultiSelect();
Selection.ApplyRequests(ms_io, Items.Size); Selection.ApplyRequests(ms_io, Items.Size);
if (want_delete)
Selection.ApplyDeletionPostLoop(ms_io, Items, item_curr_idx_to_focus);
// FIXME-MULTISELECT: Find a way to expose this in public API. This currently requires "imgui_internal.h" // FIXME-MULTISELECT: Find a way to expose this in public API. This currently requires "imgui_internal.h"
//ImGui::NavMoveRequestTryWrapping(ImGui::GetCurrentWindow(), ImGuiNavMoveFlags_WrapX); //ImGui::NavMoveRequestTryWrapping(ImGui::GetCurrentWindow(), ImGuiNavMoveFlags_WrapX);
} }
// Zooming with CTRL+Wheel
// FIXME-MULTISELECT: Try to maintain scroll.
ImGuiIO& io = ImGui::GetIO();
if (ImGui::IsWindowAppearing())
ZoomWheelAccum = 0.0f;
if (ImGui::IsWindowHovered() && io.MouseWheel != 0.0f && ImGui::IsKeyDown(ImGuiMod_Ctrl) && ImGui::IsAnyItemActive() == false)
{
ZoomWheelAccum += io.MouseWheel;
if (fabsf(ZoomWheelAccum) >= 1.0f)
{
IconSize *= powf(1.1f, (float)(int)ZoomWheelAccum);
IconSize = IM_CLAMP(IconSize, 16.0f, 128.0f);
ZoomWheelAccum -= (int)ZoomWheelAccum;
}
}
ImGui::EndChild(); ImGui::EndChild();
ImGui::Text("Selected: %d/%d items", Selection.Size, Items.Size); ImGui::Text("Selected: %d/%d items", Selection.Size, Items.Size);
ImGui::End(); ImGui::End();

Loading…
Cancel
Save