mirror of
https://github.com/ocornut/imgui.git
synced 2024-11-23 21:09:01 +08:00
Internal: Nav,MultiSelect: import ImGuiSelectionUserData, SetNextItemSelectionUserData() from MultiSelect. Track NavLastValidSelectionUserData as a convenience.
This commit is contained in:
parent
f336e639e9
commit
c86ce70968
@ -55,7 +55,7 @@ Other changes:
|
||||
|
||||
- Tooltips: made using SetItemTooltip()/IsItemHovered(ImGuiHoveredFlags_ForTooltip) defaults to
|
||||
activate tooltips on disabled items. This is done by adding ImGuiHoveredFlags_AllowWhenDisabled
|
||||
to the default value of style.HoverFlagsForTooltipMouse/HoverFlagsForTooltipNav. (##1485)
|
||||
to the default value of style.HoverFlagsForTooltipMouse/HoverFlagsForTooltipNav. (#1485)
|
||||
- Nav: Tabbing always enable nav highlight when ImGuiConfigFlags_NavEnableKeyboard is set.
|
||||
Previously was inconsistent and only enabled when stepping through a non-input item.
|
||||
(#6802, #3092, #5759, #787)
|
||||
|
24
imgui.cpp
24
imgui.cpp
@ -7065,6 +7065,7 @@ void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags)
|
||||
g.NavLayer = ImGuiNavLayer_Main;
|
||||
g.NavFocusScopeId = window ? window->NavRootFocusScopeId : 0;
|
||||
g.NavIdIsAlive = false;
|
||||
g.NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid;
|
||||
|
||||
// Close popups if any
|
||||
ClosePopupsOverWindow(window, false);
|
||||
@ -9489,6 +9490,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
|
||||
g.LastItemData.NavRect = nav_bb_arg ? *nav_bb_arg : bb;
|
||||
g.LastItemData.InFlags = g.CurrentItemFlags | g.NextItemData.ItemFlags | extra_flags;
|
||||
g.LastItemData.StatusFlags = ImGuiItemStatusFlags_None;
|
||||
// Note: we don't copy 'g.NextItemData.SelectionUserData' to an hypothetical g.LastItemData.SelectionUserData: since the former is not cleared.
|
||||
|
||||
// Directional navigation processing
|
||||
if (id != 0)
|
||||
@ -10800,6 +10802,7 @@ void ImGui::SetNavWindow(ImGuiWindow* window)
|
||||
{
|
||||
IMGUI_DEBUG_LOG_FOCUS("[focus] SetNavWindow(\"%s\")\n", window ? window->Name : "<NULL>");
|
||||
g.NavWindow = window;
|
||||
g.NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid;
|
||||
}
|
||||
g.NavInitRequest = g.NavMoveSubmitted = g.NavMoveScoringItems = false;
|
||||
NavUpdateAnyRequestFlag();
|
||||
@ -11019,6 +11022,11 @@ static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result)
|
||||
result->FocusScopeId = g.CurrentFocusScopeId;
|
||||
result->InFlags = g.LastItemData.InFlags;
|
||||
result->RectRel = WindowRectAbsToRel(window, g.LastItemData.NavRect);
|
||||
if (result->InFlags & ImGuiItemFlags_HasSelectionUserData)
|
||||
{
|
||||
IM_ASSERT(g.NextItemData.SelectionUserData != ImGuiSelectionUserData_Invalid);
|
||||
result->SelectionUserData = g.NextItemData.SelectionUserData; // INTENTIONAL: At this point this field is not cleared in NextItemData. Avoid unnecessary copy to LastItemData.
|
||||
}
|
||||
}
|
||||
|
||||
// True when current work location may be scrolled horizontally when moving left / right.
|
||||
@ -11031,7 +11039,7 @@ void ImGui::NavUpdateCurrentWindowIsScrollPushableX()
|
||||
}
|
||||
|
||||
// We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above)
|
||||
// This is called after LastItemData is set.
|
||||
// This is called after LastItemData is set, but NextItemData is also still valid.
|
||||
static void ImGui::NavProcessItem()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@ -11095,6 +11103,11 @@ static void ImGui::NavProcessItem()
|
||||
g.NavLayer = window->DC.NavLayerCurrent;
|
||||
g.NavFocusScopeId = g.CurrentFocusScopeId;
|
||||
g.NavIdIsAlive = true;
|
||||
if (g.LastItemData.InFlags & ImGuiItemFlags_HasSelectionUserData)
|
||||
{
|
||||
IM_ASSERT(g.NextItemData.SelectionUserData != ImGuiSelectionUserData_Invalid);
|
||||
g.NavLastValidSelectionUserData = g.NextItemData.SelectionUserData; // INTENTIONAL: At this point this field is not cleared in NextItemData. Avoid unnecessary copy to LastItemData.
|
||||
}
|
||||
window->NavRectRel[window->DC.NavLayerCurrent] = WindowRectAbsToRel(window, nav_bb); // Store item bounding box (relative to window position)
|
||||
}
|
||||
}
|
||||
@ -11206,7 +11219,7 @@ void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGu
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.NavMoveScoringItems = false;
|
||||
g.LastItemData.ID = tree_node_data->ID;
|
||||
g.LastItemData.InFlags = tree_node_data->InFlags;
|
||||
g.LastItemData.InFlags = tree_node_data->InFlags & ~ImGuiItemFlags_HasSelectionUserData; // Losing SelectionUserData, recovered next-frame (cheaper).
|
||||
g.LastItemData.NavRect = tree_node_data->NavRect;
|
||||
NavApplyItemToResult(result); // Result this instead of implementing a NavApplyPastTreeNodeToResult()
|
||||
NavClearPreferredPosForAxis(ImGuiAxis_Y);
|
||||
@ -11273,6 +11286,7 @@ void ImGui::NavRestoreLayer(ImGuiNavLayer layer)
|
||||
{
|
||||
ImGuiWindow* prev_nav_window = g.NavWindow;
|
||||
g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow); // FIXME-NAV: Should clear ongoing nav requests?
|
||||
g.NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid;
|
||||
if (prev_nav_window)
|
||||
IMGUI_DEBUG_LOG_FOCUS("[focus] NavRestoreLayer: from \"%s\" to SetNavWindow(\"%s\")\n", prev_nav_window->Name, g.NavWindow->Name);
|
||||
}
|
||||
@ -11568,6 +11582,8 @@ void ImGui::NavInitRequestApplyResult()
|
||||
IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: ApplyResult: NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name);
|
||||
SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel);
|
||||
g.NavIdIsAlive = true; // Mark as alive from previous frame as we got a result
|
||||
if (result->SelectionUserData != ImGuiSelectionUserData_Invalid)
|
||||
g.NavLastValidSelectionUserData = result->SelectionUserData;
|
||||
if (g.NavInitRequestFromMove)
|
||||
NavRestoreHighlightAfterMove();
|
||||
}
|
||||
@ -11799,6 +11815,7 @@ void ImGui::NavMoveRequestApplyResult()
|
||||
{
|
||||
IMGUI_DEBUG_LOG_FOCUS("[focus] NavMoveRequest: SetNavWindow(\"%s\")\n", result->Window->Name);
|
||||
g.NavWindow = result->Window;
|
||||
g.NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid;
|
||||
}
|
||||
if (g.ActiveId != result->ID)
|
||||
ClearActiveID();
|
||||
@ -11816,6 +11833,8 @@ void ImGui::NavMoveRequestApplyResult()
|
||||
IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name);
|
||||
ImVec2 preferred_scoring_pos_rel = g.NavWindow->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer];
|
||||
SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel);
|
||||
if (result->SelectionUserData != ImGuiSelectionUserData_Invalid)
|
||||
g.NavLastValidSelectionUserData = result->SelectionUserData;
|
||||
|
||||
// Restore last preferred position for current axis
|
||||
// (storing in RootWindowForNav-> as the info is desirable at the beginning of a Move Request. In theory all storage should use RootWindowForNav..)
|
||||
@ -14113,6 +14132,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
||||
Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer);
|
||||
DebugLocateItemOnHover(g.NavId);
|
||||
Text("NavInputSource: %s", GetInputSourceName(g.NavInputSource));
|
||||
Text("NavLastValidSelectionUserData = %" IM_PRId64 " (0x%" IM_PRIX64 ")", g.NavLastValidSelectionUserData, g.NavLastValidSelectionUserData);
|
||||
Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible);
|
||||
Text("NavActivateId/DownId/PressedId: %08X/%08X/%08X", g.NavActivateId, g.NavActivateDownId, g.NavActivatePressedId);
|
||||
Text("NavActivateFlags: %04X", g.NavActivateFlags);
|
||||
|
@ -309,6 +309,18 @@ namespace ImStb
|
||||
#endif
|
||||
#endif // #ifndef IM_DEBUG_BREAK
|
||||
|
||||
// Format specifiers, printing 64-bit hasn't been decently standardized...
|
||||
// In a real application you should be using PRId64 and PRIu64 from <inttypes.h> (non-windows) and on Windows define them yourself.
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define IM_PRId64 "I64d"
|
||||
#define IM_PRIu64 "I64u"
|
||||
#define IM_PRIX64 "I64X"
|
||||
#else
|
||||
#define IM_PRId64 "lld"
|
||||
#define IM_PRIu64 "llu"
|
||||
#define IM_PRIX64 "llX"
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Generic helpers
|
||||
// Note that the ImXXX helpers functions are lower-level than ImGui functions.
|
||||
@ -810,6 +822,7 @@ enum ImGuiItemFlags_
|
||||
|
||||
// Controlled by widget code
|
||||
ImGuiItemFlags_Inputable = 1 << 10, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature.
|
||||
ImGuiItemFlags_HasSelectionUserData = 1 << 11, // false // Set by SetNextItemSelectionUserData()
|
||||
};
|
||||
|
||||
// Status flags for an already submitted item
|
||||
@ -1174,6 +1187,10 @@ struct ImGuiNextWindowData
|
||||
inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; }
|
||||
};
|
||||
|
||||
// Multi-Selection item index or identifier when using SetNextItemSelectionUserData()/BeginMultiSelect()
|
||||
// (Most users are likely to use this store an item INDEX but this may be used to store a POINTER as well.)
|
||||
typedef ImS64 ImGuiSelectionUserData;
|
||||
|
||||
enum ImGuiNextItemDataFlags_
|
||||
{
|
||||
ImGuiNextItemDataFlags_None = 0,
|
||||
@ -1184,13 +1201,14 @@ enum ImGuiNextItemDataFlags_
|
||||
struct ImGuiNextItemData
|
||||
{
|
||||
ImGuiNextItemDataFlags Flags;
|
||||
ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemFlags_AllowOverlap.
|
||||
float Width; // Set by SetNextItemWidth()
|
||||
ImGuiID FocusScopeId; // Set by SetNextItemMultiSelectData() (!= 0 signify value has been set, so it's an alternate version of HasSelectionData, we don't use Flags for this because they are cleared too early. This is mostly used for debugging)
|
||||
ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemFlags_AllowOverlap.
|
||||
// Non-flags members are NOT cleared by ItemAdd() meaning they are still valid during NavProcessItem()
|
||||
float Width; // Set by SetNextItemWidth()
|
||||
ImGuiSelectionUserData SelectionUserData; // Set by SetNextItemSelectionUserData() (note that NULL/0 is a valid value, we use -1 == ImGuiSelectionUserData_Invalid to mark invalid values)
|
||||
ImGuiCond OpenCond;
|
||||
bool OpenVal; // Set by SetNextItemOpen()
|
||||
bool OpenVal; // Set by SetNextItemOpen()
|
||||
|
||||
ImGuiNextItemData() { memset(this, 0, sizeof(*this)); }
|
||||
ImGuiNextItemData() { memset(this, 0, sizeof(*this)); SelectionUserData = -1; }
|
||||
inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; ItemFlags = ImGuiItemFlags_None; } // Also cleared manually by ItemAdd()!
|
||||
};
|
||||
|
||||
@ -1528,12 +1546,13 @@ struct ImGuiNavItemData
|
||||
ImGuiID FocusScopeId; // Init,Move // Best candidate focus scope ID
|
||||
ImRect RectRel; // Init,Move // Best candidate bounding box in window relative space
|
||||
ImGuiItemFlags InFlags; // ????,Move // Best candidate item flags
|
||||
ImGuiSelectionUserData SelectionUserData;//I+Mov // Best candidate SetNextItemSelectionData() value.
|
||||
float DistBox; // Move // Best candidate box distance to current NavId
|
||||
float DistCenter; // Move // Best candidate center distance to current NavId
|
||||
float DistAxial; // Move // Best candidate axial distance to current NavId
|
||||
|
||||
ImGuiNavItemData() { Clear(); }
|
||||
void Clear() { Window = NULL; ID = FocusScopeId = 0; InFlags = 0; DistBox = DistCenter = DistAxial = FLT_MAX; }
|
||||
void Clear() { Window = NULL; ID = FocusScopeId = 0; InFlags = 0; SelectionUserData = -1; DistBox = DistCenter = DistAxial = FLT_MAX; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -1631,6 +1650,9 @@ struct ImGuiOldColumns
|
||||
// [SECTION] Multi-select support
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// We always assume that -1 is an invalid value (which works for indices and pointers)
|
||||
#define ImGuiSelectionUserData_Invalid ((ImGuiSelectionUserData)-1)
|
||||
|
||||
#ifdef IMGUI_HAS_MULTI_SELECT
|
||||
// <this is filled in 'range_select' branch>
|
||||
#endif // #ifdef IMGUI_HAS_MULTI_SELECT
|
||||
@ -1939,6 +1961,7 @@ struct ImGuiContext
|
||||
ImGuiActivateFlags NavNextActivateFlags;
|
||||
ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse
|
||||
ImGuiNavLayer NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later.
|
||||
ImGuiSelectionUserData NavLastValidSelectionUserData; // Last valid data passed to SetNextItemSelectionUser(), or -1. For current window. Not reset when focusing an item that doesn't have selection data.
|
||||
bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid
|
||||
bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default)
|
||||
bool NavDisableHighlight; // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover)
|
||||
@ -2186,6 +2209,7 @@ struct ImGuiContext
|
||||
NavJustMovedToKeyMods = ImGuiMod_None;
|
||||
NavInputSource = ImGuiInputSource_Keyboard;
|
||||
NavLayer = ImGuiNavLayer_Main;
|
||||
NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid;
|
||||
NavIdIsAlive = false;
|
||||
NavMousePosDirty = false;
|
||||
NavDisableHighlight = true;
|
||||
@ -3241,6 +3265,7 @@ namespace ImGui
|
||||
IMGUI_API void TreePushOverrideID(ImGuiID id);
|
||||
IMGUI_API void TreeNodeSetOpen(ImGuiID id, bool open);
|
||||
IMGUI_API bool TreeNodeUpdateNextOpen(ImGuiID id, ImGuiTreeNodeFlags flags); // Return open state. Consume previous SetNextItemOpen() data, if any. May return true when logging.
|
||||
IMGUI_API void SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_data);
|
||||
|
||||
// Template functions are instantiated in imgui_widgets.cpp for a finite number of types.
|
||||
// To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036).
|
||||
|
@ -19,6 +19,7 @@ Index of this file:
|
||||
// [SECTION] Widgets: TreeNode, CollapsingHeader, etc.
|
||||
// [SECTION] Widgets: Selectable
|
||||
// [SECTION] Widgets: Typing-Select support
|
||||
// [SECTION] Widgets: Multi-Select support
|
||||
// [SECTION] Widgets: ListBox
|
||||
// [SECTION] Widgets: PlotLines, PlotHistogram
|
||||
// [SECTION] Widgets: Value helpers
|
||||
@ -6759,7 +6760,15 @@ int ImGui::TypingSelectFindResult(ImGuiTypingSelectRequest* req, int items_count
|
||||
// [SECTION] Widgets: Multi-Select support
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
void ImGui::SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_data)
|
||||
{
|
||||
// Note that flags will be cleared by ItemAdd(), so it's only useful for Navigation code!
|
||||
// This designed so widgets can also cheaply set this before calling ItemAdd(), so we are not tied to MultiSelect api.
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.NextItemData.ItemFlags |= ImGuiItemFlags_HasSelectionUserData;
|
||||
g.NextItemData.SelectionUserData = selection_user_data;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// [SECTION] Widgets: ListBox
|
||||
|
Loading…
Reference in New Issue
Block a user