mirror of
https://github.com/ocornut/imgui.git
synced 2026-01-11 00:04:24 +00:00
MultiSelect: WIP range-select (#1861) (rebased six millions times)
This commit is contained in:
parent
c2d21ab04f
commit
554db6bc0f
5 changed files with 533 additions and 59 deletions
155
imgui_demo.cpp
155
imgui_demo.cpp
|
|
@ -72,6 +72,7 @@ Index of this file:
|
|||
// [SECTION] Demo Window / ShowDemoWindow()
|
||||
// - ShowDemoWindow()
|
||||
// - sub section: ShowDemoWindowWidgets()
|
||||
// - sub section: ShowDemoWindowMultiSelect()
|
||||
// - sub section: ShowDemoWindowLayout()
|
||||
// - sub section: ShowDemoWindowPopups()
|
||||
// - sub section: ShowDemoWindowTables()
|
||||
|
|
@ -214,6 +215,7 @@ static void ShowExampleMenuFile();
|
|||
// We split the contents of the big ShowDemoWindow() function into smaller functions
|
||||
// (because the link time of very large functions grow non-linearly)
|
||||
static void ShowDemoWindowWidgets();
|
||||
static void ShowDemoWindowMultiSelect();
|
||||
static void ShowDemoWindowLayout();
|
||||
static void ShowDemoWindowPopups();
|
||||
static void ShowDemoWindowTables();
|
||||
|
|
@ -251,6 +253,7 @@ void* GImGuiDemoMarkerCallbackUserData = NULL;
|
|||
//-----------------------------------------------------------------------------
|
||||
// - ShowDemoWindow()
|
||||
// - ShowDemoWindowWidgets()
|
||||
// - ShowDemoWindowMultiSelect()
|
||||
// - ShowDemoWindowLayout()
|
||||
// - ShowDemoWindowPopups()
|
||||
// - ShowDemoWindowTables()
|
||||
|
|
@ -1371,37 +1374,6 @@ static void ShowDemoWindowWidgets()
|
|||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
IMGUI_DEMO_MARKER("Widgets/Selectables/Single Selection");
|
||||
if (ImGui::TreeNode("Selection State: Single Selection"))
|
||||
{
|
||||
static int selected = -1;
|
||||
for (int n = 0; n < 5; n++)
|
||||
{
|
||||
char buf[32];
|
||||
sprintf(buf, "Object %d", n);
|
||||
if (ImGui::Selectable(buf, selected == n))
|
||||
selected = n;
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
IMGUI_DEMO_MARKER("Widgets/Selectables/Multiple Selection");
|
||||
if (ImGui::TreeNode("Selection State: Multiple Selection"))
|
||||
{
|
||||
HelpMarker("Hold CTRL and click to select multiple items.");
|
||||
static bool selection[5] = { false, false, false, false, false };
|
||||
for (int n = 0; n < 5; n++)
|
||||
{
|
||||
char buf[32];
|
||||
sprintf(buf, "Object %d", n);
|
||||
if (ImGui::Selectable(buf, selection[n]))
|
||||
{
|
||||
if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
|
||||
memset(selection, 0, sizeof(selection));
|
||||
selection[n] ^= 1;
|
||||
}
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line");
|
||||
if (ImGui::TreeNode("Rendering more items on the same line"))
|
||||
{
|
||||
|
|
@ -1461,6 +1433,15 @@ static void ShowDemoWindowWidgets()
|
|||
if (winning_state)
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f)));
|
||||
|
||||
static float spacing = 0.0f;
|
||||
ImGui::PushItemWidth(100);
|
||||
ImGui::SliderFloat("SelectableSpacing", &spacing, 0, 20, "%.0f");
|
||||
ImGui::SameLine(); HelpMarker("Selectable cancel out the regular spacing between items by extending itself by ItemSpacing/2 in each direction.\nThis has two purposes:\n- Avoid the gap between items so the mouse is always hitting something.\n- Avoid the gap between items so range-selected item looks connected.\nBy changing SelectableSpacing we can enforce spacing between selectables.");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::Spacing();
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 8));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_SelectableSpacing, ImVec2(spacing, spacing));
|
||||
|
||||
for (int y = 0; y < 4; y++)
|
||||
for (int x = 0; x < 4; x++)
|
||||
{
|
||||
|
|
@ -1479,8 +1460,10 @@ static void ShowDemoWindowWidgets()
|
|||
ImGui::PopID();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
if (winning_state)
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
IMGUI_DEMO_MARKER("Widgets/Selectables/Alignment");
|
||||
|
|
@ -1509,6 +1492,8 @@ static void ShowDemoWindowWidgets()
|
|||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ShowDemoWindowMultiSelect();
|
||||
|
||||
// To wire InputText() with std::string or any other custom string type,
|
||||
// see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
|
||||
IMGUI_DEMO_MARKER("Widgets/Text Input");
|
||||
|
|
@ -2785,6 +2770,113 @@ static void ShowDemoWindowWidgets()
|
|||
}
|
||||
}
|
||||
|
||||
static void ShowDemoWindowMultiSelect()
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Widgets/Selection State");
|
||||
if (ImGui::TreeNode("Selection State"))
|
||||
{
|
||||
HelpMarker("Selections can be built under Selectable(), TreeNode() or other widgets. Selection state is owned by application code/data.");
|
||||
|
||||
IMGUI_DEMO_MARKER("Widgets/Selection State/Single Selection");
|
||||
if (ImGui::TreeNode("Single Selection"))
|
||||
{
|
||||
static int selected = -1;
|
||||
for (int n = 0; n < 5; n++)
|
||||
{
|
||||
char buf[32];
|
||||
sprintf(buf, "Object %d", n);
|
||||
if (ImGui::Selectable(buf, selected == n))
|
||||
selected = n;
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
IMGUI_DEMO_MARKER("Widgets/Selection State/Multiple Selection (Basic)");
|
||||
if (ImGui::TreeNode("Multiple Selection (Basic)"))
|
||||
{
|
||||
HelpMarker("Hold CTRL and click to select multiple items.");
|
||||
static bool selection[5] = { false, false, false, false, false };
|
||||
for (int n = 0; n < 5; n++)
|
||||
{
|
||||
char buf[32];
|
||||
sprintf(buf, "Object %d", n);
|
||||
if (ImGui::Selectable(buf, selection[n]))
|
||||
{
|
||||
if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
|
||||
memset(selection, 0, sizeof(selection));
|
||||
selection[n] ^= 1;
|
||||
}
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
IMGUI_DEMO_MARKER("Widgets/Selection State/Multiple Selection (Full)");
|
||||
if (ImGui::TreeNode("Multiple Selection (Full)"))
|
||||
{
|
||||
// Demonstrate holding/updating multi-selection data and using the BeginMultiSelect/EndMultiSelect API to support range-selection and clipping.
|
||||
// In this demo we use ImGuiStorage (simple key->value storage) to avoid external dependencies but it's probably not optimal.
|
||||
// In your real code you could use e.g std::unordered_set<> or your own data structure for storing selection.
|
||||
// If you don't mind being limited to one view over your objects, the simplest way is to use an intrusive selection (e.g. store bool inside object, as used in examples above).
|
||||
// Otherwise external set/hash/map/interval trees (storing indices, etc.) may be appropriate.
|
||||
struct MySelection
|
||||
{
|
||||
ImGuiStorage Storage;
|
||||
void Clear() { Storage.Clear(); }
|
||||
void SelectAll(int count) { Storage.Data.reserve(count); Storage.Data.resize(0); for (int n = 0; n < count; n++) Storage.Data.push_back(ImGuiStoragePair((ImGuiID)n, 1)); }
|
||||
void SetRange(int a, int b, int sel) { if (b < a) { int tmp = b; b = a; a = tmp; } for (int n = a; n <= b; n++) Storage.SetInt((ImGuiID)n, sel); }
|
||||
bool GetSelected(int id) const { return Storage.GetInt((ImGuiID)id) != 0; }
|
||||
void SetSelected(int id, bool v) { SetRange(id, id, v ? 1 : 0); }
|
||||
};
|
||||
|
||||
static int selection_ref = 0; // Selection pivot (last clicked item, we need to preserve this to handle range-select)
|
||||
static MySelection selection;
|
||||
const char* random_names[] =
|
||||
{
|
||||
"Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper",
|
||||
"Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava",
|
||||
"Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Celtuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber"
|
||||
};
|
||||
|
||||
int COUNT = 1000;
|
||||
HelpMarker("Hold CTRL and click to select multiple items. Hold SHIFT to select a range.");
|
||||
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", (unsigned int*)&ImGui::GetIO().ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
|
||||
|
||||
if (ImGui::BeginListBox("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20)))
|
||||
{
|
||||
ImGuiMultiSelectData* multi_select_data = ImGui::BeginMultiSelect(0, (void*)(intptr_t)selection_ref, selection.GetSelected((int)selection_ref));
|
||||
if (multi_select_data->RequestClear) { selection.Clear(); }
|
||||
if (multi_select_data->RequestSelectAll) { selection.SelectAll(COUNT); }
|
||||
ImGuiListClipper clipper;
|
||||
clipper.Begin(COUNT);
|
||||
while (clipper.Step())
|
||||
{
|
||||
if (clipper.DisplayStart > (int)selection_ref)
|
||||
multi_select_data->RangeSrcPassedBy = true;
|
||||
for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
|
||||
{
|
||||
ImGui::PushID(n);
|
||||
char label[64];
|
||||
sprintf(label, "Object %05d (category: %s)", n, random_names[n % IM_ARRAYSIZE(random_names)]);
|
||||
bool item_is_selected = selection.GetSelected(n);
|
||||
ImGui::SetNextItemSelectionUserData(n);
|
||||
if (ImGui::Selectable(label, item_is_selected))
|
||||
selection.SetSelected(n, !item_is_selected);
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
multi_select_data = ImGui::EndMultiSelect();
|
||||
selection_ref = (int)(intptr_t)multi_select_data->RangeSrc;
|
||||
ImGui::EndListBox();
|
||||
if (multi_select_data->RequestClear) { selection.Clear(); }
|
||||
if (multi_select_data->RequestSelectAll) { selection.SelectAll(COUNT); }
|
||||
if (multi_select_data->RequestSetRange) { selection.SetRange((int)(intptr_t)multi_select_data->RangeSrc, (int)(intptr_t)multi_select_data->RangeDst, multi_select_data->RangeValue ? 1 : 0); }
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
static void ShowDemoWindowLayout()
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Layout");
|
||||
|
|
@ -6771,6 +6863,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
|
|||
ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
|
||||
ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
|
||||
ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
|
||||
ImGui::SliderFloat2("SelectableSpacing", (float*)&style.SelectableSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SameLine(); HelpMarker("SelectableSpacing must be < ItemSpacing.\nSelectables display their highlight after canceling out the effect of ItemSpacing, so they can be look tightly packed. This setting allows to enforce spacing between them.");
|
||||
ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
|
||||
ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
|
||||
ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue