Updated ImGui.

This commit is contained in:
Бранимир Караџић 2023-03-31 19:02:32 -07:00
parent 2c07181c1e
commit d87baafbcc
6 changed files with 134 additions and 69 deletions

View File

@ -1351,9 +1351,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];
@ -1372,6 +1372,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); }
@ -1380,7 +1382,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.
@ -1395,8 +1397,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)
@ -1462,7 +1464,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;
@ -1484,7 +1486,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;
@ -1521,7 +1523,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;
@ -3867,7 +3869,7 @@ void ImGui::MarkItemEdited(ImGuiID id)
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited;
}
static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
bool ImGui::IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
{
// An active popup disable hovering on other windows (apart from its own children)
// FIXME-OPT: This could be cached/stored within the window.
@ -7728,13 +7730,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);
@ -7783,22 +7785,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";
@ -7893,7 +7895,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;
}
@ -7930,7 +7932,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.
@ -8436,6 +8438,13 @@ static void ImGui::UpdateMouseInputs()
ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO;
// Mouse Wheel swapping flag
// As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead
// - We avoid doing it on OSX as it the OS input layer handles this already.
// - FIXME: However this means when running on OSX over Emscripten, Shift+WheelY will incur two swapping (1 in OS, 1 here), canceling the feature.
// - FIXME: When we can distinguish e.g. touchpad scroll events from mouse ones, we'll set this accordingly based on input source.
io.MouseWheelRequestAxisSwap = io.KeyShift && !io.ConfigMacOSXBehaviors;
// Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well)
if (IsMousePosValid(&io.MousePos))
io.MousePos = g.MouseLastValidPos = ImFloorSigned(io.MousePos);
@ -8596,15 +8605,9 @@ void ImGui::UpdateMouseWheel()
return;
// Mouse wheel scrolling
// As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead
// - We avoid doing it on OSX as it the OS input layer handles this already.
// - However this means when running on OSX over Emcripten, Shift+WheelY will incur two swappings (1 in OS, 1 here), cancelling the feature.
const bool swap_axis = g.IO.KeyShift && !g.IO.ConfigMacOSXBehaviors;
if (swap_axis)
{
wheel.x = wheel.y;
wheel.y = 0.0f;
}
// Read about io.MouseWheelRequestAxisSwap and its issue on Mac+Emscripten in UpdateMouseInputs()
if (g.IO.MouseWheelRequestAxisSwap)
wheel = ImVec2(wheel.y, 0.0f);
// Maintain a rough average of moving magnitude on both axises
// FIXME: should by based on wall clock time rather than frame-counter
@ -8800,7 +8803,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)
@ -8824,7 +8827,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);
@ -8852,7 +8855,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.
@ -8861,6 +8865,17 @@ void ImGui::SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags)
owner_data->LockThisFrame = (flags & ImGuiInputFlags_LockThisFrame) != 0 || (owner_data->LockUntilRelease);
}
// Rarely used helper
void ImGui::SetKeyOwnersForKeyChord(ImGuiKeyChord key_chord, ImGuiID owner_id, ImGuiInputFlags flags)
{
if (key_chord & ImGuiMod_Ctrl) { SetKeyOwner(ImGuiMod_Ctrl, owner_id, flags); }
if (key_chord & ImGuiMod_Shift) { SetKeyOwner(ImGuiMod_Shift, owner_id, flags); }
if (key_chord & ImGuiMod_Alt) { SetKeyOwner(ImGuiMod_Alt, owner_id, flags); }
if (key_chord & ImGuiMod_Super) { SetKeyOwner(ImGuiMod_Super, owner_id, flags); }
if (key_chord & ImGuiMod_Shortcut) { SetKeyOwner(ImGuiMod_Shortcut, owner_id, flags); }
if (key_chord & ~ImGuiMod_Mask_) { SetKeyOwner((ImGuiKey)(key_chord & ~ImGuiMod_Mask_), owner_id, flags); }
}
// This is more or less equivalent to:
// if (IsItemHovered() || IsItemActive())
// SetKeyOwner(key, GetItemID());
@ -8901,7 +8916,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;
@ -11781,10 +11796,11 @@ static void ImGui::NavUpdateWindowing()
}
// Start CTRL+Tab or Square+L/R window selection
const ImGuiID owner_id = ImHashStr("###NavUpdateWindowing");
const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
const bool keyboard_next_window = allow_windowing && g.ConfigNavWindowingKeyNext && Shortcut(g.ConfigNavWindowingKeyNext, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways);
const bool keyboard_prev_window = allow_windowing && g.ConfigNavWindowingKeyPrev && Shortcut(g.ConfigNavWindowingKeyPrev, ImGuiKeyOwner_None, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways);
const bool keyboard_next_window = allow_windowing && g.ConfigNavWindowingKeyNext && Shortcut(g.ConfigNavWindowingKeyNext, owner_id, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways);
const bool keyboard_prev_window = allow_windowing && g.ConfigNavWindowingKeyPrev && Shortcut(g.ConfigNavWindowingKeyPrev, owner_id, ImGuiInputFlags_Repeat | ImGuiInputFlags_RouteAlways);
const bool start_windowing_with_gamepad = allow_windowing && nav_gamepad_active && !g.NavWindowingTarget && IsKeyPressed(ImGuiKey_NavGamepadMenu, 0, ImGuiInputFlags_None);
const bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && (keyboard_next_window || keyboard_prev_window); // Note: enabled even without NavEnableKeyboard!
if (start_windowing_with_gamepad || start_windowing_with_keyboard)
@ -11795,6 +11811,10 @@ static void ImGui::NavUpdateWindowing()
g.NavWindowingAccumDeltaPos = g.NavWindowingAccumDeltaSize = ImVec2(0.0f, 0.0f);
g.NavWindowingToggleLayer = start_windowing_with_gamepad ? true : false; // Gamepad starts toggling layer
g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_Keyboard : ImGuiInputSource_Gamepad;
// Register ownership of our mods. Using ImGuiInputFlags_RouteGlobalHigh in the Shortcut() calls instead would probably be correct but may have more side-effects.
if (keyboard_next_window || keyboard_prev_window)
SetKeyOwnersForKeyChord((g.ConfigNavWindowingKeyNext | g.ConfigNavWindowingKeyPrev) & ImGuiMod_Mask_, owner_id);
}
// Gamepad update
@ -13727,7 +13747,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,

View File

@ -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 18942
#define IMGUI_VERSION_NUM 18946
#define IMGUI_HAS_TABLE
/*
@ -255,8 +255,8 @@ struct ImVec2
float x, y;
constexpr ImVec2() : x(0.0f), y(0.0f) { }
constexpr ImVec2(float _x, float _y) : x(_x), y(_y) { }
float operator[] (size_t idx) const { IM_ASSERT(idx == 0 || idx == 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine.
float& operator[] (size_t idx) { IM_ASSERT(idx == 0 || idx == 1); return (&x)[idx]; } // We very rarely use this [] operator, the assert overhead is fine.
float& operator[] (size_t idx) { IM_ASSERT(idx == 0 || idx == 1); return ((float*)(char*)this)[idx]; } // We very rarely use this [] operator, so the assert overhead is fine.
float operator[] (size_t idx) const { IM_ASSERT(idx == 0 || idx == 1); return ((const float*)(const char*)this)[idx]; }
#ifdef IM_VEC2_CLASS_EXTRA
IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2.
#endif
@ -2054,6 +2054,7 @@ struct ImGuiIO
bool MouseReleased[5]; // Mouse button went from Down to !Down
bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds.
bool MouseDownOwnedUnlessPopupClose[5]; // Track if button was clicked inside a dear imgui window.
bool MouseWheelRequestAxisSwap; // On a non-Mac system, holding SHIFT requests WheelY to perform the equivalent of a WheelX event. On a Mac system this is already enforced by the system.
float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked)
float MouseDownDurationPrev[5]; // Previous time the mouse button has been down
float MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point (used for moving thresholds)

View File

@ -5713,8 +5713,6 @@ static void ShowDemoWindowColumns()
ImGui::TreePop();
}
namespace ImGui { extern ImGuiKeyData* GetKeyData(ImGuiKey key); }
static void ShowDemoWindowInputs()
{
IMGUI_DEMO_MARKER("Inputs & Focus");
@ -5749,7 +5747,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.

View File

@ -3790,6 +3790,7 @@ void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir d
void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col)
{
// FIXME-OPT: This should be baked in font.
draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8);
}

View File

@ -2828,6 +2828,7 @@ namespace ImGui
inline void ItemSize(const ImRect& bb, float text_baseline_y = -1.0f) { ItemSize(bb.GetSize(), text_baseline_y); } // FIXME: This is a misleading API since we expect CursorPos to be bb.Min.
IMGUI_API bool ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL, ImGuiItemFlags extra_flags = 0);
IMGUI_API bool ItemHoverable(const ImRect& bb, ImGuiID id);
IMGUI_API bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags = 0);
IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id);
IMGUI_API void SetLastItemData(ImGuiID item_id, ImGuiItemFlags in_flags, ImGuiItemStatusFlags status_flags, const ImRect& item_rect);
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h);
@ -2897,9 +2898,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;
@ -2908,7 +2909,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);
@ -2932,9 +2934,10 @@ namespace ImGui
// Please open a GitHub Issue to submit your usage scenario or if there's a use case you need solved.
IMGUI_API ImGuiID GetKeyOwner(ImGuiKey key);
IMGUI_API void SetKeyOwner(ImGuiKey key, ImGuiID owner_id, ImGuiInputFlags flags = 0);
IMGUI_API void SetKeyOwnersForKeyChord(ImGuiKeyChord 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.

View File

@ -827,7 +827,7 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos)
ImU32 col = GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered);
ImVec2 center = bb.GetCenter();
if (hovered)
window->DrawList->AddCircleFilled(center, ImMax(2.0f, g.FontSize * 0.5f + 1.0f), col, 12);
window->DrawList->AddCircleFilled(center, ImMax(2.0f, g.FontSize * 0.5f + 1.0f), col);
float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f;
ImU32 cross_col = GetColorU32(ImGuiCol_Text);
@ -852,7 +852,7 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos)
ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
ImU32 text_col = GetColorU32(ImGuiCol_Text);
if (hovered || held)
window->DrawList->AddCircleFilled(bb.GetCenter()/*+ ImVec2(0.0f, -0.5f)*/, g.FontSize * 0.5f + 1.0f, bg_col, 12);
window->DrawList->AddCircleFilled(bb.GetCenter()/*+ ImVec2(0.0f, -0.5f)*/, g.FontSize * 0.5f + 1.0f, bg_col);
RenderArrow(window->DrawList, bb.Min + g.Style.FramePadding, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
// Switch to moving the window after mouse is moved beyond the initial drag threshold
@ -1233,17 +1233,18 @@ bool ImGui::RadioButton(const char* label, bool active)
MarkItemEdited(id);
RenderNavHighlight(total_bb, id);
window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16);
const int num_segment = window->DrawList->_CalcCircleAutoSegmentCount(radius);
window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), num_segment);
if (active)
{
const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f));
window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark), 16);
window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark));
}
if (style.FrameBorderSize > 0.0f)
{
window->DrawList->AddCircle(center + ImVec2(1, 1), radius, GetColorU32(ImGuiCol_BorderShadow), 16, style.FrameBorderSize);
window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize);
window->DrawList->AddCircle(center + ImVec2(1, 1), radius, GetColorU32(ImGuiCol_BorderShadow), num_segment, style.FrameBorderSize);
window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), num_segment, style.FrameBorderSize);
}
ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);
@ -3315,7 +3316,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);
@ -3326,7 +3327,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 '.
@ -3714,10 +3715,34 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* ob
r->num_chars = (int)(text_remaining - (text + line_start_idx));
}
// When ImGuiInputTextFlags_Password is set, we don't want actions such as CTRL+Arrow to leak the fact that underlying data are blanks or separators.
static bool is_separator(unsigned int c) { return ImCharIsBlankW(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|' || c=='\n' || c=='\r'; }
static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx) { if (obj->Flags & ImGuiInputTextFlags_Password) return 0; return idx > 0 ? (is_separator(obj->TextW[idx - 1]) && !is_separator(obj->TextW[idx]) ) : 1; }
static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) { if (obj->Flags & ImGuiInputTextFlags_Password) return 0; return idx > 0 ? (!is_separator(obj->TextW[idx - 1]) && is_separator(obj->TextW[idx])) : 1; }
static bool is_separator(unsigned int c)
{
return c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|' || c=='\n' || c=='\r' || c=='.' || c=='!';
}
static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx)
{
// When ImGuiInputTextFlags_Password is set, we don't want actions such as CTRL+Arrow to leak the fact that underlying data are blanks or separators.
if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0)
return 0;
bool prev_white = ImCharIsBlankW(obj->TextW[idx - 1]);
bool prev_separ = is_separator(obj->TextW[idx - 1]);
bool curr_white = ImCharIsBlankW(obj->TextW[idx]);
bool curr_separ = is_separator(obj->TextW[idx]);
return ((prev_white || prev_separ) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ);
}
static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx)
{
if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0)
return 0;
bool prev_white = ImCharIsBlankW(obj->TextW[idx]);
bool prev_separ = is_separator(obj->TextW[idx]);
bool curr_white = ImCharIsBlankW(obj->TextW[idx - 1]);
bool curr_separ = is_separator(obj->TextW[idx - 1]);
return ((prev_white) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ);
}
static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; }
static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; }
static int STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; }
@ -5629,7 +5654,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
float sin_hue_angle = ImSin(H * 2.0f * IM_PI);
ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f);
float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f;
int hue_cursor_segments = ImClamp((int)(hue_cursor_rad / 1.4f), 9, 32);
int hue_cursor_segments = draw_list->_CalcCircleAutoSegmentCount(hue_cursor_rad); // Lock segment count so the +1 one matches others.
draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments);
draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad + 1, col_midgrey, hue_cursor_segments);
draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, col_white, hue_cursor_segments);
@ -5639,13 +5664,10 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle);
ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle);
ImVec2 uv_white = GetFontTexUvWhitePixel();
draw_list->PrimReserve(6, 6);
draw_list->PrimReserve(3, 3);
draw_list->PrimVtx(tra, uv_white, hue_color32);
draw_list->PrimVtx(trb, uv_white, hue_color32);
draw_list->PrimVtx(trc, uv_white, col_white);
draw_list->PrimVtx(tra, uv_white, 0);
draw_list->PrimVtx(trb, uv_white, col_black);
draw_list->PrimVtx(trc, uv_white, 0);
draw_list->PrimVtx(trc, uv_white, col_white);
draw_list->AddTriangle(tra, trb, trc, col_midgrey, 1.5f);
sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V));
}
@ -5668,9 +5690,10 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
// Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range)
float sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f;
draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, 12);
draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad + 1, col_midgrey, 12);
draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, 12);
int sv_cursor_segments = draw_list->_CalcCircleAutoSegmentCount(sv_cursor_rad); // Lock segment count so the +1 one matches others.
draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, sv_cursor_segments);
draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad + 1, col_midgrey, sv_cursor_segments);
draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, sv_cursor_segments);
// Render alpha bar
if (alpha_bar)
@ -7610,6 +7633,12 @@ void ImGui::EndTabBar()
g.CurrentTabBar = g.CurrentTabBarStack.empty() ? NULL : GetTabBarFromTabBarRef(g.CurrentTabBarStack.back());
}
// Scrolling happens only in the central section (leading/trailing sections are not scrolling)
static float TabBarCalcScrollableWidth(ImGuiTabBar* tab_bar, ImGuiTabBarSection* sections)
{
return tab_bar->BarRect.GetWidth() - sections[0].Width - sections[2].Width - sections[1].Spacing;
}
// This is called only once a frame before by the first call to ItemTab()
// The reason we're not calling it in BeginTabBar() is to leave a chance to the user to call the SetTabItemClosed() functions.
static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
@ -7812,9 +7841,23 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
tab_bar->VisibleTabId = tab_bar->SelectedTabId;
tab_bar->VisibleTabWasSubmitted = false;
// Update scrolling
// Apply request requests
if (scroll_to_tab_id != 0)
TabBarScrollToTab(tab_bar, scroll_to_tab_id, sections);
else if ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) && IsMouseHoveringRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, true) && IsWindowContentHoverable(g.CurrentWindow))
{
const float wheel = g.IO.MouseWheelRequestAxisSwap ? g.IO.MouseWheel : g.IO.MouseWheelH;
const ImGuiKey wheel_key = g.IO.MouseWheelRequestAxisSwap ? ImGuiKey_MouseWheelY : ImGuiKey_MouseWheelX;
if (TestKeyOwner(wheel_key, tab_bar->ID) && wheel != 0.0f)
{
const float scroll_step = wheel * TabBarCalcScrollableWidth(tab_bar, sections) / 3.0f;
tab_bar->ScrollingTargetDistToVisibility = 0.0f;
tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget - scroll_step);
}
SetKeyOwner(wheel_key, tab_bar->ID);
}
// Update scrolling
tab_bar->ScrollingAnim = TabBarScrollClamp(tab_bar, tab_bar->ScrollingAnim);
tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget);
if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget)
@ -7951,8 +7994,7 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGui
int order = TabBarGetTabOrder(tab_bar, tab);
// Scrolling happens only in the central section (leading/trailing sections are not scrolling)
// FIXME: This is all confusing.
float scrollable_width = tab_bar->BarRect.GetWidth() - sections[0].Width - sections[2].Width - sections[1].Spacing;
float scrollable_width = TabBarCalcScrollableWidth(tab_bar, sections);
// We make all tabs positions all relative Sections[0].Width to make code simpler
float tab_x1 = tab->Offset - sections[0].Width + (order > sections[0].TabCount - 1 ? -margin : 0.0f);