mirror of
https://github.com/ocornut/imgui.git
synced 2024-12-11 07:26:05 +01:00
MultiSelect: made SetNextItemSelectionData() optional to allow disjoint selection (e.g. with a CollapsingHeader between items). Amend demo.
This commit is contained in:
parent
815c61b82e
commit
d2f208a30c
4
imgui.h
4
imgui.h
@ -2766,14 +2766,14 @@ enum ImGuiMultiSelectFlags_
|
|||||||
// 1) Call BeginMultiSelect() with the last saved value of ->RangeSrc and its selection state.
|
// 1) Call BeginMultiSelect() with the last saved value of ->RangeSrc and its selection state.
|
||||||
// It is because you need to pass its selection state (and you own selection) that we don't store this value in Dear ImGui.
|
// It is because you need to pass its selection state (and you own selection) that we don't store this value in Dear ImGui.
|
||||||
// (For the initial frame or when resetting your selection state: you may use the value for your first item or a "null" value that matches the type stored in your void*).
|
// (For the initial frame or when resetting your selection state: you may use the value for your first item or a "null" value that matches the type stored in your void*).
|
||||||
// 2) Honor Clear/SelectAll requests by updating your selection data. Only required if you are using a clipper in step 4: but you can use same code as step 6 anyway.
|
// 2) Honor Clear/SelectAll/SetRange requests by updating your selection data. (Only required if you are using a clipper in step 4: but you can use same code as step 6 anyway.)
|
||||||
// Loop
|
// Loop
|
||||||
// 3) Set RangeSrcPassedBy=true if the RangeSrc item is part of the items clipped before the first submitted/visible item. [Only required if you are using a clipper in step 4]
|
// 3) Set RangeSrcPassedBy=true if the RangeSrc item is part of the items clipped before the first submitted/visible item. [Only required if you are using a clipper in step 4]
|
||||||
// This is because for range-selection we need to know if we are currently "inside" or "outside" the range.
|
// This is because for range-selection we need to know if we are currently "inside" or "outside" the range.
|
||||||
// If you are using integer indices everywhere, this is easy to compute: if (clipper.DisplayStart > (int)data->RangeSrc) { data->RangeSrcPassedBy = true; }
|
// If you are using integer indices everywhere, this is easy to compute: if (clipper.DisplayStart > (int)data->RangeSrc) { data->RangeSrcPassedBy = true; }
|
||||||
// 4) Submit your items with SetNextItemSelectionUserData() + Selectable()/TreeNode() calls.
|
// 4) Submit your items with SetNextItemSelectionUserData() + Selectable()/TreeNode() calls.
|
||||||
// Call IsItemToggledSelection() to query if the selection state has been toggled, if you need the info immediately for your display (before EndMultiSelect()).
|
// Call IsItemToggledSelection() to query if the selection state has been toggled, if you need the info immediately for your display (before EndMultiSelect()).
|
||||||
// When cannot return a "IsItemSelected()" value because we need to consider clipped/unprocessed items, this is why we return a "Toggle" event instead.
|
// When cannot provide a "IsItemSelected()" value because we need to consider clipped/unprocessed items, this is why we return a "Toggled" event instead.
|
||||||
// End
|
// End
|
||||||
// 5) Call EndMultiSelect(). Save the value of ->RangeSrc for the next frame (you may convert the value in a format that is safe for persistance)
|
// 5) Call EndMultiSelect(). Save the value of ->RangeSrc for the next frame (you may convert the value in a format that is safe for persistance)
|
||||||
// 6) Honor Clear/SelectAll/SetRange requests by updating your selection data. Always process them in this order (as you will receive Clear+SetRange request simultaneously)
|
// 6) Honor Clear/SelectAll/SetRange requests by updating your selection data. Always process them in this order (as you will receive Clear+SetRange request simultaneously)
|
||||||
|
@ -2830,6 +2830,7 @@ static void ShowDemoWindowMultiSelect()
|
|||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Demonstrate implementation a most-basic form of multi-selection manually
|
||||||
IMGUI_DEMO_MARKER("Widgets/Selection State/Multiple Selection (simplfied, manual)");
|
IMGUI_DEMO_MARKER("Widgets/Selection State/Multiple Selection (simplfied, manual)");
|
||||||
if (ImGui::TreeNode("Multiple Selection (simplified, manual)"))
|
if (ImGui::TreeNode("Multiple Selection (simplified, manual)"))
|
||||||
{
|
{
|
||||||
@ -2843,7 +2844,7 @@ static void ShowDemoWindowMultiSelect()
|
|||||||
{
|
{
|
||||||
if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
|
if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
|
||||||
memset(selection, 0, sizeof(selection));
|
memset(selection, 0, sizeof(selection));
|
||||||
selection[n] ^= 1;
|
selection[n] ^= 1; // Toggle current item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
@ -2883,7 +2884,6 @@ static void ShowDemoWindowMultiSelect()
|
|||||||
{
|
{
|
||||||
char label[64];
|
char label[64];
|
||||||
sprintf(label, "Object %05d: %s", n, random_names[n % IM_ARRAYSIZE(random_names)]);
|
sprintf(label, "Object %05d: %s", n, random_names[n % IM_ARRAYSIZE(random_names)]);
|
||||||
|
|
||||||
bool item_is_selected = selection.GetSelected(n);
|
bool item_is_selected = selection.GetSelected(n);
|
||||||
ImGui::SetNextItemSelectionUserData(n);
|
ImGui::SetNextItemSelectionUserData(n);
|
||||||
ImGui::Selectable(label, item_is_selected);
|
ImGui::Selectable(label, item_is_selected);
|
||||||
@ -2916,28 +2916,36 @@ static void ShowDemoWindowMultiSelect()
|
|||||||
enum WidgetType { WidgetType_Selectable, WidgetType_TreeNode };
|
enum WidgetType { WidgetType_Selectable, WidgetType_TreeNode };
|
||||||
static bool use_table = false;
|
static bool use_table = false;
|
||||||
static bool use_drag_drop = true;
|
static bool use_drag_drop = true;
|
||||||
static bool multiple_selection_scopes = false;
|
static bool use_multiple_scopes = false;
|
||||||
|
static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_None;
|
||||||
static WidgetType widget_type = WidgetType_TreeNode;
|
static WidgetType widget_type = WidgetType_TreeNode;
|
||||||
if (ImGui::RadioButton("Selectables", widget_type == WidgetType_Selectable)) { widget_type = WidgetType_Selectable; }
|
if (ImGui::RadioButton("Selectables", widget_type == WidgetType_Selectable)) { widget_type = WidgetType_Selectable; }
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::RadioButton("Tree nodes", widget_type == WidgetType_TreeNode)) { widget_type = WidgetType_TreeNode; }
|
if (ImGui::RadioButton("Tree nodes", widget_type == WidgetType_TreeNode)) { widget_type = WidgetType_TreeNode; }
|
||||||
ImGui::Checkbox("Use table", &use_table);
|
ImGui::Checkbox("Use table", &use_table);
|
||||||
ImGui::Checkbox("Use drag & drop", &use_drag_drop);
|
ImGui::Checkbox("Use drag & drop", &use_drag_drop);
|
||||||
ImGui::Checkbox("Distinct selection scopes in same window", &multiple_selection_scopes);
|
ImGui::Checkbox("Multiple selection scopes in same window", &use_multiple_scopes);
|
||||||
|
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoMultiSelect", &flags, ImGuiMultiSelectFlags_NoMultiSelect);
|
||||||
|
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoUnselect", &flags, ImGuiMultiSelectFlags_NoUnselect);
|
||||||
|
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectAll", &flags, ImGuiMultiSelectFlags_NoSelectAll);
|
||||||
|
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnEscape", &flags, ImGuiMultiSelectFlags_ClearOnEscape);
|
||||||
|
ImGui::BeginDisabled(use_multiple_scopes);
|
||||||
|
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickWindowVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickWindowVoid);
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
// When 'multiple_selection_scopes' is set we show 3 selection scopes in the host window instead of 1 in a scrolling window.
|
// When 'use_multiple_scopes' is set we show 3 selection scopes in the host window instead of 1 in a scrolling window.
|
||||||
static ExampleSelection selections_data[3];
|
static ExampleSelection selections_data[3];
|
||||||
const int selection_scope_count = multiple_selection_scopes ? 3 : 1;
|
const int selection_scope_count = use_multiple_scopes ? 3 : 1;
|
||||||
for (int selection_scope_n = 0; selection_scope_n < selection_scope_count; selection_scope_n++)
|
for (int selection_scope_n = 0; selection_scope_n < selection_scope_count; selection_scope_n++)
|
||||||
{
|
{
|
||||||
ExampleSelection* selection = &selections_data[selection_scope_n];
|
ExampleSelection* selection = &selections_data[selection_scope_n];
|
||||||
|
|
||||||
const int ITEMS_COUNT = multiple_selection_scopes ? 12 : 1000;
|
const int ITEMS_COUNT = use_multiple_scopes ? 12 : 1000; // Smaller count to make it easier to see multiple scopes in same screen.
|
||||||
ImGui::PushID(selection_scope_n);
|
ImGui::PushID(selection_scope_n);
|
||||||
|
|
||||||
// Open a scrolling region
|
// Open a scrolling region
|
||||||
bool draw_selection = true;
|
bool draw_selection = true;
|
||||||
if (multiple_selection_scopes)
|
if (use_multiple_scopes)
|
||||||
{
|
{
|
||||||
ImGui::SeparatorText("Selection scope");
|
ImGui::SeparatorText("Selection scope");
|
||||||
}
|
}
|
||||||
@ -2952,15 +2960,13 @@ static void ShowDemoWindowMultiSelect()
|
|||||||
if (widget_type == WidgetType_TreeNode)
|
if (widget_type == WidgetType_TreeNode)
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(ImGui::GetStyle().ItemSpacing.x, 0.0f));
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(ImGui::GetStyle().ItemSpacing.x, 0.0f));
|
||||||
|
|
||||||
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_None;
|
ImGuiMultiSelectFlags local_flags = flags;
|
||||||
if (multiple_selection_scopes)
|
if (use_multiple_scopes)
|
||||||
;// flags |= ImGuiMultiSelectFlags_ClearOnClickRectVoid;
|
local_flags &= ~ImGuiMultiSelectFlags_ClearOnClickWindowVoid; // local_flags |= ImGuiMultiSelectFlags_ClearOnClickRectVoid;
|
||||||
else
|
ImGuiMultiSelectData* multi_select_data = ImGui::BeginMultiSelect(local_flags, (void*)(intptr_t)selection->RangeRef, selection->GetSelected(selection->RangeRef));
|
||||||
flags |= ImGuiMultiSelectFlags_ClearOnClickWindowVoid;
|
|
||||||
ImGuiMultiSelectData* multi_select_data = ImGui::BeginMultiSelect(flags, (void*)(intptr_t)selection->RangeRef, selection->GetSelected(selection->RangeRef));
|
|
||||||
selection->ApplyRequests(multi_select_data, ITEMS_COUNT);
|
selection->ApplyRequests(multi_select_data, ITEMS_COUNT);
|
||||||
|
|
||||||
if (multiple_selection_scopes)
|
if (use_multiple_scopes)
|
||||||
ImGui::Text("Selection size: %d", selection->GetSelectionSize()); // Draw counter below Separator and after BeginMultiSelect()
|
ImGui::Text("Selection size: %d", selection->GetSelectionSize()); // Draw counter below Separator and after BeginMultiSelect()
|
||||||
|
|
||||||
if (use_table)
|
if (use_table)
|
||||||
@ -3062,7 +3068,7 @@ static void ShowDemoWindowMultiSelect()
|
|||||||
if (widget_type == WidgetType_TreeNode)
|
if (widget_type == WidgetType_TreeNode)
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
if (multiple_selection_scopes == false)
|
if (use_multiple_scopes == false)
|
||||||
ImGui::EndListBox();
|
ImGui::EndListBox();
|
||||||
}
|
}
|
||||||
ImGui::PopID(); // ImGui::PushID(selection_scope_n);
|
ImGui::PopID(); // ImGui::PushID(selection_scope_n);
|
||||||
|
@ -6391,6 +6391,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags
|
|||||||
|
|
||||||
// Compute open and multi-select states before ItemAdd() as it clear NextItem data.
|
// Compute open and multi-select states before ItemAdd() as it clear NextItem data.
|
||||||
bool is_open = TreeNodeUpdateNextOpen(storage_id, flags);
|
bool is_open = TreeNodeUpdateNextOpen(storage_id, flags);
|
||||||
|
const bool is_multi_select = (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasSelectionData) != 0; // Before ItemAdd()
|
||||||
bool item_add = ItemAdd(interact_bb, id);
|
bool item_add = ItemAdd(interact_bb, id);
|
||||||
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect;
|
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect;
|
||||||
g.LastItemData.DisplayRect = frame_bb;
|
g.LastItemData.DisplayRect = frame_bb;
|
||||||
@ -6464,7 +6465,6 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags
|
|||||||
const bool was_selected = selected;
|
const bool was_selected = selected;
|
||||||
|
|
||||||
// Multi-selection support (header)
|
// Multi-selection support (header)
|
||||||
const bool is_multi_select = (g.MultiSelectState.Window == window);
|
|
||||||
if (is_multi_select)
|
if (is_multi_select)
|
||||||
{
|
{
|
||||||
MultiSelectItemHeader(id, &selected);
|
MultiSelectItemHeader(id, &selected);
|
||||||
@ -6780,7 +6780,9 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
|||||||
}
|
}
|
||||||
|
|
||||||
const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0;
|
const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0;
|
||||||
|
const bool is_multi_select = (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasSelectionData) != 0; // Before ItemAdd()
|
||||||
const bool item_add = ItemAdd(bb, id, NULL, disabled_item ? (ImGuiItemFlags)ImGuiItemFlags_Disabled : ImGuiItemFlags_None);
|
const bool item_add = ItemAdd(bb, id, NULL, disabled_item ? (ImGuiItemFlags)ImGuiItemFlags_Disabled : ImGuiItemFlags_None);
|
||||||
|
|
||||||
if (span_all_columns)
|
if (span_all_columns)
|
||||||
{
|
{
|
||||||
window->ClipRect.Min.x = backup_clip_rect_min_x;
|
window->ClipRect.Min.x = backup_clip_rect_min_x;
|
||||||
@ -6816,7 +6818,6 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
|||||||
if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; }
|
if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; }
|
||||||
|
|
||||||
// Multi-selection support (header)
|
// Multi-selection support (header)
|
||||||
const bool is_multi_select = (g.MultiSelectState.Window == window);
|
|
||||||
const bool was_selected = selected;
|
const bool was_selected = selected;
|
||||||
if (is_multi_select)
|
if (is_multi_select)
|
||||||
{
|
{
|
||||||
@ -7166,7 +7167,7 @@ ImGuiMultiSelectData* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, void*
|
|||||||
ms->In.RequestSelectAll = true;
|
ms->In.RequestSelectAll = true;
|
||||||
|
|
||||||
if (flags & ImGuiMultiSelectFlags_ClearOnEscape)
|
if (flags & ImGuiMultiSelectFlags_ClearOnEscape)
|
||||||
if (Shortcut(ImGuiKey_Escape))
|
if (Shortcut(ImGuiKey_Escape)) // FIXME-MULTISELECT: Only hog shortcut if selection is not null, meaning we need "has selection or "selection size" data here.
|
||||||
ms->In.RequestClear = true;
|
ms->In.RequestClear = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user