mirror of
https://github.com/ocornut/imgui.git
synced 2026-05-30 13:55:24 +08:00
MultiSelect: Added ImGuiMultiSelectFlags_ClearOnClickWindowVoid. + Demo: showcase multiple selection scopes in same window.
This commit is contained in:
@@ -2731,11 +2731,13 @@ struct ImColor
|
|||||||
// you can handle single-selection in a simpler manner by just calling Selectable() and reacting on clicks yourself.
|
// you can handle single-selection in a simpler manner by just calling Selectable() and reacting on clicks yourself.
|
||||||
enum ImGuiMultiSelectFlags_
|
enum ImGuiMultiSelectFlags_
|
||||||
{
|
{
|
||||||
ImGuiMultiSelectFlags_None = 0,
|
ImGuiMultiSelectFlags_None = 0,
|
||||||
ImGuiMultiSelectFlags_NoMultiSelect = 1 << 0,
|
ImGuiMultiSelectFlags_NoMultiSelect = 1 << 0,
|
||||||
ImGuiMultiSelectFlags_NoUnselect = 1 << 1, // Disable unselecting items with CTRL+Click, CTRL+Space etc.
|
ImGuiMultiSelectFlags_NoUnselect = 1 << 1, // Disable unselecting items with CTRL+Click, CTRL+Space etc.
|
||||||
ImGuiMultiSelectFlags_NoSelectAll = 1 << 2, // Disable CTRL+A shortcut to set RequestSelectAll
|
ImGuiMultiSelectFlags_NoSelectAll = 1 << 2, // Disable CTRL+A shortcut to set RequestSelectAll
|
||||||
ImGuiMultiSelectFlags_ClearOnEscape = 1 << 3, // Enable ESC shortcut to clear selection
|
ImGuiMultiSelectFlags_ClearOnClickWindowVoid= 1 << 3, // Clear selection when clicking on empty location within host window (use if BeginMultiSelect() covers a whole window)
|
||||||
|
//ImGuiMultiSelectFlags_ClearOnClickRectVoid= 1 << 4, // Clear selection when clicking on empty location within rectangle covered by selection scope (use if multiple BeginMultiSelect() are used in the same host window)
|
||||||
|
ImGuiMultiSelectFlags_ClearOnEscape = 1 << 5, // Clear selection when pressing Escape while scope is focused.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Abstract:
|
// Abstract:
|
||||||
|
|||||||
+35
-16
@@ -2900,42 +2900,64 @@ static void ShowDemoWindowMultiSelect()
|
|||||||
// - Showcase clipping.
|
// - Showcase clipping.
|
||||||
// - Showcase basic drag and drop.
|
// - Showcase basic drag and drop.
|
||||||
// - Showcase TreeNode variant (note that tree node don't expand in the demo: supporting expanding tree nodes + clipping a separate thing).
|
// - Showcase TreeNode variant (note that tree node don't expand in the demo: supporting expanding tree nodes + clipping a separate thing).
|
||||||
|
// - Showcase having multiple multi-selection scopes in the same window.
|
||||||
// - Showcase using inside a table.
|
// - Showcase using inside a table.
|
||||||
IMGUI_DEMO_MARKER("Widgets/Selection State/Multiple Selection (full, advanced)");
|
IMGUI_DEMO_MARKER("Widgets/Selection State/Multiple Selection (full, advanced)");
|
||||||
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
|
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
|
||||||
if (ImGui::TreeNode("Multiple Selection (full, advanced)"))
|
if (ImGui::TreeNode("Multiple Selection (full, advanced)"))
|
||||||
{
|
{
|
||||||
// Demonstrate holding/updating multi-selection data and using the BeginMultiSelect/EndMultiSelect API to support range-selection and clipping.
|
|
||||||
static ExampleSelection selections_data[1];
|
|
||||||
ExampleSelection* selection = &selections_data[0];
|
|
||||||
|
|
||||||
// Options
|
// Options
|
||||||
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 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);
|
||||||
|
|
||||||
// (spare brace to add a loop here later)
|
// When 'multiple_selection_scopes' is set we show 3 selection scopes in the host window instead of 1 in a scrolling window.
|
||||||
|
static ExampleSelection selections_data[3];
|
||||||
|
const int selection_scope_count = multiple_selection_scopes ? 3 : 1;
|
||||||
|
for (int selection_scope_n = 0; selection_scope_n < selection_scope_count; selection_scope_n++)
|
||||||
{
|
{
|
||||||
ImGui::Text("Selection size: %d", selection->GetSelectionSize());
|
ExampleSelection* selection = &selections_data[selection_scope_n];
|
||||||
|
|
||||||
|
const int ITEMS_COUNT = multiple_selection_scopes ? 12 : 1000;
|
||||||
|
ImGui::PushID(selection_scope_n);
|
||||||
|
|
||||||
// Open a scrolling region
|
// Open a scrolling region
|
||||||
const int ITEMS_COUNT = 1000;
|
bool draw_selection = true;
|
||||||
if (ImGui::BeginListBox("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20)))
|
if (multiple_selection_scopes)
|
||||||
|
{
|
||||||
|
ImGui::SeparatorText("Selection scope");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui::Text("Selection size: %d", selection->GetSelectionSize());
|
||||||
|
draw_selection = ImGui::BeginListBox("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20));
|
||||||
|
}
|
||||||
|
if (draw_selection)
|
||||||
{
|
{
|
||||||
ImVec2 color_button_sz(ImGui::GetFontSize(), ImGui::GetFontSize());
|
ImVec2 color_button_sz(ImGui::GetFontSize(), ImGui::GetFontSize());
|
||||||
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));
|
||||||
|
|
||||||
ImGuiMultiSelectData* multi_select_data = ImGui::BeginMultiSelect(ImGuiMultiSelectFlags_None, (void*)(intptr_t)selection->RangeRef, selection->GetSelected(selection->RangeRef));
|
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_None;
|
||||||
|
if (multiple_selection_scopes)
|
||||||
|
;// flags |= ImGuiMultiSelectFlags_ClearOnClickRectVoid;
|
||||||
|
else
|
||||||
|
flags |= ImGuiMultiSelectFlags_ClearOnClickWindowVoid;
|
||||||
|
ImGuiMultiSelectData* multi_select_data = ImGui::BeginMultiSelect(flags, (void*)(intptr_t)selection->RangeRef, selection->GetSelected(selection->RangeRef));
|
||||||
if (multi_select_data->RequestClear) { selection->Clear(); }
|
if (multi_select_data->RequestClear) { selection->Clear(); }
|
||||||
if (multi_select_data->RequestSelectAll) { selection->SelectAll(ITEMS_COUNT); }
|
if (multi_select_data->RequestSelectAll) { selection->SelectAll(ITEMS_COUNT); }
|
||||||
|
|
||||||
|
if (multiple_selection_scopes)
|
||||||
|
ImGui::Text("Selection size: %d", selection->GetSelectionSize()); // Draw counter below Separator and after BeginMultiSelect()
|
||||||
|
|
||||||
if (use_table)
|
if (use_table)
|
||||||
{
|
{
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0.0f, 0.0f));
|
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0.0f, 0.0f));
|
||||||
@@ -3037,15 +3059,12 @@ static void ShowDemoWindowMultiSelect()
|
|||||||
if (widget_type == WidgetType_TreeNode)
|
if (widget_type == WidgetType_TreeNode)
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
ImGui::EndListBox();
|
if (multiple_selection_scopes == false)
|
||||||
|
ImGui::EndListBox();
|
||||||
}
|
}
|
||||||
|
ImGui::PopID(); // ImGui::PushID(selection_scope_n);
|
||||||
|
} // for each selection scope (1 or 3)
|
||||||
|
|
||||||
if (use_table)
|
|
||||||
{
|
|
||||||
ImGui::EndTable();
|
|
||||||
ImGui::PopStyleVar();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
|
|||||||
@@ -1720,6 +1720,7 @@ struct IMGUI_API ImGuiMultiSelectState
|
|||||||
ImGuiMultiSelectData Out; // The Out requests are finalized and returned by EndMultiSelect()
|
ImGuiMultiSelectData Out; // The Out requests are finalized and returned by EndMultiSelect()
|
||||||
bool InRangeDstPassedBy; // (Internal) set by the the item that match NavJustMovedToId when InRequestRangeSetNav is set.
|
bool InRangeDstPassedBy; // (Internal) set by the the item that match NavJustMovedToId when InRequestRangeSetNav is set.
|
||||||
bool InRequestSetRangeNav; // (Internal) set by BeginMultiSelect() when using Shift+Navigation. Because scrolling may be affected we can't afford a frame of lag with Shift+Navigation.
|
bool InRequestSetRangeNav; // (Internal) set by BeginMultiSelect() when using Shift+Navigation. Because scrolling may be affected we can't afford a frame of lag with Shift+Navigation.
|
||||||
|
//ImRect Rect; // Extent of selection scope between BeginMultiSelect() / EndMultiSelect(), used by ImGuiMultiSelectFlags_ClearOnClickRectVoid.
|
||||||
|
|
||||||
ImGuiMultiSelectState() { Clear(); }
|
ImGuiMultiSelectState() { Clear(); }
|
||||||
void Clear() { FocusScopeId = 0; In.Clear(); Out.Clear(); InRangeDstPassedBy = InRequestSetRangeNav = false; }
|
void Clear() { FocusScopeId = 0; In.Clear(); Out.Clear(); InRangeDstPassedBy = InRequestSetRangeNav = false; }
|
||||||
|
|||||||
@@ -7188,6 +7188,17 @@ ImGuiMultiSelectData* ImGui::EndMultiSelect()
|
|||||||
ImGuiMultiSelectState* ms = &g.MultiSelectState;
|
ImGuiMultiSelectState* ms = &g.MultiSelectState;
|
||||||
IM_ASSERT(g.MultiSelectState.FocusScopeId == g.CurrentFocusScopeId);
|
IM_ASSERT(g.MultiSelectState.FocusScopeId == g.CurrentFocusScopeId);
|
||||||
|
|
||||||
|
// Clear selection when clicking void?
|
||||||
|
// We specifically test for IsMouseDragPastThreshold(0) == false to allow box-selection!
|
||||||
|
if (g.MultiSelectFlags & ImGuiMultiSelectFlags_ClearOnClickWindowVoid)
|
||||||
|
if (IsWindowHovered() && g.HoveredId == 0)
|
||||||
|
if (IsMouseReleased(0) && IsMouseDragPastThreshold(0) == false && g.IO.KeyMods == ImGuiMod_None)
|
||||||
|
{
|
||||||
|
ms->Out.RequestClear = true;
|
||||||
|
ms->Out.RequestSelectAll = ms->Out.RequestSetRange = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unwind
|
||||||
if (g.MultiSelectFlags & ImGuiMultiSelectFlags_NoUnselect)
|
if (g.MultiSelectFlags & ImGuiMultiSelectFlags_NoUnselect)
|
||||||
ms->Out.RangeValue = true;
|
ms->Out.RangeValue = true;
|
||||||
g.MultiSelectState.FocusScopeId = 0;
|
g.MultiSelectState.FocusScopeId = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user