Skip to content

Instantly share code, notes, and snippets.

@kudaba
Created February 2, 2021 18:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kudaba/af24f859f46ca339a5dedba9074f4dee to your computer and use it in GitHub Desktop.
Save kudaba/af24f859f46ca339a5dedba9074f4dee to your computer and use it in GitHub Desktop.
Example text input with autocomplete popup
#include <imgui_internal.h>
namespace ImGui
{
inline void ResetTextInputState(ImGuiID anId)
{
// Requires imgui update
//if (GImGui->InputTextState.ID == anId)
// GImGui->InputTextState.Reinitialize = true;
if (GImGui->InputTextState.ID == anId)
GImGui->InputTextState.Stb.cursor = 10000;
}
}
bool ImAutoCompleteText::Update(char const* anId, GC_ArrayRange<GC_String> const& someAutoCompletes, ImGuiInputTextFlags aFlags)
{
struct CallbackData
{
ImAutoCompleteText* Text;
GC_ArrayRange<GC_String> const* AutoCompletes;
uint AutoCompleteSelection;
} data = { this, &someAutoCompletes, someAutoCompletes.Count() };
if (mySelection >= someAutoCompletes.Count())
{
mySelection = 0;
}
ImVec2 startPos = ImGui::GetCursorPos();
ImVec2 startScreenPos = ImGui::GetCursorScreenPos();
bool result = ImGui::InputText(anId, myText.Buffer(), myText.Capacity(), ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_EnterReturnsTrue | aFlags,
[](ImGuiInputTextCallbackData* data) -> int
{
CallbackData* callbackData = (CallbackData*)data->UserData;
if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
{
callbackData->AutoCompleteSelection = callbackData->Text->mySelection;
}
else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
{
if (data->EventKey == ImGuiKey_UpArrow)
{
if (callbackData->Text->mySelection > 0)
--callbackData->Text->mySelection;
}
else if (callbackData->AutoCompletes->Count() && callbackData->Text->mySelection < callbackData->AutoCompletes->Count() - 1)
{
++callbackData->Text->mySelection;
}
}
return 0;
},
&data);
if (myResetFocus)
{
myResetFocus = false;
ImGui::SetKeyboardFocusHere(-1);
}
ImGuiID id = ImGui::GetID(anId);
if (data.AutoCompleteSelection != someAutoCompletes.Count())
{
myText = someAutoCompletes[data.AutoCompleteSelection];
ImGui::ResetTextInputState(id);
}
if (!ImGui::IsItemEnabled() || someAutoCompletes.Count() == 0)
{
myIsPopupActive = false;
}
else if (ImGui::IsItemActive())
{
myIsPopupActive = true;
}
if (myIsPopupActive)
{
// Draw popup window
ImGuiWindowFlags popupFlags =
ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_HorizontalScrollbar |
ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoDocking |
ImGuiWindowFlags_AlwaysAutoResize;
ImVec2 endPos = ImGui::GetCursorPos();
GC_Vector2f winPos = ImGui::GetWindowPos();
if (startPos.y - winPos.y > ImGui::GetContentRegionAvail().y)
{
// appear on top
ImGui::SetNextWindowPos(startScreenPos, 0, { 0, 1 });
}
else
{
// appear on top
ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
}
ImGui::SetNextWindowSizeConstraints({ -1, 0 }, { -1, ImGui::GetTextLineHeight() * 16 });
ImGui::Begin("history_popup", nullptr, popupFlags);
ImGui::PushAllowKeyboardFocus(false);
for_index(char const* ac : someAutoCompletes)
{
bool selected = i == mySelection;
if (ImGui::Selectable(ac, &selected))
{
myText = ac;
myResetFocus = true;
ImGui::ResetTextInputState(id);
}
}
ImGui::PopAllowKeyboardFocus();
if (!ImGui::IsWindowFocused(ImGuiHoveredFlags_RootAndChildWindows))
myIsPopupActive = false;
ImGui::End();
}
return result;
}
#pragma once
struct ImAutoCompleteText
{
ImAutoCompleteText() : mySelection(0), myDrawBelow(false), myIsPopupActive(false) {}
bool Update(char const* anId, GC_ArrayRange<GC_String> const& someAutoCompletes, ImGuiInputTextFlags aFlags = 0);
GC_StaticString<1024> myText;
uint mySelection;
bool myDrawBelow;
bool myIsPopupActive;
bool myResetFocus;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment