Make classes not depend on the implicit GImGui context (#6199, #5856, #6199): ImGuiIO

This commit is a preparation toward adding ImGui apis with explicit context
and making ImGui applications being able to use multiple context at the same time
whatever their concurrency model.

About ImGuiIO:
- ImGuiIO depends on ImGuiContext because some of its method want to event to `g.InputEventQueue`.
- To make ImGuiIO aware of the context to use, context which creates the ImGuiIO is given as argument of ImGuiIO constructor.
- The assert `IM_ASSERT(&g.IO == this && "Can only add events to current context.")` has been removed since it does not make sense anymore

NOTE: ImGuiIO could be completely independent of ImGuiContext if the InputEventQueue was moved from ImGuiContext to ImGuiIO, but since
ImGuiIO is a public class it would expose InputEvent type. Solving this problem is out of the current scope, but it is interesting to notice.
This commit is contained in:
Marc Delorme 2022-11-01 20:35:05 +09:00 committed by ocornut
parent 5a1e6b60a2
commit 10ace228bc
4 changed files with 20 additions and 15 deletions

View File

@ -54,6 +54,7 @@ Other changes:
- Nav: Fixed an issue with Gamepad navigation when the movement lead to a scroll and - Nav: Fixed an issue with Gamepad navigation when the movement lead to a scroll and
frame time > repeat rate. Triggering a new move request on the same frame as a move frame time > repeat rate. Triggering a new move request on the same frame as a move
result lead to an incorrect calculation and loss of navigation id. (#6171) result lead to an incorrect calculation and loss of navigation id. (#6171)
- IO: Lifted constraint to call io.AddEventXXX functions from current context. (#4921, #5856, #6199)
- Drag and Drop: Fixed handling of overlapping targets when smaller one is submitted - Drag and Drop: Fixed handling of overlapping targets when smaller one is submitted
before and can accept the same data type. (#6183). before and can accept the same data type. (#6183).
- Drag and Drop: Clear drag and drop state as soon as delivery is accepted in order to - Drag and Drop: Clear drag and drop state as soon as delivery is accepted in order to

View File

@ -1244,8 +1244,8 @@ ImGuiIO::ImGuiIO()
// FIXME: Should in theory be called "AddCharacterEvent()" to be consistent with new API // FIXME: Should in theory be called "AddCharacterEvent()" to be consistent with new API
void ImGuiIO::AddInputCharacter(unsigned int c) void ImGuiIO::AddInputCharacter(unsigned int c)
{ {
ImGuiContext& g = *GImGui; IM_ASSERT(Ctx != NULL);
IM_ASSERT(&g.IO == this && "Can only add events to current context."); ImGuiContext& g = *Ctx;
if (c == 0 || !AppAcceptingEvents) if (c == 0 || !AppAcceptingEvents)
return; return;
@ -1357,10 +1357,10 @@ static ImGuiInputEvent* FindLatestInputEvent(ImGuiInputEventType type, int arg =
void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value) 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); } //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); }
IM_ASSERT(Ctx != NULL);
if (key == ImGuiKey_None || !AppAcceptingEvents) if (key == ImGuiKey_None || !AppAcceptingEvents)
return; return;
ImGuiContext& g = *GImGui; ImGuiContext& g = *Ctx;
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
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::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)); // 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) 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)
@ -1435,8 +1435,8 @@ void ImGuiIO::SetAppAcceptingEvents(bool accepting_events)
// Queue a mouse move event // Queue a mouse move event
void ImGuiIO::AddMousePosEvent(float x, float y) void ImGuiIO::AddMousePosEvent(float x, float y)
{ {
ImGuiContext& g = *GImGui; IM_ASSERT(Ctx != NULL);
IM_ASSERT(&g.IO == this && "Can only add events to current context."); ImGuiContext& g = *Ctx;
if (!AppAcceptingEvents) if (!AppAcceptingEvents)
return; return;
@ -1459,8 +1459,8 @@ void ImGuiIO::AddMousePosEvent(float x, float y)
void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down) void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
{ {
ImGuiContext& g = *GImGui; IM_ASSERT(Ctx != NULL);
IM_ASSERT(&g.IO == this && "Can only add events to current context."); ImGuiContext& g = *Ctx;
IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT); IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT);
if (!AppAcceptingEvents) if (!AppAcceptingEvents)
return; return;
@ -1482,8 +1482,8 @@ void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
// Queue a mouse wheel event (some mouse/API may only have a Y component) // Queue a mouse wheel event (some mouse/API may only have a Y component)
void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y) void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y)
{ {
ImGuiContext& g = *GImGui; IM_ASSERT(Ctx != NULL);
IM_ASSERT(&g.IO == this && "Can only add events to current context."); ImGuiContext& g = *Ctx;
// Filter duplicate (unlike most events, wheel values are relative and easy to filter) // Filter duplicate (unlike most events, wheel values are relative and easy to filter)
if (!AppAcceptingEvents || (wheel_x == 0.0f && wheel_y == 0.0f)) if (!AppAcceptingEvents || (wheel_x == 0.0f && wheel_y == 0.0f))
@ -1499,8 +1499,8 @@ void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y)
void ImGuiIO::AddFocusEvent(bool focused) void ImGuiIO::AddFocusEvent(bool focused)
{ {
ImGuiContext& g = *GImGui; IM_ASSERT(Ctx != NULL);
IM_ASSERT(&g.IO == this && "Can only add events to current context."); ImGuiContext& g = *Ctx;
// Filter duplicate // Filter duplicate
const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_Focus); const ImGuiInputEvent* latest_event = FindLatestInputEvent(ImGuiInputEventType_Focus);

View File

@ -2022,6 +2022,8 @@ struct ImGuiIO
// [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed! // [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed!
//------------------------------------------------------------------ //------------------------------------------------------------------
ImGuiContext* Ctx; // Parent UI context (needs to be set explicitly by parent).
// Main Input State // Main Input State
// (this block used to be written by backend, since 1.87 it is best to NOT write to those directly, call the AddXXX functions above instead) // (this block used to be written by backend, since 1.87 it is best to NOT write to those directly, call the AddXXX functions above instead)
// (reading from those variables is fair game, as they are extremely unlikely to be moving anywhere) // (reading from those variables is fair game, as they are extremely unlikely to be moving anywhere)

View File

@ -1052,7 +1052,7 @@ struct IMGUI_API ImGuiMenuColumns
// For a given item ID, access with ImGui::GetInputTextState() // For a given item ID, access with ImGui::GetInputTextState()
struct IMGUI_API ImGuiInputTextState struct IMGUI_API ImGuiInputTextState
{ {
ImGuiContext* Ctx; // parent dear imgui context ImGuiContext* Ctx; // parent UI context (needs to be set explicitly by parent).
ImGuiID ID; // widget id owning the text state ImGuiID ID; // widget id owning the text state
int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not. int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not.
ImVector<ImWchar> TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer. ImVector<ImWchar> TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer.
@ -1068,7 +1068,7 @@ struct IMGUI_API ImGuiInputTextState
bool Edited; // edited this frame bool Edited; // edited this frame
ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set. ImGuiInputTextFlags Flags; // copy of InputText() flags. may be used to check if e.g. ImGuiInputTextFlags_Password is set.
ImGuiInputTextState(ImGuiContext* ctx) { memset(this, 0, sizeof(*this)); Ctx = ctx;} ImGuiInputTextState() { memset(this, 0, sizeof(*this)); }
void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); } void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); }
void ClearFreeMemory() { TextW.clear(); TextA.clear(); InitialTextA.clear(); } void ClearFreeMemory() { TextW.clear(); TextA.clear(); InitialTextA.clear(); }
int GetUndoAvailCount() const { return Stb.undostate.undo_point; } int GetUndoAvailCount() const { return Stb.undostate.undo_point; }
@ -2013,8 +2013,10 @@ struct ImGuiContext
ImVector<char> TempBuffer; // Temporary text buffer ImVector<char> TempBuffer; // Temporary text buffer
ImGuiContext(ImFontAtlas* shared_font_atlas) ImGuiContext(ImFontAtlas* shared_font_atlas)
: InputTextState(this)
{ {
IO.Ctx = this;
InputTextState.Ctx = this;
Initialized = false; Initialized = false;
FontAtlasOwnedByContext = shared_font_atlas ? false : true; FontAtlasOwnedByContext = shared_font_atlas ? false : true;
Font = NULL; Font = NULL;