Skip to content

Commit

Permalink
Make classes not depend on the implicit GImGui context (#5856, #6199)…
Browse files Browse the repository at this point in the history
…: ImGuiWindow, ImGuiInputTextCallbackData, ImGuiListClipper, ImGuiStackSizes

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.

This commit modifies ImGuiInputTextCallback, ImGuiListClipper and ImGuiStackSize so those classes do not to depend on GImGui context anymore.

About ImGuiInputTextCallback:
- ImGuiInputTextCallback depends on ImGuiContext because it has a
  `InsertChars` method adding character to `g.InputTextState`
- To make ImGuiInputTextCallback aware of which context to use, the
  appropriate context is given as argument of ImGuiInputTextCallback
  constructor.

About ImGuiListClipper:
- ImGuiListClipper apply to a context through its `Begin`, `End`, and `Step`
  method.
- To make ImGuiListClipper aware of which context to use, the
  appropriate context is given as argument of ImGuiListClipper
  constructor.
- Since the behavior is different than previously the class has been
  renamed ImGuiListClipperEx
- In order to preserve backward compatibility, a subclass of ImGuiListClipperEx
  named ImGuiListClipper has been defined and forward the implicit context
  to ImGuiListClipperEx parent.

About ImGuiTextFilter:
- ImGuiTextFilter depends on the implicit context because the Draw(..)
  method call ImGui::InputText(...)
- Instead from that commit the Draw(...) method takes an explicit context
  as first argument
- Since the behavior is different than previously the class has been
  renamed ImGuiTextFilterEx
- In order to preserve backward compatibility, a subclass of ImGuiTextFilterEx
  named ImGuiTextFilter has been defined. This subclass has a draw method
  override which and forward the implicit context to the parent class Draw(...)

About ImGuiStackSizes:
- ImGuiStackSizes was depending on ImGuiContext because of its
  `SetToCurrentState` and `CompareWithCurrentState` method
- ImGuiStackSizes is an helper object use
  for comparing state of context. It does not necessarily need to
  compare the same context. For that reason, as opposed to previous
  classes it takes the context it wants to compare to as argument of
  its method.
- For this occasion `SetToCurrentState` and `CompareWithCurrentState`
  have been renamed `SetToContextState` and `CompareWithContextState`
  to match the new method signature.

ImGuiListClipper

ImGuiInputTextCallbackData
  • Loading branch information
Dragnalith authored and ocornut committed Mar 8, 2023
1 parent 10ace22 commit c8ad25c
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 23 deletions.
33 changes: 18 additions & 15 deletions imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2709,6 +2709,8 @@ static void ImGuiListClipper_SeekCursorForItem(ImGuiListClipper* clipper, int it
ImGuiListClipper::ImGuiListClipper()
{
memset(this, 0, sizeof(*this));
Ctx = ImGui::GetCurrentContext();
IM_ASSERT(Ctx != NULL);
ItemsCount = -1;
}

Expand All @@ -2719,7 +2721,7 @@ ImGuiListClipper::~ImGuiListClipper()

void ImGuiListClipper::Begin(int items_count, float items_height)
{
ImGuiContext& g = *GImGui;
ImGuiContext& g = *Ctx;
ImGuiWindow* window = g.CurrentWindow;
IMGUI_DEBUG_LOG_CLIPPER("Clipper: Begin(%d,%.2f) in '%s'\n", items_count, items_height, window->Name);

Expand All @@ -2744,7 +2746,7 @@ void ImGuiListClipper::Begin(int items_count, float items_height)

void ImGuiListClipper::End()
{
ImGuiContext& g = *GImGui;
ImGuiContext& g = *Ctx;
if (ImGuiListClipperData* data = (ImGuiListClipperData*)TempData)
{
// In theory here we should assert that we are already at the right position, but it seems saner to just seek at the end and not assert/crash the user.
Expand Down Expand Up @@ -2776,7 +2778,7 @@ void ImGuiListClipper::ForceDisplayRangeByIndices(int item_min, int item_max)

static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
{
ImGuiContext& g = *GImGui;
ImGuiContext& g = *clipper->Ctx;
ImGuiWindow* window = g.CurrentWindow;
ImGuiListClipperData* data = (ImGuiListClipperData*)clipper->TempData;
IM_ASSERT(data != NULL && "Called ImGuiListClipper::Step() too many times, or before ImGuiListClipper::Begin() ?");
Expand Down Expand Up @@ -2899,7 +2901,7 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)

bool ImGuiListClipper::Step()
{
ImGuiContext& g = *GImGui;
ImGuiContext& g = *Ctx;
bool need_items_height = (ItemsHeight <= 0.0f);
bool ret = ImGuiListClipper_StepInternal(this);
if (ret && (DisplayStart == DisplayEnd))
Expand Down Expand Up @@ -3618,9 +3620,10 @@ void ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type)
//-----------------------------------------------------------------------------

// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods
ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) : DrawListInst(NULL)
ImGuiWindow::ImGuiWindow(ImGuiContext* ctx, const char* name) : DrawListInst(NULL)
{
memset(this, 0, sizeof(*this));
Ctx = ctx;
Name = ImStrdup(name);
NameBufLen = (int)strlen(name) + 1;
ID = ImHashStr(name);
Expand All @@ -3637,7 +3640,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) : DrawListInst
FontWindowScale = 1.0f;
SettingsOffset = -1;
DrawList = &DrawListInst;
DrawList->_Data = &context->DrawListSharedData;
DrawList->_Data = &Ctx->DrawListSharedData;
DrawList->_OwnerName = Name;
}

Expand All @@ -3652,7 +3655,7 @@ ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
{
ImGuiID seed = IDStack.back();
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
ImGuiContext& g = *GImGui;
ImGuiContext& g = *Ctx;
if (g.DebugHookIdInfo == id)
ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
return id;
Expand All @@ -3662,7 +3665,7 @@ ImGuiID ImGuiWindow::GetID(const void* ptr)
{
ImGuiID seed = IDStack.back();
ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
ImGuiContext& g = *GImGui;
ImGuiContext& g = *Ctx;
if (g.DebugHookIdInfo == id)
ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL);
return id;
Expand All @@ -3672,7 +3675,7 @@ ImGuiID ImGuiWindow::GetID(int n)
{
ImGuiID seed = IDStack.back();
ImGuiID id = ImHashData(&n, sizeof(n), seed);
ImGuiContext& g = *GImGui;
ImGuiContext& g = *Ctx;
if (g.DebugHookIdInfo == id)
ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
return id;
Expand Down Expand Up @@ -6084,7 +6087,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
ImGuiWindowStackData window_stack_data;
window_stack_data.Window = window;
window_stack_data.ParentLastItemDataBackup = g.LastItemData;
window_stack_data.StackSizesOnBegin.SetToCurrentState();
window_stack_data.StackSizesOnBegin.SetToContextState(&g);
g.CurrentWindowStack.push_back(window_stack_data);
if (flags & ImGuiWindowFlags_ChildMenu)
g.BeginMenuCount++;
Expand Down Expand Up @@ -6744,7 +6747,7 @@ void ImGui::End()
g.BeginMenuCount--;
if (window->Flags & ImGuiWindowFlags_Popup)
g.BeginPopupStack.pop_back();
g.CurrentWindowStack.back().StackSizesOnBegin.CompareWithCurrentState();
g.CurrentWindowStack.back().StackSizesOnBegin.CompareWithContextState(&g);
g.CurrentWindowStack.pop_back();
SetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window);
}
Expand Down Expand Up @@ -9064,9 +9067,9 @@ void ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, vo
}

// Save current stack sizes for later compare
void ImGuiStackSizes::SetToCurrentState()
void ImGuiStackSizes::SetToContextState(ImGuiContext* ctx)
{
ImGuiContext& g = *GImGui;
ImGuiContext& g = *ctx;
ImGuiWindow* window = g.CurrentWindow;
SizeOfIDStack = (short)window->IDStack.Size;
SizeOfColorStack = (short)g.ColorStack.Size;
Expand All @@ -9080,9 +9083,9 @@ void ImGuiStackSizes::SetToCurrentState()
}

// Compare to detect usage errors
void ImGuiStackSizes::CompareWithCurrentState()
void ImGuiStackSizes::CompareWithContextState(ImGuiContext* ctx)
{
ImGuiContext& g = *GImGui;
ImGuiContext& g = *ctx;
ImGuiWindow* window = g.CurrentWindow;
IM_UNUSED(window);

Expand Down
2 changes: 2 additions & 0 deletions imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -2079,6 +2079,7 @@ struct ImGuiIO
// - ImGuiInputTextFlags_CallbackResize: Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow.
struct ImGuiInputTextCallbackData
{
ImGuiContext* Ctx; // Parent UI context
ImGuiInputTextFlags EventFlag; // One ImGuiInputTextFlags_Callback* // Read-only
ImGuiInputTextFlags Flags; // What user passed to InputText() // Read-only
void* UserData; // What user passed to InputText() // Read-only
Expand Down Expand Up @@ -2303,6 +2304,7 @@ struct ImGuiStorage
// - The clipper also handles various subtleties related to keyboard/gamepad navigation, wrapping etc.
struct ImGuiListClipper
{
ImGuiContext* Ctx; // Parent UI context
int DisplayStart; // First item to display, updated by each call to Step()
int DisplayEnd; // End of items to display (exclusive)
int ItemsCount; // [Internal] Number of items
Expand Down
11 changes: 6 additions & 5 deletions imgui_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1182,8 +1182,8 @@ struct IMGUI_API ImGuiStackSizes
short SizeOfDisabledStack;

ImGuiStackSizes() { memset(this, 0, sizeof(*this)); }
void SetToCurrentState();
void CompareWithCurrentState();
void SetToContextState(ImGuiContext* ctx);
void CompareWithContextState(ImGuiContext* ctx);
};

// Data saved for each window pushed into the stack
Expand Down Expand Up @@ -2237,6 +2237,7 @@ struct IMGUI_API ImGuiWindowTempData
// Storage for one window
struct IMGUI_API ImGuiWindow
{
ImGuiContext* Ctx; // Parent UI context (needs to be set explicitly by parent).
char* Name; // Window name, owned by the window.
ImGuiID ID; // == ImHashStr(Name)
ImGuiWindowFlags Flags; // See enum ImGuiWindowFlags_
Expand Down Expand Up @@ -2347,10 +2348,10 @@ struct IMGUI_API ImGuiWindow

// We don't use g.FontSize because the window may be != g.CurrentWindow.
ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
float CalcFontSize() const { ImGuiContext& g = *GImGui; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; }
float TitleBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + g.Style.FramePadding.y * 2.0f; }
float CalcFontSize() const { ImGuiContext& g = *Ctx; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; }
float TitleBarHeight() const { ImGuiContext& g = *Ctx; return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + g.Style.FramePadding.y * 2.0f; }
ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); }
float MenuBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + g.Style.FramePadding.y * 2.0f : 0.0f; }
float MenuBarHeight() const { ImGuiContext& g = *Ctx; return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + g.Style.FramePadding.y * 2.0f : 0.0f; }
ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); }
};

Expand Down
8 changes: 5 additions & 3 deletions imgui_widgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3843,7 +3843,7 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons
return;

// Contrary to STB_TEXTEDIT_INSERTCHARS() this is working in the UTF8 buffer, hence the mildly similar code (until we remove the U16 buffer altogether!)
ImGuiContext& g = *GImGui;
ImGuiContext& g = *Ctx;
ImGuiInputTextState* edit_state = &g.InputTextState;
IM_ASSERT(edit_state->ID != 0 && g.ActiveId == edit_state->ID);
IM_ASSERT(Buf == edit_state->TextA.Data);
Expand Down Expand Up @@ -3947,8 +3947,9 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f
// Custom callback filter
if (flags & ImGuiInputTextFlags_CallbackCharFilter)
{
ImGuiContext& g = *GImGui;
ImGuiInputTextCallbackData callback_data;
memset(&callback_data, 0, sizeof(ImGuiInputTextCallbackData));
callback_data.Ctx = &g;
callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter;
callback_data.EventChar = (ImWchar)c;
callback_data.Flags = flags;
Expand Down Expand Up @@ -4588,7 +4589,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (event_flag)
{
ImGuiInputTextCallbackData callback_data;
memset(&callback_data, 0, sizeof(ImGuiInputTextCallbackData));
callback_data.Ctx = &g;
callback_data.EventFlag = event_flag;
callback_data.Flags = flags;
callback_data.UserData = callback_user_data;
Expand Down Expand Up @@ -4651,6 +4652,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (is_resizable)
{
ImGuiInputTextCallbackData callback_data;
callback_data.Ctx = &g;
callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize;
callback_data.Flags = flags;
callback_data.Buf = buf;
Expand Down

0 comments on commit c8ad25c

Please sign in to comment.