mirror of
https://github.com/ocornut/imgui.git
synced 2026-09-22 20:24:58 +08:00
Merge branch 'master' into docking
This commit is contained in:
+667
-1
File diff suppressed because it is too large
Load Diff
@@ -1385,9 +1385,9 @@ void ImGuiIO::ClearInputKeys()
|
||||
MouseWheel = MouseWheelH = 0.0f;
|
||||
}
|
||||
|
||||
static ImGuiInputEvent* FindLatestInputEvent(ImGuiInputEventType type, int arg = -1)
|
||||
static ImGuiInputEvent* FindLatestInputEvent(ImGuiContext* ctx, ImGuiInputEventType type, int arg = -1)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiContext& g = *ctx;
|
||||
for (int n = g.InputEventsQueue.Size - 1; n >= 0; n--)
|
||||
{
|
||||
ImGuiInputEvent* e = &g.InputEventsQueue[n];
|
||||
@@ -1406,6 +1406,8 @@ static ImGuiInputEvent* FindLatestInputEvent(ImGuiInputEventType type, int arg =
|
||||
// - ImGuiKey key: Translated key (as in, generally ImGuiKey_A matches the key end-user would use to emit an 'A' character)
|
||||
// - bool down: Is the key down? use false to signify a key release.
|
||||
// - float analog_value: 0.0f..1.0f
|
||||
// IMPORTANT: THIS FUNCTION AND OTHER "ADD" GRABS THE CONTEXT FROM OUR INSTANCE.
|
||||
// WE NEED TO ENSURE THAT ALL FUNCTION CALLS ARE FULLFILLING THIS, WHICH IS WHY GetKeyData() HAS AN EXPLICIT CONTEXT.
|
||||
void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value)
|
||||
{
|
||||
//if (e->Down) { IMGUI_DEBUG_LOG_IO("AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); }
|
||||
@@ -1414,7 +1416,7 @@ void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value)
|
||||
return;
|
||||
ImGuiContext& g = *Ctx;
|
||||
IM_ASSERT(ImGui::IsNamedKeyOrModKey(key)); // Backend needs to pass a valid ImGuiKey_ constant. 0..511 values are legacy native key codes which are not accepted by this API.
|
||||
IM_ASSERT(!ImGui::IsAliasKey(key)); // Backend cannot submit ImGuiKey_MouseXXX values they are automatically inferred from AddMouseXXX() events.
|
||||
IM_ASSERT(ImGui::IsAliasKey(key) == false); // Backend cannot submit ImGuiKey_MouseXXX values they are automatically inferred from AddMouseXXX() events.
|
||||
IM_ASSERT(key != ImGuiMod_Shortcut); // We could easily support the translation here but it seems saner to not accept it (TestEngine perform a translation itself)
|
||||
|
||||
// Verify that backend isn't mixing up using new io.AddKeyEvent() api and old io.KeysDown[] + io.KeyMap[] data.
|
||||
@@ -1429,8 +1431,8 @@ void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value)
|
||||
BackendUsingLegacyNavInputArray = false;
|
||||
|
||||
// Filter duplicate (in particular: key mods and gamepad analog values are commonly spammed)
|
||||
const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_Key, (int)key);
|
||||
const ImGuiKeyData* key_data = ImGui::GetKeyData(key);
|
||||
const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Key, (int)key);
|
||||
const ImGuiKeyData* key_data = ImGui::GetKeyData(&g, key);
|
||||
const bool latest_key_down = latest_event ? latest_event->Key.Down : key_data->Down;
|
||||
const float latest_key_analog = latest_event ? latest_event->Key.AnalogValue : key_data->AnalogValue;
|
||||
if (latest_key_down == down && latest_key_analog == analog_value)
|
||||
@@ -1496,7 +1498,7 @@ void ImGuiIO::AddMousePosEvent(float x, float y)
|
||||
ImVec2 pos((x > -FLT_MAX) ? ImFloorSigned(x) : x, (y > -FLT_MAX) ? ImFloorSigned(y) : y);
|
||||
|
||||
// Filter duplicate
|
||||
const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_MousePos);
|
||||
const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_MousePos);
|
||||
const ImVec2 latest_pos = latest_event ? ImVec2(latest_event->MousePos.PosX, latest_event->MousePos.PosY) : g.IO.MousePos;
|
||||
if (latest_pos.x == pos.x && latest_pos.y == pos.y)
|
||||
return;
|
||||
@@ -1518,7 +1520,7 @@ void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
|
||||
return;
|
||||
|
||||
// Filter duplicate
|
||||
const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_MouseButton, (int)mouse_button);
|
||||
const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_MouseButton, (int)mouse_button);
|
||||
const bool latest_button_down = latest_event ? latest_event->MouseButton.Down : g.IO.MouseDown[mouse_button];
|
||||
if (latest_button_down == down)
|
||||
return;
|
||||
@@ -1551,14 +1553,14 @@ void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y)
|
||||
|
||||
void ImGuiIO::AddMouseViewportEvent(ImGuiID viewport_id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
|
||||
IM_ASSERT(Ctx != NULL);
|
||||
ImGuiContext& g = *Ctx;
|
||||
IM_ASSERT(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport);
|
||||
if (!AppAcceptingEvents)
|
||||
return;
|
||||
|
||||
// Filter duplicate
|
||||
const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_MouseViewport);
|
||||
const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_MouseViewport);
|
||||
const ImGuiID latest_viewport_id = latest_event ? latest_event->MouseViewport.HoveredViewportID : g.IO.MouseHoveredViewport;
|
||||
if (latest_viewport_id == viewport_id)
|
||||
return;
|
||||
@@ -1576,7 +1578,7 @@ void ImGuiIO::AddFocusEvent(bool focused)
|
||||
ImGuiContext& g = *Ctx;
|
||||
|
||||
// Filter duplicate
|
||||
const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_Focus);
|
||||
const ImGuiInputEvent* latest_event = FindLatestInputEvent(&g, ImGuiInputEventType_Focus);
|
||||
const bool latest_focused = latest_event ? latest_event->AppFocused.Focused : !g.IO.AppFocusLost;
|
||||
if (latest_focused == focused)
|
||||
return;
|
||||
@@ -3666,6 +3668,7 @@ void ImGui::Shutdown()
|
||||
g.ClipboardHandlerData.clear();
|
||||
g.MenusIdSubmittedThisFrame.clear();
|
||||
g.InputTextState.ClearFreeMemory();
|
||||
g.InputTextDeactivatedState.ClearFreeMemory();
|
||||
|
||||
g.SettingsWindows.clear();
|
||||
g.SettingsHandlers.clear();
|
||||
@@ -3844,13 +3847,23 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
|
||||
// While most behaved code would make an effort to not steal active id during window move/drag operations,
|
||||
// we at least need to be resilient to it. Cancelling the move is rather aggressive and users of 'master' branch
|
||||
// may prefer the weird ill-defined half working situation ('docking' did assert), so may need to rework that.
|
||||
if (g.MovingWindow != NULL && g.ActiveId == g.MovingWindow->MoveId)
|
||||
// Clear previous active id
|
||||
if (g.ActiveId != 0)
|
||||
{
|
||||
IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() cancel MovingWindow\n");
|
||||
g.MovingWindow = NULL;
|
||||
// While most behaved code would make an effort to not steal active id during window move/drag operations,
|
||||
// we at least need to be resilient to it. Canceling the move is rather aggressive and users of 'master' branch
|
||||
// may prefer the weird ill-defined half working situation ('docking' did assert), so may need to rework that.
|
||||
if (g.MovingWindow != NULL && g.ActiveId == g.MovingWindow->MoveId)
|
||||
{
|
||||
IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() cancel MovingWindow\n");
|
||||
g.MovingWindow = NULL;
|
||||
}
|
||||
|
||||
// This could be written in a more general way (e.g associate a hook to ActiveId),
|
||||
// but since this is currently quite an exception we'll leave it as is.
|
||||
// One common scenario leading to this is: pressing Key ->NavMoveRequestApplyResult() -> ClearActiveId()
|
||||
if (g.InputTextState.ID == g.ActiveId)
|
||||
InputTextDeactivateHook(g.ActiveId);
|
||||
}
|
||||
|
||||
// Set active id
|
||||
@@ -3876,7 +3889,8 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
|
||||
if (id)
|
||||
{
|
||||
g.ActiveIdIsAlive = id;
|
||||
g.ActiveIdSource = (g.NavActivateId == id || g.NavJustMovedToId == id) ? (ImGuiInputSource)ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
|
||||
g.ActiveIdSource = (g.NavActivateId == id || g.NavJustMovedToId == id) ? g.NavInputSource : ImGuiInputSource_Mouse;
|
||||
IM_ASSERT(g.ActiveIdSource != ImGuiInputSource_None);
|
||||
}
|
||||
|
||||
// Clear declaration of inputs claimed by the widget
|
||||
@@ -3924,11 +3938,17 @@ void ImGui::MarkItemEdited(ImGuiID id)
|
||||
// This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit().
|
||||
// ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need to fill the data.
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive);
|
||||
IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out.
|
||||
if (g.ActiveId == id || g.ActiveId == 0)
|
||||
{
|
||||
g.ActiveIdHasBeenEditedThisFrame = true;
|
||||
g.ActiveIdHasBeenEditedBefore = true;
|
||||
}
|
||||
|
||||
// We accept a MarkItemEdited() on drag and drop targets (see https://github.com/ocornut/imgui/issues/1875#issuecomment-978243343)
|
||||
// We accept 'ActiveIdPreviousFrame == id' for InputText() returning an edit after it has been taken ActiveId away (#4714)
|
||||
IM_ASSERT(g.DragDropActive || g.ActiveId == id || g.ActiveId == 0 || g.ActiveIdPreviousFrame == id);
|
||||
|
||||
//IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
|
||||
g.ActiveIdHasBeenEditedThisFrame = true;
|
||||
g.ActiveIdHasBeenEditedBefore = true;
|
||||
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited;
|
||||
}
|
||||
|
||||
@@ -5542,7 +5562,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, b
|
||||
FocusWindow(child_window);
|
||||
NavInitWindow(child_window, false);
|
||||
SetActiveID(id + 1, child_window); // Steal ActiveId with another arbitrary id so that key-press won't activate child item
|
||||
g.ActiveIdSource = ImGuiInputSource_Nav;
|
||||
g.ActiveIdSource = g.NavInputSource;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -8307,13 +8327,13 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
|
||||
// - Shortcut() [Internal]
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ImGuiKeyData* ImGui::GetKeyData(ImGuiKey key)
|
||||
ImGuiKeyData* ImGui::GetKeyData(ImGuiContext* ctx, ImGuiKey key)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiContext& g = *ctx;
|
||||
|
||||
// Special storage location for mods
|
||||
if (key & ImGuiMod_Mask_)
|
||||
key = ConvertSingleModFlagToKey(key);
|
||||
key = ConvertSingleModFlagToKey(ctx, key);
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
|
||||
IM_ASSERT(key >= ImGuiKey_LegacyNativeKey_BEGIN && key < ImGuiKey_NamedKey_END);
|
||||
@@ -8362,22 +8382,22 @@ IM_STATIC_ASSERT(ImGuiKey_NamedKey_COUNT == IM_ARRAYSIZE(GKeyNames));
|
||||
|
||||
const char* ImGui::GetKeyName(ImGuiKey key)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
#ifdef IMGUI_DISABLE_OBSOLETE_KEYIO
|
||||
IM_ASSERT((IsNamedKey(key) || key == ImGuiKey_None) && "Support for user key indices was dropped in favor of ImGuiKey. Please update backend and user code.");
|
||||
#else
|
||||
if (IsLegacyKey(key))
|
||||
{
|
||||
ImGuiIO& io = GetIO();
|
||||
if (io.KeyMap[key] == -1)
|
||||
if (g.IO.KeyMap[key] == -1)
|
||||
return "N/A";
|
||||
IM_ASSERT(IsNamedKey((ImGuiKey)io.KeyMap[key]));
|
||||
key = (ImGuiKey)io.KeyMap[key];
|
||||
IM_ASSERT(IsNamedKey((ImGuiKey)g.IO.KeyMap[key]));
|
||||
key = (ImGuiKey)g.IO.KeyMap[key];
|
||||
}
|
||||
#endif
|
||||
if (key == ImGuiKey_None)
|
||||
return "None";
|
||||
if (key & ImGuiMod_Mask_)
|
||||
key = ConvertSingleModFlagToKey(key);
|
||||
key = ConvertSingleModFlagToKey(&g, key);
|
||||
if (!IsNamedKey(key))
|
||||
return "Unknown";
|
||||
|
||||
@@ -8472,7 +8492,7 @@ static void ImGui::UpdateKeyRoutingTable(ImGuiKeyRoutingTable* rt)
|
||||
// Apply routing to owner if there's no owner already (RoutingCurr == None at this point)
|
||||
if (routing_entry->Mods == g.IO.KeyMods)
|
||||
{
|
||||
ImGuiKeyOwnerData* owner_data = ImGui::GetKeyOwnerData(key);
|
||||
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
|
||||
if (owner_data->OwnerCurr == ImGuiKeyOwner_None)
|
||||
owner_data->OwnerCurr = routing_entry->RoutingCurr;
|
||||
}
|
||||
@@ -8509,7 +8529,7 @@ ImGuiKeyRoutingData* ImGui::GetShortcutRoutingData(ImGuiKeyChord key_chord)
|
||||
ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
|
||||
ImGuiKey mods = (ImGuiKey)(key_chord & ImGuiMod_Mask_);
|
||||
if (key == ImGuiKey_None)
|
||||
key = ConvertSingleModFlagToKey(mods);
|
||||
key = ConvertSingleModFlagToKey(&g, mods);
|
||||
IM_ASSERT(IsNamedKey(key));
|
||||
|
||||
// Get (in the majority of case, the linked list will have one element so this should be 2 reads.
|
||||
@@ -9242,7 +9262,7 @@ void ImGui::SetNextFrameWantCaptureMouse(bool want_capture_mouse)
|
||||
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
|
||||
static const char* GetInputSourceName(ImGuiInputSource source)
|
||||
{
|
||||
const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Nav", "Clipboard" };
|
||||
const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Clipboard" };
|
||||
IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT && source >= 0 && source < ImGuiInputSource_COUNT);
|
||||
return input_source_names[source];
|
||||
}
|
||||
@@ -9389,7 +9409,7 @@ ImGuiID ImGui::GetKeyOwner(ImGuiKey key)
|
||||
return ImGuiKeyOwner_None;
|
||||
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key);
|
||||
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
|
||||
ImGuiID owner_id = owner_data->OwnerCurr;
|
||||
|
||||
if (g.ActiveIdUsingAllKeyboardKeys && owner_id != g.ActiveId && owner_id != ImGuiKeyOwner_Any)
|
||||
@@ -9413,7 +9433,7 @@ bool ImGui::TestKeyOwner(ImGuiKey key, ImGuiID owner_id)
|
||||
if (key >= ImGuiKey_Keyboard_BEGIN && key < ImGuiKey_Keyboard_END)
|
||||
return false;
|
||||
|
||||
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key);
|
||||
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
|
||||
if (owner_id == ImGuiKeyOwner_Any)
|
||||
return (owner_data->LockThisFrame == false);
|
||||
|
||||
@@ -9441,7 +9461,8 @@ void ImGui::SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags)
|
||||
IM_ASSERT(IsNamedKeyOrModKey(key) && (owner_id != ImGuiKeyOwner_Any || (flags & (ImGuiInputFlags_LockThisFrame | ImGuiInputFlags_LockUntilRelease)))); // Can only use _Any with _LockXXX flags (to eat a key away without an ID to retrieve it)
|
||||
IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetKeyOwner) == 0); // Passing flags not supported by this function!
|
||||
|
||||
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key);
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
|
||||
owner_data->OwnerCurr = owner_data->OwnerNext = owner_id;
|
||||
|
||||
// We cannot lock by default as it would likely break lots of legacy code.
|
||||
@@ -9490,7 +9511,7 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags
|
||||
// Special storage location for mods
|
||||
ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
|
||||
if (key == ImGuiKey_None)
|
||||
key = ConvertSingleModFlagToKey(mods);
|
||||
key = ConvertSingleModFlagToKey(&g, mods);
|
||||
|
||||
if (!IsKeyPressed(key, owner_id, (flags & (ImGuiInputFlags_Repeat | (ImGuiInputFlags)ImGuiInputFlags_RepeatRateMask_))))
|
||||
return false;
|
||||
@@ -9941,7 +9962,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
|
||||
// return false;
|
||||
const bool is_rect_visible = bb.Overlaps(window->ClipRect);
|
||||
if (!is_rect_visible)
|
||||
if (id == 0 || (id != g.ActiveId && id != g.NavId))
|
||||
if (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId))
|
||||
if (!g.LogEnabled)
|
||||
return false;
|
||||
|
||||
@@ -11232,7 +11253,7 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
|
||||
if (g.LastItemData.ID == id)
|
||||
window->NavRectRel[nav_layer] = WindowRectAbsToRel(window, g.LastItemData.NavRect);
|
||||
|
||||
if (g.ActiveIdSource == ImGuiInputSource_Nav)
|
||||
if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad)
|
||||
g.NavDisableMouseHover = true;
|
||||
else
|
||||
g.NavDisableHighlight = true;
|
||||
@@ -19290,7 +19311,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
|
||||
{
|
||||
for (ImGuiKey key = ImGuiKey_NamedKey_BEGIN; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1))
|
||||
{
|
||||
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(key);
|
||||
ImGuiKeyOwnerData* owner_data = GetKeyOwnerData(&g, key);
|
||||
if (owner_data->OwnerCurr == ImGuiKeyOwner_None)
|
||||
continue;
|
||||
Text("%s: 0x%08X%s", GetKeyName(key), owner_data->OwnerCurr,
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
// Library Version
|
||||
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345')
|
||||
#define IMGUI_VERSION "1.89.5 WIP"
|
||||
#define IMGUI_VERSION_NUM 18941
|
||||
#define IMGUI_VERSION_NUM 18943
|
||||
#define IMGUI_HAS_TABLE
|
||||
#define IMGUI_HAS_VIEWPORT // Viewport WIP branch
|
||||
#define IMGUI_HAS_DOCK // Docking WIP branch
|
||||
|
||||
+1
-3
@@ -5786,8 +5786,6 @@ static void ShowDemoWindowColumns()
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
namespace ImGui { extern ImGuiKeyData* GetKeyData(ImGuiKey key); }
|
||||
|
||||
static void ShowDemoWindowInputs()
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Inputs & Focus");
|
||||
@@ -5822,7 +5820,7 @@ static void ShowDemoWindowInputs()
|
||||
struct funcs { static bool IsLegacyNativeDupe(ImGuiKey key) { return key < 512 && ImGui::GetIO().KeyMap[key] != -1; } }; // Hide Native<>ImGuiKey duplicates when both exists in the array
|
||||
ImGuiKey start_key = (ImGuiKey)0;
|
||||
#endif
|
||||
ImGui::Text("Keys down:"); for (ImGuiKey key = start_key; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !ImGui::IsKeyDown(key)) continue; ImGui::SameLine(); ImGui::Text((key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); ImGui::SameLine(); ImGui::Text("(%.02f)", ImGui::GetKeyData(key)->DownDuration); }
|
||||
ImGui::Text("Keys down:"); for (ImGuiKey key = start_key; key < ImGuiKey_NamedKey_END; key = (ImGuiKey)(key + 1)) { if (funcs::IsLegacyNativeDupe(key) || !ImGui::IsKeyDown(key)) continue; ImGui::SameLine(); ImGui::Text((key < ImGuiKey_NamedKey_BEGIN) ? "\"%s\"" : "\"%s\" %d", ImGui::GetKeyName(key), key); }
|
||||
ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
|
||||
ImGui::Text("Chars queue:"); for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine(); ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public.
|
||||
|
||||
|
||||
+20
-8
@@ -134,6 +134,7 @@ struct ImGuiDockNode; // Docking system node (hold a list of Windo
|
||||
struct ImGuiDockNodeSettings; // Storage for a dock node in .ini file (we preserve those even if the associated dock node isn't active during the session)
|
||||
struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup()
|
||||
struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box
|
||||
struct ImGuiInputTextDeactivateData;// Short term storage to backup text of a deactivating InputText() while another is stealing active id
|
||||
struct ImGuiLastItemData; // Status storage for last submitted items
|
||||
struct ImGuiLocEntry; // A localization entry.
|
||||
struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only
|
||||
@@ -1058,6 +1059,15 @@ struct IMGUI_API ImGuiMenuColumns
|
||||
void CalcNextTotalWidth(bool update_offsets);
|
||||
};
|
||||
|
||||
// Internal temporary state for deactivating InputText() instances.
|
||||
struct IMGUI_API ImGuiInputTextDeactivatedState
|
||||
{
|
||||
ImGuiID ID; // widget id owning the text state (which just got deactivated)
|
||||
ImVector<char> TextA; // text buffer
|
||||
|
||||
ImGuiInputTextDeactivatedState() { memset(this, 0, sizeof(*this)); }
|
||||
void ClearFreeMemory() { ID = 0; TextA.clear(); }
|
||||
};
|
||||
// Internal state of the currently focused/edited text input box
|
||||
// For a given item ID, access with ImGui::GetInputTextState()
|
||||
struct IMGUI_API ImGuiInputTextState
|
||||
@@ -1277,7 +1287,6 @@ enum ImGuiInputSource
|
||||
ImGuiInputSource_Keyboard,
|
||||
ImGuiInputSource_Gamepad,
|
||||
ImGuiInputSource_Clipboard, // Currently only used by InputText()
|
||||
ImGuiInputSource_Nav, // Stored in g.ActiveIdSource only
|
||||
ImGuiInputSource_COUNT
|
||||
};
|
||||
|
||||
@@ -1968,7 +1977,7 @@ struct ImGuiContext
|
||||
bool ActiveIdHasBeenEditedThisFrame;
|
||||
ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior)
|
||||
ImGuiWindow* ActiveIdWindow;
|
||||
ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard)
|
||||
ImGuiInputSource ActiveIdSource; // Activating source: ImGuiInputSource_Mouse OR ImGuiInputSource_Keyboard OR ImGuiInputSource_Gamepad
|
||||
int ActiveIdMouseButton;
|
||||
ImGuiID ActiveIdPreviousFrame;
|
||||
bool ActiveIdPreviousFrameIsAlive;
|
||||
@@ -2031,7 +2040,7 @@ struct ImGuiContext
|
||||
ImGuiKeyChord NavJustMovedToKeyMods;
|
||||
ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame.
|
||||
ImGuiActivateFlags NavNextActivateFlags;
|
||||
ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS WILL ONLY BE None or NavGamepad or NavKeyboard.
|
||||
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.
|
||||
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)
|
||||
@@ -2125,6 +2134,7 @@ struct ImGuiContext
|
||||
// Widget state
|
||||
ImVec2 MouseLastValidPos;
|
||||
ImGuiInputTextState InputTextState;
|
||||
ImGuiInputTextDeactivatedState InputTextDeactivatedState;
|
||||
ImFont InputTextPasswordFont;
|
||||
ImGuiID TempInputId; // Temporary text input when CTRL+clicking on a slider, etc.
|
||||
ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets
|
||||
@@ -2283,7 +2293,7 @@ struct ImGuiContext
|
||||
NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0;
|
||||
NavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None;
|
||||
NavJustMovedToKeyMods = ImGuiMod_None;
|
||||
NavInputSource = ImGuiInputSource_None;
|
||||
NavInputSource = ImGuiInputSource_Keyboard;
|
||||
NavLayer = ImGuiNavLayer_Main;
|
||||
NavIdIsAlive = false;
|
||||
NavMousePosDirty = false;
|
||||
@@ -3125,9 +3135,9 @@ namespace ImGui
|
||||
inline bool IsMouseKey(ImGuiKey key) { return key >= ImGuiKey_Mouse_BEGIN && key < ImGuiKey_Mouse_END; }
|
||||
inline bool IsAliasKey(ImGuiKey key) { return key >= ImGuiKey_Aliases_BEGIN && key < ImGuiKey_Aliases_END; }
|
||||
inline ImGuiKeyChord ConvertShortcutMod(ImGuiKeyChord key_chord) { ImGuiContext& g = *GImGui; IM_ASSERT_PARANOID(key_chord & ImGuiMod_Shortcut); return (key_chord & ~ImGuiMod_Shortcut) | (g.IO.ConfigMacOSXBehaviors ? ImGuiMod_Super : ImGuiMod_Ctrl); }
|
||||
inline ImGuiKey ConvertSingleModFlagToKey(ImGuiKey key)
|
||||
inline ImGuiKey ConvertSingleModFlagToKey(ImGuiContext* ctx, ImGuiKey key)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiContext& g = *ctx;
|
||||
if (key == ImGuiMod_Ctrl) return ImGuiKey_ReservedForModCtrl;
|
||||
if (key == ImGuiMod_Shift) return ImGuiKey_ReservedForModShift;
|
||||
if (key == ImGuiMod_Alt) return ImGuiKey_ReservedForModAlt;
|
||||
@@ -3136,7 +3146,8 @@ namespace ImGui
|
||||
return key;
|
||||
}
|
||||
|
||||
IMGUI_API ImGuiKeyData* GetKeyData(ImGuiKey key);
|
||||
IMGUI_API ImGuiKeyData* GetKeyData(ImGuiContext* ctx, ImGuiKey key);
|
||||
inline ImGuiKeyData* GetKeyData(ImGuiKey key) { ImGuiContext& g = *GImGui; return GetKeyData(&g, key); }
|
||||
IMGUI_API void GetKeyChordName(ImGuiKeyChord key_chord, char* out_buf, int out_buf_size);
|
||||
inline ImGuiKey MouseButtonToKey(ImGuiMouseButton button) { IM_ASSERT(button >= 0 && button < ImGuiMouseButton_COUNT); return (ImGuiKey)(ImGuiKey_MouseLeft + button); }
|
||||
IMGUI_API bool IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold = -1.0f);
|
||||
@@ -3162,7 +3173,7 @@ namespace ImGui
|
||||
IMGUI_API void SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags = 0);
|
||||
IMGUI_API void SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags = 0); // Set key owner to last item if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'.
|
||||
IMGUI_API bool TestKeyOwner(ImGuiKey key, ImGuiID owner_id); // Test that key is either not owned, either owned by 'owner_id'
|
||||
inline ImGuiKeyOwnerData* GetKeyOwnerData(ImGuiKey key) { if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(key); IM_ASSERT(IsNamedKey(key)); return &GImGui->KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; }
|
||||
inline ImGuiKeyOwnerData* GetKeyOwnerData(ImGuiContext* ctx, ImGuiKey key) { if (key & ImGuiMod_Mask_) key = ConvertSingleModFlagToKey(ctx, key); IM_ASSERT(IsNamedKey(key)); return &ctx->KeysOwnerData[key - ImGuiKey_NamedKey_BEGIN]; }
|
||||
|
||||
// [EXPERIMENTAL] High-Level: Input Access functions w/ support for Key/Input Ownership
|
||||
// - Important: legacy IsKeyPressed(ImGuiKey, bool repeat=true) _DEFAULTS_ to repeat, new IsKeyPressed() requires _EXPLICIT_ ImGuiInputFlags_Repeat flag.
|
||||
@@ -3429,6 +3440,7 @@ namespace ImGui
|
||||
|
||||
// InputText
|
||||
IMGUI_API bool InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
|
||||
IMGUI_API void InputTextDeactivateHook(ImGuiID id);
|
||||
IMGUI_API bool TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags);
|
||||
IMGUI_API bool TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min = NULL, const void* p_clamp_max = NULL);
|
||||
inline bool TempInputIsActive(ImGuiID id) { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputId == id); }
|
||||
|
||||
+47
-15
@@ -622,7 +622,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
||||
// Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button.
|
||||
pressed = true;
|
||||
SetActiveID(id, window);
|
||||
g.ActiveIdSource = ImGuiInputSource_Nav;
|
||||
g.ActiveIdSource = g.NavInputSource;
|
||||
if (!(flags & ImGuiButtonFlags_NoNavFocus))
|
||||
SetFocusID(id, window);
|
||||
}
|
||||
@@ -660,7 +660,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
||||
if (!(flags & ImGuiButtonFlags_NoNavFocus))
|
||||
g.NavDisableHighlight = true;
|
||||
}
|
||||
else if (g.ActiveIdSource == ImGuiInputSource_Nav)
|
||||
else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad)
|
||||
{
|
||||
// When activated using Nav, we hold on the ActiveID until activation button is released
|
||||
if (g.NavActivateDownId != id)
|
||||
@@ -2251,7 +2251,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
|
||||
if (g.IO.KeyShift)
|
||||
adjust_delta *= 10.0f;
|
||||
}
|
||||
else if (g.ActiveIdSource == ImGuiInputSource_Nav)
|
||||
else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad)
|
||||
{
|
||||
const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0;
|
||||
const bool tweak_slow = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow);
|
||||
@@ -2358,7 +2358,7 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v
|
||||
// Those are the things we can do easily outside the DragBehaviorT<> template, saves code generation.
|
||||
if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0])
|
||||
ClearActiveID();
|
||||
else if (g.ActiveIdSource == ImGuiInputSource_Nav && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated)
|
||||
else if ((g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad) && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated)
|
||||
ClearActiveID();
|
||||
}
|
||||
if (g.ActiveId != id)
|
||||
@@ -2827,7 +2827,7 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
|
||||
set_new_value = true;
|
||||
}
|
||||
}
|
||||
else if (g.ActiveIdSource == ImGuiInputSource_Nav)
|
||||
else if (g.ActiveIdSource == ImGuiInputSource_Keyboard || g.ActiveIdSource == ImGuiInputSource_Gamepad)
|
||||
{
|
||||
if (g.ActiveIdIsJustActivated)
|
||||
{
|
||||
@@ -3306,7 +3306,7 @@ void ImParseFormatSanitizeForPrinting(const char* fmt_in, char* fmt_out, size_t
|
||||
*fmt_out = 0; // Zero-terminate
|
||||
}
|
||||
|
||||
// - For scanning we need to remove all width and precision fields "%3.7f" -> "%f". BUT don't strip types like "%I64d" which includes digits. ! "%07I64d" -> "%I64d"
|
||||
// - For scanning we need to remove all width and precision fields and flags "%+3.7f" -> "%f". BUT don't strip types like "%I64d" which includes digits. ! "%07I64d" -> "%I64d"
|
||||
const char* ImParseFormatSanitizeForScanning(const char* fmt_in, char* fmt_out, size_t fmt_out_size)
|
||||
{
|
||||
const char* fmt_end = ImParseFormatFindEnd(fmt_in);
|
||||
@@ -3317,7 +3317,7 @@ const char* ImParseFormatSanitizeForScanning(const char* fmt_in, char* fmt_out,
|
||||
while (fmt_in < fmt_end)
|
||||
{
|
||||
char c = *fmt_in++;
|
||||
if (!has_type && ((c >= '0' && c <= '9') || c == '.'))
|
||||
if (!has_type && ((c >= '0' && c <= '9') || c == '.' || c == '+' || c == '#'))
|
||||
continue;
|
||||
has_type |= ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); // Stop skipping digits
|
||||
if (c != '\'' && c != '$' && c != '_') // Custom flags provided by stb_sprintf.h. POSIX 2008 also supports '.
|
||||
@@ -3456,7 +3456,12 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data
|
||||
flags |= ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselves by comparing the actual data rather than the string.
|
||||
|
||||
bool value_changed = false;
|
||||
if (p_step != NULL)
|
||||
if (p_step == NULL)
|
||||
{
|
||||
if (InputText(label, buf, IM_ARRAYSIZE(buf), flags))
|
||||
value_changed = DataTypeApplyFromText(buf, data_type, p_data, format);
|
||||
}
|
||||
else
|
||||
{
|
||||
const float button_size = GetFrameHeight();
|
||||
|
||||
@@ -3499,11 +3504,6 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data
|
||||
PopID();
|
||||
EndGroup();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (InputText(label, buf, IM_ARRAYSIZE(buf), flags))
|
||||
value_changed = DataTypeApplyFromText(buf, data_type, p_data, format);
|
||||
}
|
||||
if (value_changed)
|
||||
MarkItemEdited(g.LastItemData.ID);
|
||||
|
||||
@@ -4005,6 +4005,21 @@ static void InputTextReconcileUndoStateAfterUserCallback(ImGuiInputTextState* st
|
||||
p[i] = ImStb::STB_TEXTEDIT_GETCHAR(state, first_diff + i);
|
||||
}
|
||||
|
||||
// As InputText() retain textual data and we currently provide a path for user to not retain it (via local variables)
|
||||
// we need some form of hook to reapply data back to user buffer on deactivation frame. (#4714)
|
||||
// It would be more desirable that we discourage users from taking advantage of the "user not retaining data" trick,
|
||||
// but that more likely be attractive when we do have _NoLiveEdit flag available.
|
||||
void ImGui::InputTextDeactivateHook(ImGuiID id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiInputTextState* state = &g.InputTextState;
|
||||
if (id == 0 || state->ID != id)
|
||||
return;
|
||||
g.InputTextDeactivatedState.ID = state->ID;
|
||||
g.InputTextDeactivatedState.TextA.resize(state->CurLenA + 1);
|
||||
memcpy(g.InputTextDeactivatedState.TextA.Data, state->TextA.Data, state->CurLenA + 1);
|
||||
}
|
||||
|
||||
// Edit a string of text
|
||||
// - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!".
|
||||
// This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match
|
||||
@@ -4110,7 +4125,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
|
||||
float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX;
|
||||
|
||||
const bool init_changed_specs = (state != NULL && state->Stb.single_line != !is_multiline);
|
||||
const bool init_changed_specs = (state != NULL && state->Stb.single_line != !is_multiline); // state != NULL means its our state.
|
||||
const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav || input_requested_by_tabbing);
|
||||
const bool init_state = (init_make_active || user_scroll_active);
|
||||
if ((init_state && g.ActiveId != id) || init_changed_specs)
|
||||
@@ -4119,6 +4134,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
state = &g.InputTextState;
|
||||
state->CursorAnimReset();
|
||||
|
||||
// Backup state of deactivating item so they'll have a chance to do a write to output buffer on the same frame they report IsItemDeactivatedAfterEdit (#4714)
|
||||
InputTextDeactivateHook(state->ID);
|
||||
|
||||
// Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar)
|
||||
// From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode)
|
||||
const int buf_len = (int)strlen(buf);
|
||||
@@ -4531,6 +4549,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
// Push records into the undo stack so we can CTRL+Z the revert operation itself
|
||||
apply_new_text = state->InitialTextA.Data;
|
||||
apply_new_text_length = state->InitialTextA.Size - 1;
|
||||
value_changed = true;
|
||||
ImVector<ImWchar> w_text;
|
||||
if (apply_new_text_length > 0)
|
||||
{
|
||||
@@ -4644,10 +4663,24 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
{
|
||||
apply_new_text = state->TextA.Data;
|
||||
apply_new_text_length = state->CurLenA;
|
||||
value_changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle reapplying final data on deactivation (see InputTextDeactivateHook() for details)
|
||||
if (g.InputTextDeactivatedState.ID == id)
|
||||
{
|
||||
if (g.ActiveId != id && IsItemDeactivatedAfterEdit() && !is_readonly)
|
||||
{
|
||||
apply_new_text = g.InputTextDeactivatedState.TextA.Data;
|
||||
apply_new_text_length = g.InputTextDeactivatedState.TextA.Size - 1;
|
||||
value_changed |= (strcmp(g.InputTextDeactivatedState.TextA.Data, buf) != 0);
|
||||
//IMGUI_DEBUG_LOG("InputText(): apply Deactivated data for 0x%08X: \"%.*s\".\n", id, apply_new_text_length, apply_new_text);
|
||||
}
|
||||
g.InputTextDeactivatedState.ID = 0;
|
||||
}
|
||||
|
||||
// Copy result to user buffer. This can currently only happen when (g.ActiveId == id)
|
||||
if (apply_new_text != NULL)
|
||||
{
|
||||
@@ -4675,7 +4708,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
|
||||
// If the underlying buffer resize was denied or not carried to the next frame, apply_new_text_length+1 may be >= buf_size.
|
||||
ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size));
|
||||
value_changed = true;
|
||||
}
|
||||
|
||||
// Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value)
|
||||
|
||||
Reference in New Issue
Block a user