mirror of
https://github.com/ocornut/imgui.git
synced 2024-11-27 16:29:02 +08:00
MultiSelect: Added ImGuiMultiSelectFlags_SelectOnClickRelease to allow dragging an unselected item without altering selection + update drag and drop demo.
This commit is contained in:
parent
5628dda5a5
commit
82de6c470b
2
imgui.h
2
imgui.h
@ -2736,6 +2736,8 @@ enum ImGuiMultiSelectFlags_
|
|||||||
ImGuiMultiSelectFlags_ClearOnEscape = 1 << 2, // Clear selection when pressing Escape while scope is focused.
|
ImGuiMultiSelectFlags_ClearOnEscape = 1 << 2, // Clear selection when pressing Escape while scope is focused.
|
||||||
ImGuiMultiSelectFlags_ClearOnClickWindowVoid= 1 << 3, // Clear selection when clicking on empty location within host window (use if BeginMultiSelect() covers a whole window)
|
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_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_SelectOnClick = 1 << 5, // Apply selection on mouse down when clicking on unselected item. (Default)
|
||||||
|
ImGuiMultiSelectFlags_SelectOnClickRelease = 1 << 6, // Apply selection on mouse release when clicking an unselected item. Allow dragging an unselected item without altering selection.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Multi-selection system
|
// Multi-selection system
|
||||||
|
@ -3338,6 +3338,7 @@ static void ShowDemoWindowMultiSelect()
|
|||||||
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectAll", &flags, ImGuiMultiSelectFlags_NoSelectAll);
|
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectAll", &flags, ImGuiMultiSelectFlags_NoSelectAll);
|
||||||
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnEscape", &flags, ImGuiMultiSelectFlags_ClearOnEscape);
|
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnEscape", &flags, ImGuiMultiSelectFlags_ClearOnEscape);
|
||||||
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickWindowVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickWindowVoid);
|
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickWindowVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickWindowVoid);
|
||||||
|
ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClickRelease", &flags, ImGuiMultiSelectFlags_SelectOnClickRelease); ImGui::SameLine(); HelpMarker("Allow dragging an unselected item without altering selection.");
|
||||||
|
|
||||||
// Initialize default list with 1000 items.
|
// Initialize default list with 1000 items.
|
||||||
static ImVector<int> items;
|
static ImVector<int> items;
|
||||||
@ -3403,11 +3404,11 @@ static void ShowDemoWindowMultiSelect()
|
|||||||
// IMPORTANT: for deletion refocus to work we need object ID to be stable,
|
// IMPORTANT: for deletion refocus to work we need object ID to be stable,
|
||||||
// aka not depend on their index in the list. Here we use our persistent item_id
|
// aka not depend on their index in the list. Here we use our persistent item_id
|
||||||
// instead of index to build a unique ID that will persist.
|
// instead of index to build a unique ID that will persist.
|
||||||
// (If we used PushID(n) instead, focus wouldn't be restored correctly after deletion).
|
// (If we used PushID(index) instead, focus wouldn't be restored correctly after deletion).
|
||||||
ImGui::PushID(item_id);
|
ImGui::PushID(item_id);
|
||||||
|
|
||||||
// Emit a color button, to test that Shift+LeftArrow landing on an item that is not part
|
// Emit a color button, to test that Shift+LeftArrow landing on an item that is not part
|
||||||
// of the selection scope doesn't erroneously alter our selection (FIXME-TESTS: Add a test for that!).
|
// of the selection scope doesn't erroneously alter our selection.
|
||||||
if (show_color_button)
|
if (show_color_button)
|
||||||
{
|
{
|
||||||
ImU32 dummy_col = (ImU32)((unsigned int)n * 0xC250B74B) | IM_COL32_A_MASK;
|
ImU32 dummy_col = (ImU32)((unsigned int)n * 0xC250B74B) | IM_COL32_A_MASK;
|
||||||
@ -3415,39 +3416,57 @@ static void ShowDemoWindowMultiSelect()
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Submit item
|
||||||
bool item_is_selected = selection.Contains((ImGuiID)n);
|
bool item_is_selected = selection.Contains((ImGuiID)n);
|
||||||
|
bool item_is_open = false;
|
||||||
ImGui::SetNextItemSelectionUserData(n);
|
ImGui::SetNextItemSelectionUserData(n);
|
||||||
if (widget_type == WidgetType_Selectable)
|
if (widget_type == WidgetType_Selectable)
|
||||||
{
|
{
|
||||||
ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_None;
|
ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_None);
|
||||||
ImGui::Selectable(label, item_is_selected, selectable_flags);
|
|
||||||
if (item_curr_idx_to_focus == n)
|
|
||||||
ImGui::SetKeyboardFocusHere(-1);
|
|
||||||
|
|
||||||
if (use_drag_drop && ImGui::BeginDragDropSource())
|
|
||||||
{
|
|
||||||
ImGui::Text("(Dragging %d items)", selection.GetSize());
|
|
||||||
ImGui::EndDragDropSource();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (widget_type == WidgetType_TreeNode)
|
else if (widget_type == WidgetType_TreeNode)
|
||||||
{
|
{
|
||||||
ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth;
|
ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
|
||||||
tree_node_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
|
|
||||||
if (item_is_selected)
|
if (item_is_selected)
|
||||||
tree_node_flags |= ImGuiTreeNodeFlags_Selected;
|
tree_node_flags |= ImGuiTreeNodeFlags_Selected;
|
||||||
bool open = ImGui::TreeNodeEx(label, tree_node_flags);
|
item_is_open = ImGui::TreeNodeEx(label, tree_node_flags);
|
||||||
if (item_curr_idx_to_focus == n)
|
|
||||||
ImGui::SetKeyboardFocusHere(-1);
|
|
||||||
if (use_drag_drop && ImGui::BeginDragDropSource())
|
|
||||||
{
|
|
||||||
ImGui::Text("(Dragging %d items)", selection.GetSize());
|
|
||||||
ImGui::EndDragDropSource();
|
|
||||||
}
|
|
||||||
if (open)
|
|
||||||
ImGui::TreePop();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Focus (for after deletion)
|
||||||
|
if (item_curr_idx_to_focus == n)
|
||||||
|
ImGui::SetKeyboardFocusHere(-1);
|
||||||
|
|
||||||
|
// Drag and Drop
|
||||||
|
if (use_drag_drop && ImGui::BeginDragDropSource())
|
||||||
|
{
|
||||||
|
// Write payload with full selection OR single unselected item (only possible with ImGuiMultiSelectFlags_SelectOnClickRelease)
|
||||||
|
if (ImGui::GetDragDropPayload() == NULL)
|
||||||
|
{
|
||||||
|
ImVector<int> payload_items;
|
||||||
|
if (!item_is_selected)
|
||||||
|
payload_items.push_back(item_id);
|
||||||
|
else
|
||||||
|
for (const ImGuiStoragePair& pair : selection.Storage.Data)
|
||||||
|
if (pair.val_i)
|
||||||
|
payload_items.push_back((int)pair.key);
|
||||||
|
ImGui::SetDragDropPayload("MULTISELECT_DEMO_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display payload content in tooltip
|
||||||
|
const ImGuiPayload* payload = ImGui::GetDragDropPayload();
|
||||||
|
const int* payload_items = (int*)payload->Data;
|
||||||
|
const int payload_count = (int)payload->DataSize / (int)sizeof(payload_items[0]);
|
||||||
|
if (payload_count == 1)
|
||||||
|
ImGui::Text("Object %05d: %s", payload_items[0], ExampleNames[payload_items[0] % IM_ARRAYSIZE(ExampleNames)]);
|
||||||
|
else
|
||||||
|
ImGui::Text("Dragging %d objects", payload_count);
|
||||||
|
|
||||||
|
ImGui::EndDragDropSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (widget_type == WidgetType_TreeNode && item_is_open)
|
||||||
|
ImGui::TreePop();
|
||||||
|
|
||||||
// Right-click: context menu
|
// Right-click: context menu
|
||||||
if (ImGui::BeginPopupContextItem())
|
if (ImGui::BeginPopupContextItem())
|
||||||
{
|
{
|
||||||
|
@ -7306,10 +7306,9 @@ void ImGui::MultiSelectItemHeader(ImGuiID id, bool* p_selected, ImGuiButtonFlags
|
|||||||
// Alter button behavior flags
|
// Alter button behavior flags
|
||||||
// To handle drag and drop of multiple items we need to avoid clearing selection on click.
|
// To handle drag and drop of multiple items we need to avoid clearing selection on click.
|
||||||
// Enabling this test makes actions using CTRL+SHIFT delay their effect on MouseUp which is annoying, but it allows drag and drop of multiple items.
|
// Enabling this test makes actions using CTRL+SHIFT delay their effect on MouseUp which is annoying, but it allows drag and drop of multiple items.
|
||||||
// FIXME-MULTISELECT: Consider opt-in for drag and drop behavior in ImGuiMultiSelectFlags?
|
|
||||||
ImGuiButtonFlags button_flags = *p_button_flags;
|
ImGuiButtonFlags button_flags = *p_button_flags;
|
||||||
button_flags |= ImGuiButtonFlags_NoHoveredOnFocus;
|
button_flags |= ImGuiButtonFlags_NoHoveredOnFocus;
|
||||||
if (!selected || (g.ActiveId == id && g.ActiveIdHasBeenPressedBefore))
|
if ((!selected || (g.ActiveId == id && g.ActiveIdHasBeenPressedBefore)) && !(ms->Flags & ImGuiMultiSelectFlags_SelectOnClickRelease))
|
||||||
button_flags = (button_flags | ImGuiButtonFlags_PressedOnClick) & ~ImGuiButtonFlags_PressedOnClickRelease;
|
button_flags = (button_flags | ImGuiButtonFlags_PressedOnClick) & ~ImGuiButtonFlags_PressedOnClickRelease;
|
||||||
else
|
else
|
||||||
button_flags |= ImGuiButtonFlags_PressedOnClickRelease;
|
button_flags |= ImGuiButtonFlags_PressedOnClickRelease;
|
||||||
|
Loading…
Reference in New Issue
Block a user