mirror of
https://github.com/ocornut/imgui.git
synced 2024-11-13 18:50:58 +01:00
TypingSelect: rework GetTypingSelectRequest(), provide TypingSelectFindResult().
Amend 9714594
This commit is contained in:
parent
9714594c35
commit
f336e639e9
@ -1540,21 +1540,23 @@ struct ImGuiNavItemData
|
|||||||
// [SECTION] Typing-select support
|
// [SECTION] Typing-select support
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
// Flags for GetTypingSelectRequest()
|
// Flags for GetTypingSelectRequest(), TypingSelectFindResult()
|
||||||
enum ImGuiTypingSelectFlags_
|
enum ImGuiTypingSelectFlags_
|
||||||
{
|
{
|
||||||
ImGuiTypingSelectFlags_None = 0,
|
ImGuiTypingSelectFlags_None = 0,
|
||||||
ImGuiTypingSelectFlags_AllowBackspace = 1 << 0, // Backspace to delete character inputs. If using: ensure GetTypingSelectRequest() is not called more than once per frame (filter by e.g. focus state)
|
ImGuiTypingSelectFlags_AllowBackspace = 1 << 0, // Backspace to delete character inputs. If using: ensure GetTypingSelectRequest() is not called more than once per frame (filter by e.g. focus state)
|
||||||
|
ImGuiTypingSelectFlags_AllowSingleCharMode = 1 << 1, // Allow "single char" search mode which is activated when pressing the same character multiple times.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returned by GetTypingSelectRequest(), designed to eventually be public.
|
// Returned by GetTypingSelectRequest(), designed to eventually be public.
|
||||||
struct IMGUI_API ImGuiTypingSelectRequest
|
struct IMGUI_API ImGuiTypingSelectRequest
|
||||||
{
|
{
|
||||||
const char* SearchBuffer;
|
ImGuiTypingSelectFlags Flags; // Flags passed to GetTypingSelectRequest()
|
||||||
int SearchBufferLen;
|
int SearchBufferLen;
|
||||||
bool SelectRequest; // Set when buffer was modified this frame, requesting a selection.
|
const char* SearchBuffer;
|
||||||
bool RepeatCharMode; // Notify when buffer contains same character repeated, to implement special mode.
|
bool SelectRequest; // Set when buffer was modified this frame, requesting a selection.
|
||||||
ImS8 RepeatCharSize; // Length in bytes of first letter codepoint (1 for ascii, 2-4 for UTF-8). If (SearchBufferLen==RepeatCharSize) only 1 letter has been input.
|
bool SingleCharMode; // Notify when buffer contains same character repeated, to implement special mode.
|
||||||
|
ImS8 SingleCharSize; // Length in bytes of first letter codepoint (1 for ascii, 2-4 for UTF-8). If (SearchBufferLen==RepeatCharSize) only 1 letter has been input.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Storage for GetTypingSelectRequest()
|
// Storage for GetTypingSelectRequest()
|
||||||
@ -3097,7 +3099,8 @@ namespace ImGui
|
|||||||
IMGUI_API void RenderDragDropTargetRect(const ImRect& bb);
|
IMGUI_API void RenderDragDropTargetRect(const ImRect& bb);
|
||||||
|
|
||||||
// Typing-Select API
|
// Typing-Select API
|
||||||
IMGUI_API const ImGuiTypingSelectRequest* GetTypingSelectRequest(ImGuiTypingSelectFlags flags = ImGuiTypingSelectFlags_None);
|
IMGUI_API ImGuiTypingSelectRequest* GetTypingSelectRequest(ImGuiTypingSelectFlags flags = ImGuiTypingSelectFlags_None);
|
||||||
|
IMGUI_API int TypingSelectFindResult(ImGuiTypingSelectRequest* req, int items_count, const char* (*get_item_name_func)(void*, int), void* user_data, int nav_item_idx);
|
||||||
|
|
||||||
// Internal Columns API (this is not exposed because we will encourage transitioning to the Tables API)
|
// Internal Columns API (this is not exposed because we will encourage transitioning to the Tables API)
|
||||||
IMGUI_API void SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect);
|
IMGUI_API void SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect);
|
||||||
|
@ -6612,11 +6612,10 @@ bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags
|
|||||||
// Consume character inputs and return search request, if any.
|
// Consume character inputs and return search request, if any.
|
||||||
// This would typically only be called on the focused window or location you want to grab inputs for, e.g.
|
// This would typically only be called on the focused window or location you want to grab inputs for, e.g.
|
||||||
// if (ImGui::IsWindowFocused(...))
|
// if (ImGui::IsWindowFocused(...))
|
||||||
// if (const ImGuiTypingSelectRequest* req = ImGui::GetTypingSelectRequest())
|
// if (ImGuiTypingSelectRequest* req = ImGui::GetTypingSelectRequest())
|
||||||
// if (req->SearchRequest)
|
// focus_idx = ImGui::TypingSelectFindResult(req, my_items.size(), [](void*, int n) { return my_items[n]->Name; }, &my_items, -1);
|
||||||
// // perform search
|
|
||||||
// However the code is written in a way where calling it from multiple locations is safe (e.g. to obtain buffer).
|
// However the code is written in a way where calling it from multiple locations is safe (e.g. to obtain buffer).
|
||||||
const ImGuiTypingSelectRequest* ImGui::GetTypingSelectRequest(ImGuiTypingSelectFlags flags)
|
ImGuiTypingSelectRequest* ImGui::GetTypingSelectRequest(ImGuiTypingSelectFlags flags)
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
ImGuiTypingSelectData* data = &g.TypingSelectData;
|
ImGuiTypingSelectData* data = &g.TypingSelectData;
|
||||||
@ -6663,36 +6662,98 @@ const ImGuiTypingSelectRequest* ImGui::GetTypingSelectRequest(ImGuiTypingSelectF
|
|||||||
if (buffer_len == 0)
|
if (buffer_len == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// Return request if any
|
|
||||||
if (buffer_changed)
|
if (buffer_changed)
|
||||||
{
|
{
|
||||||
data->FocusScope = g.NavFocusScopeId;
|
data->FocusScope = g.NavFocusScopeId;
|
||||||
data->LastRequestFrame = g.FrameCount;
|
data->LastRequestFrame = g.FrameCount;
|
||||||
data->LastRequestTime = (float)g.Time;
|
data->LastRequestTime = (float)g.Time;
|
||||||
}
|
}
|
||||||
out_request->SearchBuffer = data->SearchBuffer;
|
|
||||||
|
// Return request if any
|
||||||
|
out_request->Flags = flags;
|
||||||
out_request->SearchBufferLen = buffer_len;
|
out_request->SearchBufferLen = buffer_len;
|
||||||
|
out_request->SearchBuffer = data->SearchBuffer;
|
||||||
out_request->SelectRequest = (data->LastRequestFrame == g.FrameCount);
|
out_request->SelectRequest = (data->LastRequestFrame == g.FrameCount);
|
||||||
out_request->RepeatCharMode = false;
|
out_request->SingleCharMode = false;
|
||||||
out_request->RepeatCharSize = 0;
|
out_request->SingleCharSize = 0;
|
||||||
|
|
||||||
// Calculate if buffer contains the same character repeated.
|
// Calculate if buffer contains the same character repeated.
|
||||||
// - This can be used to implement a special search mode on first character.
|
// - This can be used to implement a special search mode on first character.
|
||||||
// - Performed on UTF-8 codepoint for correctness.
|
// - Performed on UTF-8 codepoint for correctness.
|
||||||
// - RepeatCharMode is always set for first input character, because it usually leads to a "next".
|
// - SingleCharMode is always set for first input character, because it usually leads to a "next".
|
||||||
const char* buf_begin = out_request->SearchBuffer;
|
if (flags & ImGuiTypingSelectFlags_AllowSingleCharMode)
|
||||||
const char* buf_end = out_request->SearchBuffer + out_request->SearchBufferLen;
|
{
|
||||||
const int c0_len = ImTextCountUtf8BytesFromChar(buf_begin, buf_end);
|
const char* buf_begin = out_request->SearchBuffer;
|
||||||
const char* p = buf_begin + c0_len;
|
const char* buf_end = out_request->SearchBuffer + out_request->SearchBufferLen;
|
||||||
for (; p < buf_end; p += c0_len)
|
const int c0_len = ImTextCountUtf8BytesFromChar(buf_begin, buf_end);
|
||||||
if (memcmp(buf_begin, p, (size_t)c0_len) != 0)
|
const char* p = buf_begin + c0_len;
|
||||||
break;
|
for (; p < buf_end; p += c0_len)
|
||||||
out_request->RepeatCharMode = (p == buf_end);
|
if (memcmp(buf_begin, p, (size_t)c0_len) != 0)
|
||||||
out_request->RepeatCharSize = out_request->RepeatCharMode ? (ImS8)c0_len : 0;
|
break;
|
||||||
|
out_request->SingleCharMode = (p == buf_end);
|
||||||
|
out_request->SingleCharSize = out_request->SingleCharMode ? (ImS8)c0_len : 0;
|
||||||
|
}
|
||||||
|
|
||||||
return out_request;
|
return out_request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ImStrimatchlen(const char* s1, const char* s1_end, const char* s2)
|
||||||
|
{
|
||||||
|
int match_len = 0;
|
||||||
|
while (s1 < s1_end && ImToUpper(*s1++) == ImToUpper(*s2++))
|
||||||
|
match_len++;
|
||||||
|
return match_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default handler for finding a result for typing-select. You may implement your own.
|
||||||
|
// You might want to display a tooltip to visualize the current request.
|
||||||
|
// With same single character mode enabled:
|
||||||
|
// - it may make less sense to be displaying a tooltip.
|
||||||
|
// - the index of the currently focused item is required.
|
||||||
|
// - in the context of using BeginMultiSelect(), you may retrieve data you stored to ImGuiMultiSelectIO::NavIdItem and convert it to an index.
|
||||||
|
int ImGui::TypingSelectFindResult(ImGuiTypingSelectRequest* req, int items_count, const char* (*get_item_name_func)(void*, int), void* user_data, int nav_item_idx)
|
||||||
|
{
|
||||||
|
if (req->SelectRequest == false)
|
||||||
|
return -1;
|
||||||
|
if (req->SingleCharMode && (req->Flags & ImGuiTypingSelectFlags_AllowSingleCharMode))
|
||||||
|
{
|
||||||
|
// Special handling when a same character is typed twice in a row : perform search on a single letter and goes to next.
|
||||||
|
int first_match_idx = -1;
|
||||||
|
bool return_next_match = false;
|
||||||
|
for (int idx = 0; idx < items_count; idx++)
|
||||||
|
{
|
||||||
|
const char* item_name = get_item_name_func(user_data, idx);
|
||||||
|
if (ImStrimatchlen(req->SearchBuffer, req->SearchBuffer + req->SingleCharSize, item_name) < req->SingleCharSize)
|
||||||
|
continue;
|
||||||
|
if (return_next_match) // Return next matching item after current item.
|
||||||
|
return idx;
|
||||||
|
if (first_match_idx == -1 && nav_item_idx == -1) // Return first match immediately if we don't have a nav_item_idx value.
|
||||||
|
return idx;
|
||||||
|
if (first_match_idx == -1) // Record first match for wrapping.
|
||||||
|
first_match_idx = idx;
|
||||||
|
if (nav_item_idx == idx) // Record that we encountering nav_item so we can return next match.
|
||||||
|
return_next_match = true;
|
||||||
|
}
|
||||||
|
return first_match_idx; // First result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find longest match in item list
|
||||||
|
int longest_match_idx = -1;
|
||||||
|
int longest_match_len = 0;
|
||||||
|
for (int idx = 0; idx < items_count; idx++)
|
||||||
|
{
|
||||||
|
const char* item_name = get_item_name_func(user_data, idx);
|
||||||
|
const int match_len = ImStrimatchlen(req->SearchBuffer, req->SearchBuffer + req->SearchBufferLen, item_name);
|
||||||
|
if (match_len <= longest_match_len)
|
||||||
|
continue;
|
||||||
|
longest_match_idx = idx;
|
||||||
|
longest_match_len = match_len;
|
||||||
|
if (match_len == req->SearchBufferLen)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return longest_match_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// [SECTION] Widgets: Multi-Select support
|
// [SECTION] Widgets: Multi-Select support
|
||||||
|
Loading…
Reference in New Issue
Block a user