MultiSelect: Shallow tweaks/refactors.
Including moving IsFocused back internally for now.
This commit is contained in:
parent
a05700e327
commit
78cb1661cb
46
imgui.h
46
imgui.h
@ -2754,6 +2754,7 @@ enum ImGuiMultiSelectFlags_
|
||||
// you may as well not bother with clipping, as the cost should be negligible (as least on Dear ImGui side).
|
||||
// If you are not sure, always start without clipping and you can work your way to the more optimized version afterwards.
|
||||
// - The void* RangeSrc/RangeDst value represent a selectable object. They are the values you pass to SetNextItemSelectionUserData().
|
||||
// Most likely you will want to store an index here.
|
||||
// Storing an integer index is the easiest thing to do, as SetRange requests will give you two end points and you will need to interpolate
|
||||
// between them to honor range selection. But the code never assume that sortable integers are used (you may store pointers to your object,
|
||||
// and then from the pointer have your own way of iterating from RangeSrc to RangeDst).
|
||||
@ -2761,35 +2762,36 @@ enum ImGuiMultiSelectFlags_
|
||||
// e.g. instructive selection (store a bool inside each object), external array (store an array aside from your objects),
|
||||
// hash/map/set (store only selected items in a hash/map/set), or other structures (store indices in an interval tree), etc.
|
||||
// Usage flow:
|
||||
// 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.
|
||||
// (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]
|
||||
// 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.
|
||||
// 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.
|
||||
// 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.
|
||||
// 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)
|
||||
// Begin
|
||||
// 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.
|
||||
// (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.
|
||||
// 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]
|
||||
// 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; }
|
||||
// 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()).
|
||||
// When cannot return a "IsItemSelected()" value because we need to consider clipped/unprocessed items, this is why we return a "Toggle" event instead.
|
||||
// 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)
|
||||
// 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)
|
||||
// If you submit all items (no clipper), Step 2 and 3 and will be handled by Selectable() on a per-item basis.
|
||||
struct ImGuiMultiSelectData
|
||||
{
|
||||
bool IsFocused; // Begin // Set if currently focusing the selection scope (any item of the selection). May be used if you have custom shortcut associated to selection.
|
||||
bool RequestClear; // Begin, End // Request user to clear selection
|
||||
bool RequestSelectAll; // Begin, End // Request user to select all
|
||||
bool RequestSetRange; // End // Request user to set or clear selection in the [RangeSrc..RangeDst] range
|
||||
bool RangeSrcPassedBy; // In loop // (If clipping) Need to be set by user if RangeSrc was part of the clipped set before submitting the visible items. Ignore if not clipping.
|
||||
bool RangeValue; // End // End: parameter from RequestSetRange request. True = Select Range, False = Unselect range.
|
||||
void* RangeSrc; // Begin, End // End: parameter from RequestSetRange request + you need to save this value so you can pass it again next frame. / Begin: this is the value you passed to BeginMultiSelect()
|
||||
void* RangeDst; // End // End: parameter from RequestSetRange request.
|
||||
int RangeDirection; // End // End: parameter from RequestSetRange request. +1 if RangeSrc came before RangeDst, -1 otherwise. Available as an indicator in case you cannot infer order from the void* values.
|
||||
bool RequestClear; // Begin, End // 1. Request user to clear selection
|
||||
bool RequestSelectAll; // Begin, End // 2. Request user to select all
|
||||
bool RequestSetRange; // End // 3. Request user to set or clear selection in the [RangeSrc..RangeDst] range
|
||||
bool RangeSrcPassedBy; // Loop // (If clipping) Need to be set by user if RangeSrc was part of the clipped set before submitting the visible items. Ignore if not clipping.
|
||||
bool RangeValue; // End // End: parameter from RequestSetRange request. true = Select Range, false = Unselect Range.
|
||||
void* RangeSrc; // Begin, End // End: parameter from RequestSetRange request + you need to save this value so you can pass it again next frame. / Begin: this is the value you passed to BeginMultiSelect()
|
||||
void* RangeDst; // End // End: parameter from RequestSetRange request.
|
||||
int RangeDirection; // End // End: parameter from RequestSetRange request. +1 if RangeSrc came before RangeDst, -1 otherwise. Available as an indicator in case you cannot infer order from the void* values.
|
||||
|
||||
ImGuiMultiSelectData() { Clear(); }
|
||||
void Clear()
|
||||
{
|
||||
IsFocused = false;
|
||||
RequestClear = RequestSelectAll = RequestSetRange = RangeSrcPassedBy = RangeValue = false;
|
||||
RangeSrc = RangeDst = NULL;
|
||||
RangeDirection = 0;
|
||||
|
@ -608,6 +608,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
|
||||
static void ShowDemoWindowWidgets()
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Widgets");
|
||||
//ImGui::SetNextItemOpen(true, ImGuiCond_Once);
|
||||
if (!ImGui::CollapsingHeader("Widgets"))
|
||||
return;
|
||||
|
||||
@ -1353,6 +1354,7 @@ static void ShowDemoWindowWidgets()
|
||||
}
|
||||
|
||||
IMGUI_DEMO_MARKER("Widgets/Selectables");
|
||||
//ImGui::SetNextItemOpen(true, ImGuiCond_Once);
|
||||
if (ImGui::TreeNode("Selectables"))
|
||||
{
|
||||
// Selectable() has 2 overloads:
|
||||
@ -2759,26 +2761,28 @@ static void ShowDemoWindowWidgets()
|
||||
}
|
||||
}
|
||||
|
||||
// [Advanced] Helper class to simulate storage of a multi-selection state, used by the advanced multi-selection demos.
|
||||
// [Advanced] Helper class to simulate storage of a multi-selection state, used by the BeginMultiSelect() demos.
|
||||
// We use ImGuiStorage (simple key->value storage) to avoid external dependencies but it's probably not optimal.
|
||||
// To store a single-selection:
|
||||
// - You only need a single variable and don't need any of this!
|
||||
// To store a multi-selection, in your real application you could:
|
||||
// - Use intrusively stored selection (e.g. 'bool IsSelected' inside your object). This is by far the simplest
|
||||
// way to store your selection data, but it means you cannot have multiple simultaneous views over your objects.
|
||||
// This is what may of the simpler demos in this file are using (so they are not using this class).
|
||||
// - Otherwise, any externally stored unordered_set/set/hash/map/interval trees (storing indices, objects id, etc.)
|
||||
// This is what many of the simpler demos in this file are using (so they are not using this class).
|
||||
// - Use external storage: e.g. unordered_set/set/hash/map/interval trees (storing indices, objects id, etc.)
|
||||
// are generally appropriate. Even a large array of bool might work for you...
|
||||
// - If you need to handle extremely large selections, it might be advantageous to support a "negative" mode in
|
||||
// your storage, so "Select All" becomes "Negative=1, Clear" and then sparse unselect can add to the storage.
|
||||
// your storage, so "Select All" becomes "Negative=1 + Clear" and then sparse unselect can add to the storage.
|
||||
// About RefItem:
|
||||
// - The MultiSelect API requires you to store information about the reference/pivot item (generally the last clicked item).
|
||||
// - The BeginMultiSelect() API requires you to store information about the reference/pivot item (generally the last clicked item).
|
||||
struct ExampleSelection
|
||||
{
|
||||
ImGuiStorage Storage;
|
||||
// Data
|
||||
ImGuiStorage Storage; // Selection set
|
||||
int SelectionSize; // Number of selected items (== number of 1 in the Storage, maintained by this class)
|
||||
int RangeRef; // Reference/pivot item (generally last clicked item)
|
||||
|
||||
// Functions
|
||||
ExampleSelection() { RangeRef = 0; Clear(); }
|
||||
void Clear() { Storage.Clear(); SelectionSize = 0; }
|
||||
bool GetSelected(int n) const { return Storage.GetInt((ImGuiID)n, 0) != 0; }
|
||||
@ -2791,11 +2795,20 @@ struct ExampleSelection
|
||||
// you will need a way to iterate from one object to another given the ID you use.
|
||||
// You are likely to need some kind of data structure to convert 'view index' <> 'object ID'.
|
||||
// FIXME-MULTISELECT: Would be worth providing a demo of doing this.
|
||||
// FIXME-MULTISELECT: SetRange() is currently very inefficient since it doesn't take advantage of the fact that ImGuiStorage stores sorted key.
|
||||
void SetRange(int n1, int n2, bool v) { if (n2 < n1) { int tmp = n2; n2 = n1; n1 = tmp; } for (int n = n1; n <= n2; n++) SetSelected(n, v); }
|
||||
void SelectAll(int count) { Storage.Data.resize(count); for (int idx = 0; idx < count; idx++) Storage.Data[idx] = ImGuiStoragePair((ImGuiID)idx, 1); SelectionSize = count; } // This could be using SetRange(), but it this way is faster.
|
||||
// FIXME-MULTISELECT: This implementation of SetRange() is inefficient because it doesn't take advantage of the fact that ImGuiStorage stores sorted key.
|
||||
void SetRange(int a, int b, bool v) { if (b < a) { int tmp = b; b = a; a = tmp; } for (int n = a; n <= b; n++) SetSelected(n, v); }
|
||||
void SelectAll(int count) { Storage.Data.resize(count); for (int idx = 0; idx < count; idx++) Storage.Data[idx] = ImGuiStoragePair((ImGuiID)idx, 1); SelectionSize = count; } // This could be using SetRange(), but it this way is faster.
|
||||
|
||||
// Apply requests coming from BeginMultiSelect() and EndMultiSelect(). Must be done in this order! Order->SelectAll->SetRange.
|
||||
void ApplyRequests(ImGuiMultiSelectData* ms_data, int items_count)
|
||||
{
|
||||
if (ms_data->RequestClear) { Clear(); }
|
||||
if (ms_data->RequestSelectAll) { SelectAll(items_count); }
|
||||
if (ms_data->RequestSetRange) { SetRange((int)(intptr_t)ms_data->RangeSrc, (int)(intptr_t)ms_data->RangeDst, ms_data->RangeValue ? 1 : 0); }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void ShowDemoWindowMultiSelect()
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Widgets/Selection State");
|
||||
@ -2864,8 +2877,7 @@ static void ShowDemoWindowMultiSelect()
|
||||
{
|
||||
ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape;
|
||||
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->RequestSelectAll) { selection.SelectAll(ITEMS_COUNT); }
|
||||
selection.ApplyRequests(multi_select_data, ITEMS_COUNT);
|
||||
|
||||
for (int n = 0; n < ITEMS_COUNT; n++)
|
||||
{
|
||||
@ -2886,9 +2898,7 @@ static void ShowDemoWindowMultiSelect()
|
||||
// Apply multi-select requests
|
||||
multi_select_data = ImGui::EndMultiSelect();
|
||||
selection.RangeRef = (int)(intptr_t)multi_select_data->RangeSrc;
|
||||
if (multi_select_data->RequestClear) { selection.Clear(); }
|
||||
if (multi_select_data->RequestSelectAll) { selection.SelectAll(ITEMS_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); }
|
||||
selection.ApplyRequests(multi_select_data, ITEMS_COUNT);
|
||||
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
@ -2903,7 +2913,7 @@ static void ShowDemoWindowMultiSelect()
|
||||
// - Showcase having multiple multi-selection scopes in the same window.
|
||||
// - Showcase using inside a table.
|
||||
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)"))
|
||||
{
|
||||
// Options
|
||||
@ -2952,8 +2962,7 @@ static void ShowDemoWindowMultiSelect()
|
||||
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->RequestSelectAll) { selection->SelectAll(ITEMS_COUNT); }
|
||||
selection->ApplyRequests(multi_select_data, ITEMS_COUNT);
|
||||
|
||||
if (multiple_selection_scopes)
|
||||
ImGui::Text("Selection size: %d", selection->GetSelectionSize()); // Draw counter below Separator and after BeginMultiSelect()
|
||||
@ -2971,8 +2980,8 @@ static void ShowDemoWindowMultiSelect()
|
||||
clipper.Begin(ITEMS_COUNT);
|
||||
while (clipper.Step())
|
||||
{
|
||||
// IF clipping is used you need to set 'RangeSrcPassedBy = true' if RangeRef was passed over.
|
||||
if (clipper.DisplayStart > selection->RangeRef)
|
||||
// IF clipping is used you need to set 'RangeSrcPassedBy = true' if RangeSrc was passed over.
|
||||
if ((int)(intptr_t)multi_select_data->RangeSrc <= clipper.DisplayStart)
|
||||
multi_select_data->RangeSrcPassedBy = true;
|
||||
|
||||
for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
|
||||
@ -3052,9 +3061,7 @@ static void ShowDemoWindowMultiSelect()
|
||||
// Apply multi-select requests
|
||||
multi_select_data = ImGui::EndMultiSelect();
|
||||
selection->RangeRef = (int)(intptr_t)multi_select_data->RangeSrc;
|
||||
if (multi_select_data->RequestClear) { selection->Clear(); }
|
||||
if (multi_select_data->RequestSelectAll) { selection->SelectAll(ITEMS_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); }
|
||||
selection->ApplyRequests(multi_select_data, ITEMS_COUNT);
|
||||
|
||||
if (widget_type == WidgetType_TreeNode)
|
||||
ImGui::PopStyleVar();
|
||||
|
@ -1715,15 +1715,19 @@ struct ImGuiOldColumns
|
||||
|
||||
struct IMGUI_API ImGuiMultiSelectState
|
||||
{
|
||||
ImGuiID FocusScopeId; // Same as g.CurrentFocusScopeId (unless another selection scope was pushed manually)
|
||||
ImGuiID FocusScopeId; // Copied from g.CurrentFocusScopeId (unless another selection scope was pushed manually)
|
||||
ImGuiMultiSelectFlags Flags;
|
||||
ImGuiKeyChord KeyMods;
|
||||
ImGuiWindow* Window;
|
||||
ImGuiMultiSelectData In; // The In requests are set and returned by BeginMultiSelect()
|
||||
ImGuiMultiSelectData Out; // The Out requests are finalized and returned by EndMultiSelect()
|
||||
bool IsFocused; // Set if currently focusing the selection scope (any item of the selection). May be used if you have custom shortcut associated to selection.
|
||||
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.
|
||||
//ImRect Rect; // Extent of selection scope between BeginMultiSelect() / EndMultiSelect(), used by ImGuiMultiSelectFlags_ClearOnClickRectVoid.
|
||||
|
||||
ImGuiMultiSelectState() { Clear(); }
|
||||
void Clear() { FocusScopeId = 0; In.Clear(); Out.Clear(); InRangeDstPassedBy = InRequestSetRangeNav = false; }
|
||||
void Clear() { FocusScopeId = 0; Flags = ImGuiMultiSelectFlags_None; KeyMods = ImGuiMod_None; Window = NULL; In.Clear(); Out.Clear(); InRangeDstPassedBy = InRequestSetRangeNav = false; }
|
||||
};
|
||||
|
||||
#endif // #ifdef IMGUI_HAS_MULTI_SELECT
|
||||
@ -2121,10 +2125,7 @@ struct ImGuiContext
|
||||
ImVec2 NavWindowingAccumDeltaSize;
|
||||
|
||||
// Range-Select/Multi-Select
|
||||
ImGuiWindow* MultiSelectEnabledWindow; // FIXME-MULTISELECT: We currently don't support recursing/stacking multi-select
|
||||
ImGuiMultiSelectFlags MultiSelectFlags;
|
||||
ImGuiMultiSelectState MultiSelectState;
|
||||
ImGuiKeyChord MultiSelectKeyMods;
|
||||
ImGuiMultiSelectState MultiSelectState; // FIXME-MULTISELECT: We currently don't support recursing/stacking multi-select
|
||||
|
||||
// Render
|
||||
float DimBgRatio; // 0.0..1.0 animation when fading in a dimming background (for modal window and CTRL+TAB list)
|
||||
@ -2389,10 +2390,6 @@ struct ImGuiContext
|
||||
NavWindowingToggleLayer = false;
|
||||
NavWindowingToggleKey = ImGuiKey_None;
|
||||
|
||||
MultiSelectEnabledWindow = NULL;
|
||||
MultiSelectFlags = ImGuiMultiSelectFlags_None;
|
||||
MultiSelectKeyMods = ImGuiMod_None;
|
||||
|
||||
DimBgRatio = 0.0f;
|
||||
|
||||
DragDropActive = DragDropWithinSource = DragDropWithinTarget = false;
|
||||
|
@ -6464,7 +6464,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiID storage_id, ImGuiTreeNodeFlags
|
||||
const bool was_selected = selected;
|
||||
|
||||
// Multi-selection support (header)
|
||||
const bool is_multi_select = (g.MultiSelectEnabledWindow == window);
|
||||
const bool is_multi_select = (g.MultiSelectState.Window == window);
|
||||
if (is_multi_select)
|
||||
{
|
||||
MultiSelectItemHeader(id, &selected);
|
||||
@ -6816,7 +6816,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
||||
if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; }
|
||||
|
||||
// Multi-selection support (header)
|
||||
const bool is_multi_select = (g.MultiSelectEnabledWindow == window);
|
||||
const bool is_multi_select = (g.MultiSelectState.Window == window);
|
||||
const bool was_selected = selected;
|
||||
if (is_multi_select)
|
||||
{
|
||||
@ -7126,23 +7126,19 @@ ImGuiMultiSelectData* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, void*
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
|
||||
IM_ASSERT(g.MultiSelectEnabledWindow == NULL); // No recursion allowed yet (we could allow it if we deem it useful)
|
||||
IM_ASSERT(g.MultiSelectFlags == 0);
|
||||
IM_ASSERT(g.MultiSelectState.FocusScopeId == 0);
|
||||
ImGuiMultiSelectState* ms = &g.MultiSelectState;
|
||||
IM_ASSERT(ms->Window == NULL && ms->Flags == 0 && ms->FocusScopeId == 0); // No recursion allowed yet (we could allow it if we deem it useful)
|
||||
|
||||
// FIXME: BeginFocusScope()
|
||||
ImGuiMultiSelectState* ms = &g.MultiSelectState;
|
||||
ms->Clear();
|
||||
ms->FocusScopeId = window->IDStack.back();
|
||||
ms->Flags = flags;
|
||||
ms->Window = window;
|
||||
ms->IsFocused = (ms->FocusScopeId == g.NavFocusScopeId);
|
||||
PushFocusScope(ms->FocusScopeId);
|
||||
g.MultiSelectEnabledWindow = window;
|
||||
g.MultiSelectFlags = flags;
|
||||
|
||||
// Report focus
|
||||
ms->In.IsFocused = ms->Out.IsFocused = (ms->FocusScopeId == g.NavFocusScopeId);
|
||||
|
||||
// Use copy of keyboard mods at the time of the request, otherwise we would requires mods to be held for an extra frame.
|
||||
g.MultiSelectKeyMods = g.NavJustMovedToId ? g.NavJustMovedToKeyMods : g.IO.KeyMods;
|
||||
ms->KeyMods = g.NavJustMovedToId ? g.NavJustMovedToKeyMods : g.IO.KeyMods;
|
||||
|
||||
if ((flags & ImGuiMultiSelectFlags_NoMultiSelect) == 0)
|
||||
{
|
||||
@ -7154,14 +7150,14 @@ ImGuiMultiSelectData* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, void*
|
||||
// FIXME: Polling key mods after the fact (frame following the move request) is incorrect, but latching it would requires non-trivial change in MultiSelectItemFooter()
|
||||
if (g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == ms->FocusScopeId && g.NavJustMovedToHasSelectionData)
|
||||
{
|
||||
if (g.MultiSelectKeyMods & ImGuiMod_Shift)
|
||||
if (ms->KeyMods & ImGuiMod_Shift)
|
||||
ms->InRequestSetRangeNav = true;
|
||||
if ((g.MultiSelectKeyMods & (ImGuiMod_Ctrl | ImGuiMod_Shift)) == 0)
|
||||
if ((ms->KeyMods & (ImGuiMod_Ctrl | ImGuiMod_Shift)) == 0)
|
||||
ms->In.RequestClear = true;
|
||||
}
|
||||
|
||||
// Shortcuts
|
||||
if (ms->In.IsFocused)
|
||||
if (ms->IsFocused)
|
||||
{
|
||||
// Select All helper shortcut (CTRL+A)
|
||||
// Note: we are comparing FocusScope so we don't need to be testing for IsWindowFocused()
|
||||
@ -7174,10 +7170,8 @@ ImGuiMultiSelectData* ImGui::BeginMultiSelect(ImGuiMultiSelectFlags flags, void*
|
||||
ms->In.RequestClear = true;
|
||||
}
|
||||
|
||||
#ifdef IMGUI_DEBUG_MULTISELECT
|
||||
if (ms->In.RequestClear) IMGUI_DEBUG_LOG("BeginMultiSelect: RequestClear\n");
|
||||
if (ms->In.RequestSelectAll) IMGUI_DEBUG_LOG("BeginMultiSelect: RequestSelectAll\n");
|
||||
#endif
|
||||
//if (ms->In.RequestClear) IMGUI_DEBUG_LOG("BeginMultiSelect: RequestClear\n");
|
||||
//if (ms->In.RequestSelectAll) IMGUI_DEBUG_LOG("BeginMultiSelect: RequestSelectAll\n");
|
||||
|
||||
return &ms->In;
|
||||
}
|
||||
@ -7190,7 +7184,7 @@ ImGuiMultiSelectData* ImGui::EndMultiSelect()
|
||||
|
||||
// Clear selection when clicking void?
|
||||
// We specifically test for IsMouseDragPastThreshold(0) == false to allow box-selection!
|
||||
if (g.MultiSelectFlags & ImGuiMultiSelectFlags_ClearOnClickWindowVoid)
|
||||
if (ms->Flags & ImGuiMultiSelectFlags_ClearOnClickWindowVoid)
|
||||
if (IsWindowHovered() && g.HoveredId == 0)
|
||||
if (IsMouseReleased(0) && IsMouseDragPastThreshold(0) == false && g.IO.KeyMods == ImGuiMod_None)
|
||||
{
|
||||
@ -7199,18 +7193,16 @@ ImGuiMultiSelectData* ImGui::EndMultiSelect()
|
||||
}
|
||||
|
||||
// Unwind
|
||||
if (g.MultiSelectFlags & ImGuiMultiSelectFlags_NoUnselect)
|
||||
if (ms->Flags & ImGuiMultiSelectFlags_NoUnselect)
|
||||
ms->Out.RangeValue = true;
|
||||
g.MultiSelectState.FocusScopeId = 0;
|
||||
ms->FocusScopeId = 0;
|
||||
ms->Window = NULL;
|
||||
ms->Flags = ImGuiMultiSelectFlags_None;
|
||||
PopFocusScope();
|
||||
g.MultiSelectEnabledWindow = NULL;
|
||||
g.MultiSelectFlags = ImGuiMultiSelectFlags_None;
|
||||
|
||||
#ifdef IMGUI_DEBUG_MULTISELECT
|
||||
if (ms->Out.RequestClear) IMGUI_DEBUG_LOG("EndMultiSelect: RequestClear\n");
|
||||
if (ms->Out.RequestSelectAll) IMGUI_DEBUG_LOG("EndMultiSelect: RequestSelectAll\n");
|
||||
if (ms->Out.RequestSetRange) IMGUI_DEBUG_LOG("EndMultiSelect: RequestSetRange %p..%p = %d\n", ms->Out.RangeSrc, ms->Out.RangeDst, ms->Out.RangeValue);
|
||||
#endif
|
||||
//if (ms->Out.RequestClear) IMGUI_DEBUG_LOG("EndMultiSelect: RequestClear\n");
|
||||
//if (ms->Out.RequestSelectAll) IMGUI_DEBUG_LOG("EndMultiSelect: RequestSelectAll\n");
|
||||
//if (ms->Out.RequestSetRange) IMGUI_DEBUG_LOG("EndMultiSelect: RequestSetRange %p..%p = %d\n", ms->Out.RangeSrc, ms->Out.RangeDst, ms->Out.RangeValue);
|
||||
|
||||
return &ms->Out;
|
||||
}
|
||||
@ -7257,13 +7249,13 @@ void ImGui::MultiSelectItemHeader(ImGuiID id, bool* p_selected)
|
||||
if (ms->InRequestSetRangeNav)
|
||||
{
|
||||
IM_ASSERT(id != 0);
|
||||
IM_ASSERT((g.MultiSelectKeyMods & ImGuiMod_Shift) != 0);
|
||||
IM_ASSERT((ms->KeyMods & ImGuiMod_Shift) != 0);
|
||||
const bool is_range_dst = !ms->InRangeDstPassedBy && g.NavJustMovedToId == id; // Assume that g.NavJustMovedToId is not clipped.
|
||||
if (is_range_dst)
|
||||
ms->InRangeDstPassedBy = true;
|
||||
if (is_range_src || is_range_dst || ms->In.RangeSrcPassedBy != ms->InRangeDstPassedBy)
|
||||
selected = ms->In.RangeValue;
|
||||
else if ((g.MultiSelectKeyMods & ImGuiMod_Ctrl) == 0)
|
||||
else if ((ms->KeyMods & ImGuiMod_Ctrl) == 0)
|
||||
selected = false;
|
||||
}
|
||||
|
||||
@ -7278,11 +7270,11 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
|
||||
|
||||
void* item_data = (void*)g.NextItemData.SelectionUserData;
|
||||
|
||||
const bool is_multiselect = (ms->Flags & ImGuiMultiSelectFlags_NoMultiSelect) == 0;
|
||||
bool selected = *p_selected;
|
||||
bool pressed = *p_pressed;
|
||||
const bool is_multiselect = (g.MultiSelectFlags & ImGuiMultiSelectFlags_NoMultiSelect) == 0;
|
||||
bool is_ctrl = (g.MultiSelectKeyMods & ImGuiMod_Ctrl) != 0;
|
||||
bool is_shift = (g.MultiSelectKeyMods & ImGuiMod_Shift) != 0;
|
||||
bool is_ctrl = (ms->KeyMods & ImGuiMod_Ctrl) != 0;
|
||||
bool is_shift = (ms->KeyMods & ImGuiMod_Shift) != 0;
|
||||
|
||||
// Auto-select as you navigate a list
|
||||
if (g.NavJustMovedToId == id)
|
||||
@ -7334,7 +7326,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
|
||||
}
|
||||
else
|
||||
{
|
||||
selected = (!is_ctrl || (g.MultiSelectFlags & ImGuiMultiSelectFlags_NoUnselect)) ? true : !selected;
|
||||
selected = (!is_ctrl || (ms->Flags & ImGuiMultiSelectFlags_NoUnselect)) ? true : !selected;
|
||||
ms->Out.RangeSrc = ms->Out.RangeDst = item_data;
|
||||
ms->Out.RangeValue = selected;
|
||||
}
|
||||
@ -7371,7 +7363,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
|
||||
}
|
||||
|
||||
// Update/store the selection state of the Source item (used by CTRL+SHIFT, when Source is unselected we perform a range unselect)
|
||||
if (ms->Out.RangeSrc == item_data && is_ctrl && is_shift && is_multiselect && !(g.MultiSelectFlags & ImGuiMultiSelectFlags_NoUnselect))
|
||||
if (ms->Out.RangeSrc == item_data && is_ctrl && is_shift && is_multiselect && !(ms->Flags & ImGuiMultiSelectFlags_NoUnselect))
|
||||
ms->Out.RangeValue = selected;
|
||||
|
||||
*p_selected = selected;
|
||||
|
Loading…
Reference in New Issue
Block a user