mirror of
https://github.com/ocornut/imgui.git
synced 2026-01-11 00:04:24 +00:00
Merge branch 'master' into docking
This commit is contained in:
commit
71f45c12e9
8 changed files with 234 additions and 228 deletions
2
.github/workflows/static-analysis.yml
vendored
2
.github/workflows/static-analysis.yml
vendored
|
|
@ -42,5 +42,5 @@ jobs:
|
||||||
fi
|
fi
|
||||||
cd examples/example_null
|
cd examples/example_null
|
||||||
pvs-studio-analyzer trace -- make WITH_EXTRA_WARNINGS=1
|
pvs-studio-analyzer trace -- make WITH_EXTRA_WARNINGS=1
|
||||||
pvs-studio-analyzer analyze -e ../../imstb_rectpack.h -e ../../imstb_textedit.h -e ../../imstb_truetype.h -l ../../pvs-studio.lic -o pvs-studio.log
|
pvs-studio-analyzer analyze --disableLicenseExpirationCheck -e ../../imstb_rectpack.h -e ../../imstb_textedit.h -e ../../imstb_truetype.h -l ../../pvs-studio.lic -o pvs-studio.log
|
||||||
plog-converter -a 'GA:1,2;OP:1' -d V1071 -t errorfile -w pvs-studio.log
|
plog-converter -a 'GA:1,2;OP:1' -d V1071 -t errorfile -w pvs-studio.log
|
||||||
|
|
|
||||||
|
|
@ -66,14 +66,18 @@ Other Changes:
|
||||||
In theory the buffer size should always account for a zero-terminator, but idioms
|
In theory the buffer size should always account for a zero-terminator, but idioms
|
||||||
such as using InputTextMultiline() with ImGuiInputTextFlags_ReadOnly to display
|
such as using InputTextMultiline() with ImGuiInputTextFlags_ReadOnly to display
|
||||||
a text blob are facilitated by allowing this.
|
a text blob are facilitated by allowing this.
|
||||||
|
- InputText: refactored internals to simplify and optimizing rendering of selection.
|
||||||
|
Very large selection (e.g. 1 MB) now take less overhead.
|
||||||
- InputText: revert a change in 1.79 where pressing Down or PageDown on the last line
|
- InputText: revert a change in 1.79 where pressing Down or PageDown on the last line
|
||||||
of a multi-line buffer without a trailing carriage return would keep the cursor
|
of a multi-line buffer without a trailing carriage return would keep the cursor
|
||||||
unmoved. We revert back to move to the end of line in this situation.
|
unmoved. We revert back to move to the end of line in this situation.
|
||||||
|
- InputText: fixed pressing End (without Shift) in a multi-line selection from
|
||||||
|
mistakenly moving cursor based on selection start.
|
||||||
- Focus, InputText: fixed an issue where SetKeyboardFocusHere() did not work
|
- Focus, InputText: fixed an issue where SetKeyboardFocusHere() did not work
|
||||||
on InputTextMultiline() fields with ImGuiInputTextFlags_AllowTabInput, since
|
on InputTextMultiline() fields with ImGuiInputTextFlags_AllowTabInput, since
|
||||||
they normally inhibit activation to allow tabbing through multiple items. (#8928)
|
they normally inhibit activation to allow tabbing through multiple items. (#8928)
|
||||||
- Selectable: added ImGuiSelectableFlags_SelectOnNav to auto-select an item when
|
- Selectable: added ImGuiSelectableFlags_SelectOnNav to auto-select an item when
|
||||||
moved into (automatic when in a BeginMultiSelect() block).
|
moved into, unless Ctrl is held. (automatic when in a BeginMultiSelect() block).
|
||||||
- TabBar: fixed an issue were forcefully selecting a tab using internal API would
|
- TabBar: fixed an issue were forcefully selecting a tab using internal API would
|
||||||
be ignored on first/appearing frame before tabs are submitted (#8929, #6681)
|
be ignored on first/appearing frame before tabs are submitted (#8929, #6681)
|
||||||
- DrawList: fixed CloneOutput() unnecessarily taking a copy of the ImDrawListSharedData
|
- DrawList: fixed CloneOutput() unnecessarily taking a copy of the ImDrawListSharedData
|
||||||
|
|
@ -85,6 +89,8 @@ Other Changes:
|
||||||
is now skipped. (#8904, #4631)
|
is now skipped. (#8904, #4631)
|
||||||
- Debug Tools: ID Stack Tool: added option to hex-encode non-ASCII characters in
|
- Debug Tools: ID Stack Tool: added option to hex-encode non-ASCII characters in
|
||||||
output path. (#8904, #4631)
|
output path. (#8904, #4631)
|
||||||
|
- Debug Tools: Fixed assertion failure when opening a combo box while using
|
||||||
|
io.ConfigDebugBeginReturnValueOnce/ConfigDebugBeginReturnValueLoop. (#8931) [@harrymander]
|
||||||
- Demo: tweaked ShowFontSelector() and ShowStyleSelector() to update selection
|
- Demo: tweaked ShowFontSelector() and ShowStyleSelector() to update selection
|
||||||
while navigating and to not close popup automatically.
|
while navigating and to not close popup automatically.
|
||||||
- Examples: Android: Android+OpenGL3: update Gradle project (#8888, #8878) [@scribam]
|
- Examples: Android: Android+OpenGL3: update Gradle project (#8888, #8878) [@scribam]
|
||||||
|
|
|
||||||
17
imgui.cpp
17
imgui.cpp
|
|
@ -3137,19 +3137,21 @@ void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
|
||||||
va_end(args_copy);
|
va_end(args_copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IM_MSVC_RUNTIME_CHECKS_OFF
|
||||||
void ImGuiTextIndex::append(const char* base, int old_size, int new_size)
|
void ImGuiTextIndex::append(const char* base, int old_size, int new_size)
|
||||||
{
|
{
|
||||||
IM_ASSERT(old_size >= 0 && new_size >= old_size && new_size >= EndOffset);
|
IM_ASSERT(old_size >= 0 && new_size >= old_size && new_size >= EndOffset);
|
||||||
if (old_size == new_size)
|
if (old_size == new_size)
|
||||||
return;
|
return;
|
||||||
if (EndOffset == 0 || base[EndOffset - 1] == '\n')
|
if (EndOffset == 0 || base[EndOffset - 1] == '\n')
|
||||||
LineOffsets.push_back(EndOffset);
|
Offsets.push_back(EndOffset);
|
||||||
const char* base_end = base + new_size;
|
const char* base_end = base + new_size;
|
||||||
for (const char* p = base + old_size; (p = (const char*)ImMemchr(p, '\n', base_end - p)) != 0; )
|
for (const char* p = base + old_size; (p = (const char*)ImMemchr(p, '\n', base_end - p)) != 0; )
|
||||||
if (++p < base_end) // Don't push a trailing offset on last \n
|
if (++p < base_end) // Don't push a trailing offset on last \n
|
||||||
LineOffsets.push_back((int)(intptr_t)(p - base));
|
Offsets.push_back((int)(intptr_t)(p - base));
|
||||||
EndOffset = ImMax(EndOffset, new_size);
|
EndOffset = ImMax(EndOffset, new_size);
|
||||||
}
|
}
|
||||||
|
IM_MSVC_RUNTIME_CHECKS_RESTORE
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] ImGuiListClipper
|
// [SECTION] ImGuiListClipper
|
||||||
|
|
@ -3477,6 +3479,13 @@ bool ImGuiListClipper::Step()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generic helper, equivalent to old ImGui::CalcListClipping() but statelesss
|
||||||
|
void ImGui::CalcClipRectVisibleItemsY(const ImRect& clip_rect, const ImVec2& pos, float items_height, int* out_visible_start, int* out_visible_end)
|
||||||
|
{
|
||||||
|
*out_visible_start = ImMax((int)((clip_rect.Min.y - pos.y) / items_height), 0);
|
||||||
|
*out_visible_end = ImMax((int)ImCeil((clip_rect.Max.y - pos.y) / items_height), *out_visible_start);
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// [SECTION] STYLING
|
// [SECTION] STYLING
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
@ -4473,6 +4482,7 @@ void ImGui::Shutdown()
|
||||||
g.ClipboardHandlerData.clear();
|
g.ClipboardHandlerData.clear();
|
||||||
g.MenusIdSubmittedThisFrame.clear();
|
g.MenusIdSubmittedThisFrame.clear();
|
||||||
g.InputTextState.ClearFreeMemory();
|
g.InputTextState.ClearFreeMemory();
|
||||||
|
g.InputTextLineIndex.clear();
|
||||||
g.InputTextDeactivatedState.ClearFreeMemory();
|
g.InputTextDeactivatedState.ClearFreeMemory();
|
||||||
|
|
||||||
g.SettingsWindows.clear();
|
g.SettingsWindows.clear();
|
||||||
|
|
@ -4593,6 +4603,7 @@ void ImGui::GcCompactTransientMiscBuffers()
|
||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
g.ItemFlagsStack.clear();
|
g.ItemFlagsStack.clear();
|
||||||
g.GroupStack.clear();
|
g.GroupStack.clear();
|
||||||
|
g.InputTextLineIndex.clear();
|
||||||
g.MultiSelectTempDataStacked = 0;
|
g.MultiSelectTempDataStacked = 0;
|
||||||
g.MultiSelectTempData.clear_destruct();
|
g.MultiSelectTempData.clear_destruct();
|
||||||
TableGcCompactSettings();
|
TableGcCompactSettings();
|
||||||
|
|
@ -23752,7 +23763,7 @@ void ImGui::ShowFontSelector(const char* label)
|
||||||
for (ImFont* font : io.Fonts->Fonts)
|
for (ImFont* font : io.Fonts->Fonts)
|
||||||
{
|
{
|
||||||
PushID((void*)font);
|
PushID((void*)font);
|
||||||
if (Selectable(font->GetDebugName(), font == font_current, ImGuiSelectableFlags_SelectOnNav | ImGuiSelectableFlags_NoAutoClosePopups))
|
if (Selectable(font->GetDebugName(), font == font_current, ImGuiSelectableFlags_SelectOnNav))
|
||||||
io.FontDefault = font;
|
io.FontDefault = font;
|
||||||
if (font == font_current)
|
if (font == font_current)
|
||||||
SetItemDefaultFocus();
|
SetItemDefaultFocus();
|
||||||
|
|
|
||||||
2
imgui.h
2
imgui.h
|
|
@ -1380,7 +1380,7 @@ enum ImGuiSelectableFlags_
|
||||||
ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text
|
ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text
|
||||||
ImGuiSelectableFlags_AllowOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one
|
ImGuiSelectableFlags_AllowOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one
|
||||||
ImGuiSelectableFlags_Highlight = 1 << 5, // Make the item be displayed as if it is hovered
|
ImGuiSelectableFlags_Highlight = 1 << 5, // Make the item be displayed as if it is hovered
|
||||||
ImGuiSelectableFlags_SelectOnNav = 1 << 6, // Auto-select when moved into. Automatic when in a BeginMultiSelect() block.
|
ImGuiSelectableFlags_SelectOnNav = 1 << 6, // Auto-select when moved into, unless Ctrl is held. Automatic when in a BeginMultiSelect() block.
|
||||||
|
|
||||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||||
ImGuiSelectableFlags_DontClosePopups = ImGuiSelectableFlags_NoAutoClosePopups, // Renamed in 1.91.0
|
ImGuiSelectableFlags_DontClosePopups = ImGuiSelectableFlags_NoAutoClosePopups, // Renamed in 1.91.0
|
||||||
|
|
|
||||||
|
|
@ -8328,17 +8328,18 @@ void ImGui::ShowAboutWindow(bool* p_open)
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
|
// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
|
||||||
// Here we use the simplified Combo() api that packs items into a single literal string.
|
|
||||||
// Useful for quick combo boxes where the choices are known locally.
|
|
||||||
bool ImGui::ShowStyleSelector(const char* label)
|
bool ImGui::ShowStyleSelector(const char* label)
|
||||||
{
|
{
|
||||||
|
// FIXME: This is a bit tricky to get right as style are functions, they don't register a name nor the fact that one is active.
|
||||||
|
// So we keep track of last active one among our limited selection.
|
||||||
static int style_idx = -1;
|
static int style_idx = -1;
|
||||||
const char* style_names[] = { "Dark", "Light", "Classic" };
|
const char* style_names[] = { "Dark", "Light", "Classic" };
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (ImGui::BeginCombo(label, (style_idx >= 0 && style_idx < IM_ARRAYSIZE(style_names)) ? style_names[style_idx] : ""))
|
if (ImGui::BeginCombo(label, (style_idx >= 0 && style_idx < IM_ARRAYSIZE(style_names)) ? style_names[style_idx] : ""))
|
||||||
{
|
{
|
||||||
for (int n = 0; n < IM_ARRAYSIZE(style_names); n++)
|
for (int n = 0; n < IM_ARRAYSIZE(style_names); n++)
|
||||||
if (ImGui::Selectable(style_names[n], style_idx == n, ImGuiSelectableFlags_SelectOnNav | ImGuiSelectableFlags_NoAutoClosePopups))
|
{
|
||||||
|
if (ImGui::Selectable(style_names[n], style_idx == n, ImGuiSelectableFlags_SelectOnNav))
|
||||||
{
|
{
|
||||||
style_idx = n;
|
style_idx = n;
|
||||||
ret = true;
|
ret = true;
|
||||||
|
|
@ -8349,6 +8350,9 @@ bool ImGui::ShowStyleSelector(const char* label)
|
||||||
case 2: ImGui::StyleColorsClassic(); break;
|
case 2: ImGui::StyleColorsClassic(); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (style_idx == n)
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
}
|
||||||
ImGui::EndCombo();
|
ImGui::EndCombo();
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
||||||
|
|
@ -815,13 +815,13 @@ struct ImChunkStream
|
||||||
// Maintain a line index for a text buffer. This is a strong candidate to be moved into the public API.
|
// Maintain a line index for a text buffer. This is a strong candidate to be moved into the public API.
|
||||||
struct ImGuiTextIndex
|
struct ImGuiTextIndex
|
||||||
{
|
{
|
||||||
ImVector<int> LineOffsets;
|
ImVector<int> Offsets;
|
||||||
int EndOffset = 0; // Because we don't own text buffer we need to maintain EndOffset (may bake in LineOffsets?)
|
int EndOffset = 0; // Because we don't own text buffer we need to maintain EndOffset (may bake in LineOffsets?)
|
||||||
|
|
||||||
void clear() { LineOffsets.clear(); EndOffset = 0; }
|
void clear() { Offsets.clear(); EndOffset = 0; }
|
||||||
int size() { return LineOffsets.Size; }
|
int size() { return Offsets.Size; }
|
||||||
const char* get_line_begin(const char* base, int n) { return base + LineOffsets[n]; }
|
const char* get_line_begin(const char* base, int n) { return base + (Offsets.Size != 0 ? Offsets[n] : 0); }
|
||||||
const char* get_line_end(const char* base, int n) { return base + (n + 1 < LineOffsets.Size ? (LineOffsets[n + 1] - 1) : EndOffset); }
|
const char* get_line_end(const char* base, int n) { return base + (n + 1 < Offsets.Size ? (Offsets[n + 1] - 1) : EndOffset); }
|
||||||
void append(const char* base, int old_size, int new_size);
|
void append(const char* base, int old_size, int new_size);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -2635,6 +2635,7 @@ struct ImGuiContext
|
||||||
|
|
||||||
// Widget state
|
// Widget state
|
||||||
ImGuiInputTextState InputTextState;
|
ImGuiInputTextState InputTextState;
|
||||||
|
ImGuiTextIndex InputTextLineIndex; // Temporary storage
|
||||||
ImGuiInputTextDeactivatedState InputTextDeactivatedState;
|
ImGuiInputTextDeactivatedState InputTextDeactivatedState;
|
||||||
ImFontBaked InputTextPasswordFontBackupBaked;
|
ImFontBaked InputTextPasswordFontBackupBaked;
|
||||||
ImFontFlags InputTextPasswordFontBackupFlags;
|
ImFontFlags InputTextPasswordFontBackupFlags;
|
||||||
|
|
@ -3495,6 +3496,7 @@ namespace ImGui
|
||||||
IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x);
|
IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x);
|
||||||
IMGUI_API void PushMultiItemsWidths(int components, float width_full);
|
IMGUI_API void PushMultiItemsWidths(int components, float width_full);
|
||||||
IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess, float width_min);
|
IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess, float width_min);
|
||||||
|
IMGUI_API void CalcClipRectVisibleItemsY(const ImRect& clip_rect, const ImVec2& pos, float items_height, int* out_visible_start, int* out_visible_end);
|
||||||
|
|
||||||
// Parameter stacks (shared)
|
// Parameter stacks (shared)
|
||||||
IMGUI_API const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx);
|
IMGUI_API const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx);
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,6 @@ static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1);
|
||||||
|
|
||||||
// For InputTextEx()
|
// For InputTextEx()
|
||||||
static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard = false);
|
static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, bool input_source_is_clipboard = false);
|
||||||
static int InputTextCalcTextLenAndLineCount(ImGuiContext* ctx, const char* text_begin, const char** out_text_end, float wrap_width);
|
|
||||||
static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end_display, const char* text_end, const char** out_remaining = NULL, ImVec2* out_offset = NULL, ImDrawTextFlags flags = 0);
|
static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end_display, const char* text_end, const char** out_remaining = NULL, ImVec2* out_offset = NULL, ImDrawTextFlags flags = 0);
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
|
|
@ -2038,7 +2037,8 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags
|
||||||
if (!ret)
|
if (!ret)
|
||||||
{
|
{
|
||||||
EndPopup();
|
EndPopup();
|
||||||
IM_ASSERT(0); // This should never happen as we tested for IsPopupOpen() above
|
if (!g.IO.ConfigDebugBeginReturnValueOnce && !g.IO.ConfigDebugBeginReturnValueLoop) // Begin may only return false with those debug tools activated.
|
||||||
|
IM_ASSERT(0); // This should never happen as we tested for IsPopupOpen() above
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
g.BeginComboDepth++;
|
g.BeginComboDepth++;
|
||||||
|
|
@ -3943,46 +3943,6 @@ bool ImGui::InputTextWithHint(const char* label, const char* hint, char* buf, si
|
||||||
return InputTextEx(label, hint, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data);
|
return InputTextEx(label, hint, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is only used in the path where the multiline widget is inactive.
|
|
||||||
static int InputTextCalcTextLenAndLineCount(ImGuiContext* ctx, const char* text_begin, const char** out_text_end, float wrap_width)
|
|
||||||
{
|
|
||||||
int line_count = 0;
|
|
||||||
const char* s = text_begin;
|
|
||||||
if (wrap_width == 0.0f)
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
const char* s_eol = strchr(s, '\n');
|
|
||||||
line_count++;
|
|
||||||
if (s_eol == NULL)
|
|
||||||
{
|
|
||||||
s = s + ImStrlen(s);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
s = s_eol + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// FIXME-WORDWRAP, FIXME-OPT: This is very suboptimal.
|
|
||||||
// We basically want both text_end and text_size, they could more optimally be emitted from a RenderText call that uses word-wrapping.
|
|
||||||
ImGuiContext& g = *ctx;
|
|
||||||
ImFont* font = g.Font;
|
|
||||||
const char* text_end = text_begin + strlen(text_begin);
|
|
||||||
while (s < text_end)
|
|
||||||
{
|
|
||||||
s = ImFontCalcWordWrapPositionEx(font, g.FontSize, s, text_end, wrap_width, ImDrawTextFlags_WrapKeepBlanks);
|
|
||||||
s = (*s == '\n') ? s + 1 : s;
|
|
||||||
line_count++;
|
|
||||||
}
|
|
||||||
if (text_end > text_begin && text_end[-1] == '\n')
|
|
||||||
line_count++;
|
|
||||||
IM_ASSERT(s == text_end);
|
|
||||||
}
|
|
||||||
*out_text_end = s;
|
|
||||||
return line_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end_display, const char* text_end, const char** out_remaining, ImVec2* out_offset, ImDrawTextFlags flags)
|
static ImVec2 InputTextCalcTextSize(ImGuiContext* ctx, const char* text_begin, const char* text_end_display, const char* text_end, const char** out_remaining, ImVec2* out_offset, ImDrawTextFlags flags)
|
||||||
{
|
{
|
||||||
ImGuiContext& g = *ctx;
|
ImGuiContext& g = *ctx;
|
||||||
|
|
@ -4560,6 +4520,97 @@ void ImGui::InputTextDeactivateHook(ImGuiID id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int* ImLowerBound(int* in_begin, int* in_end, int v)
|
||||||
|
{
|
||||||
|
int* in_p = in_begin;
|
||||||
|
for (size_t count = (size_t)(in_end - in_p); count > 0; )
|
||||||
|
{
|
||||||
|
size_t count2 = count >> 1;
|
||||||
|
int* mid = in_p + count2;
|
||||||
|
if (*mid < v)
|
||||||
|
{
|
||||||
|
in_p = ++mid;
|
||||||
|
count -= count2 + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count = count2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return in_p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME-WORDWRAP: Bundle some of this into ImGuiTextIndex and/or extract as a different tool?
|
||||||
|
// 'max_output_buffer_size' happens to be a meaningful optimization to avoid writing the full line_index when not necessarily needed (e.g. very large buffer, scrolled up, inactive)
|
||||||
|
static int InputTextLineIndexBuild(ImGuiInputTextFlags flags, ImGuiTextIndex* line_index, const char* buf, const char* buf_end, float wrap_width, int max_output_buffer_size, const char** out_buf_end)
|
||||||
|
{
|
||||||
|
ImGuiContext& g = *GImGui;
|
||||||
|
int size = 0;
|
||||||
|
const char* s;
|
||||||
|
if (flags & ImGuiInputTextFlags_WordWrap)
|
||||||
|
{
|
||||||
|
for (s = buf; s < buf_end; s = (*s == '\n') ? s + 1 : s)
|
||||||
|
{
|
||||||
|
if (size++ <= max_output_buffer_size)
|
||||||
|
line_index->Offsets.push_back((int)(s - buf));
|
||||||
|
s = ImFontCalcWordWrapPositionEx(g.Font, g.FontSize, s, buf_end, wrap_width, ImDrawTextFlags_WrapKeepBlanks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (buf_end != NULL)
|
||||||
|
{
|
||||||
|
for (s = buf; s < buf_end; s = s ? s + 1 : buf_end)
|
||||||
|
{
|
||||||
|
if (size++ <= max_output_buffer_size)
|
||||||
|
line_index->Offsets.push_back((int)(s - buf));
|
||||||
|
s = (const char*)ImMemchr(s, '\n', buf_end - s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const char* s_eol;
|
||||||
|
for (s = buf; ; s = s_eol + 1)
|
||||||
|
{
|
||||||
|
if (size++ <= max_output_buffer_size)
|
||||||
|
line_index->Offsets.push_back((int)(s - buf));
|
||||||
|
if ((s_eol = strchr(s, '\n')) != NULL)
|
||||||
|
continue;
|
||||||
|
s += strlen(s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (out_buf_end != NULL)
|
||||||
|
*out_buf_end = buf_end = s;
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
line_index->Offsets.push_back(0);
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
if (buf_end > buf && buf_end[-1] == '\n' && size <= max_output_buffer_size)
|
||||||
|
{
|
||||||
|
line_index->Offsets.push_back((int)(buf_end - buf));
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ImVec2 InputTextLineIndexGetPosOffset(ImGuiContext& g, ImGuiInputTextState* state, ImGuiTextIndex* line_index, const char* buf, const char* buf_end, int cursor_n)
|
||||||
|
{
|
||||||
|
const char* cursor_ptr = buf + cursor_n;
|
||||||
|
int* it_begin = line_index->Offsets.begin();
|
||||||
|
int* it_end = line_index->Offsets.end();
|
||||||
|
const int* it = ImLowerBound(it_begin, it_end, cursor_n);
|
||||||
|
if (it > it_begin)
|
||||||
|
if (it == it_end || *it != cursor_n || (cursor_ptr[-1] != '\n' && cursor_ptr[-1] != 0 && state != NULL && state->LastMoveDirectionLR == ImGuiDir_Right))
|
||||||
|
it--;
|
||||||
|
|
||||||
|
const int line_no = (it == it_begin) ? 0 : line_index->Offsets.index_from_ptr(it);
|
||||||
|
const char* line_start = line_index->get_line_begin(buf, line_no);
|
||||||
|
ImVec2 offset;
|
||||||
|
offset.x = InputTextCalcTextSize(&g, line_start, cursor_ptr, buf_end, NULL, NULL, ImDrawTextFlags_WrapKeepBlanks).x;
|
||||||
|
offset.y = (line_no + 1) * g.FontSize;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
// Edit a string of text
|
// Edit a string of text
|
||||||
// - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!".
|
// - buf_size account for the zero-terminator, so a buf_size of 6 can hold "Hello" but not "Hello!".
|
||||||
// This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match
|
// This is so we can easily call InputText() on static arrays using ARRAYSIZE() and to match
|
||||||
|
|
@ -5332,15 +5383,42 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||||
buf_display = hint;
|
buf_display = hint;
|
||||||
buf_display_end = hint + ImStrlen(hint);
|
buf_display_end = hint + ImStrlen(hint);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (render_cursor || render_selection || g.ActiveId == id)
|
||||||
|
buf_display_end = buf_display + state->TextLen; //-V595
|
||||||
|
else if (is_multiline && !is_wordwrap)
|
||||||
|
buf_display_end = NULL; // Inactive multi-line: end of buffer will be output by InputTextLineIndexBuild() special strchr() path.
|
||||||
|
else
|
||||||
|
buf_display_end = buf_display + ImStrlen(buf_display);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate visibility
|
||||||
|
int line_visible_n0 = 0, line_visible_n1 = 1;
|
||||||
|
if (is_multiline)
|
||||||
|
CalcClipRectVisibleItemsY(clip_rect, draw_pos, g.FontSize, &line_visible_n0, &line_visible_n1);
|
||||||
|
|
||||||
|
// Build line index for easy data access (makes code below simpler and faster)
|
||||||
|
ImGuiTextIndex* line_index = &g.InputTextLineIndex;
|
||||||
|
line_index->Offsets.resize(0);
|
||||||
|
int line_count = 1;
|
||||||
|
if (is_multiline)
|
||||||
|
line_count = InputTextLineIndexBuild(flags, line_index, buf_display, buf_display_end, wrap_width, (render_cursor && state && state->CursorFollow) ? INT_MAX : line_visible_n1 + 1, buf_display_end ? NULL : &buf_display_end);
|
||||||
|
line_index->EndOffset = (int)(buf_display_end - buf_display);
|
||||||
|
line_visible_n1 = ImMin(line_visible_n1, line_count);
|
||||||
|
|
||||||
|
// Store text height (we don't need width)
|
||||||
|
text_size = ImVec2(inner_size.x, line_count * g.FontSize);
|
||||||
|
//GetForegroundDrawList()->AddRect(draw_pos + ImVec2(0, line_visible_n0 * g.FontSize), draw_pos + ImVec2(frame_size.x, line_visible_n1 * g.FontSize), IM_COL32(255, 0, 0, 255));
|
||||||
|
|
||||||
|
// Calculate blinking cursor position
|
||||||
|
const ImVec2 cursor_offset = render_cursor && state ? InputTextLineIndexGetPosOffset(g, state, line_index, buf_display, buf_display_end, state->Stb->cursor) : ImVec2(0.0f, 0.0f);
|
||||||
|
ImVec2 draw_scroll;
|
||||||
|
|
||||||
// Render text. We currently only render selection when the widget is active or while scrolling.
|
// Render text. We currently only render selection when the widget is active or while scrolling.
|
||||||
// FIXME: This is one of the messiest piece of the whole codebase.
|
const ImU32 text_col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text);
|
||||||
if (render_cursor || render_selection)
|
if (render_cursor || render_selection)
|
||||||
{
|
{
|
||||||
IM_ASSERT(state != NULL);
|
|
||||||
if (!is_displaying_hint)
|
|
||||||
buf_display_end = buf_display + state->TextLen;
|
|
||||||
|
|
||||||
// Render text (with cursor and selection)
|
// Render text (with cursor and selection)
|
||||||
// This is going to be messy. We need to:
|
// This is going to be messy. We need to:
|
||||||
// - Display the text (this alone can be more easily clipped)
|
// - Display the text (this alone can be more easily clipped)
|
||||||
|
|
@ -5348,85 +5426,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||||
// - Measure text height (for scrollbar)
|
// - Measure text height (for scrollbar)
|
||||||
// We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)
|
// We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)
|
||||||
// FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8.
|
// FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8.
|
||||||
const char* text_begin = buf_display;
|
IM_ASSERT(state != NULL);
|
||||||
const char* text_end = text_begin + state->TextLen;
|
state->LineCount = line_count;
|
||||||
ImVec2 cursor_offset;
|
|
||||||
float select_start_offset_y = 0.0f; // Offset of beginning of non-wrapped line for selection.
|
|
||||||
|
|
||||||
{
|
|
||||||
// Find lines numbers straddling cursor and selection min position
|
|
||||||
int cursor_line_no = render_cursor ? -1 : -1000;
|
|
||||||
int selmin_line_no = render_selection ? -1 : -1000;
|
|
||||||
const char* cursor_ptr = render_cursor ? text_begin + state->Stb->cursor : NULL;
|
|
||||||
const char* selmin_ptr = render_selection ? text_begin + ImMin(state->Stb->select_start, state->Stb->select_end) : NULL;
|
|
||||||
const char* cursor_line_start = NULL;
|
|
||||||
const char* selmin_line_start = NULL;
|
|
||||||
bool cursor_straddle_word_wrap = false;
|
|
||||||
|
|
||||||
// Count lines and find line number for cursor and selection ends
|
|
||||||
// FIXME: Switch to zero-based index to reduce confusion.
|
|
||||||
int line_count = 1;
|
|
||||||
if (is_multiline)
|
|
||||||
{
|
|
||||||
if (!is_wordwrap)
|
|
||||||
{
|
|
||||||
for (const char* s = text_begin; (s = (const char*)ImMemchr(s, '\n', (size_t)(text_end - s))) != NULL; s++)
|
|
||||||
{
|
|
||||||
if (cursor_line_no == -1 && s >= cursor_ptr) { cursor_line_no = line_count; }
|
|
||||||
if (selmin_line_no == -1 && s >= selmin_ptr) { selmin_line_no = line_count; }
|
|
||||||
line_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool is_start_of_non_wrapped_line = true;
|
|
||||||
int line_count_for_non_wrapped_line = 1;
|
|
||||||
for (const char* s = text_begin; s < text_end; s = (*s == '\n') ? s + 1 : s)
|
|
||||||
{
|
|
||||||
const char* s_eol = ImFontCalcWordWrapPositionEx(g.Font, g.FontSize, s, text_end, wrap_width, ImDrawTextFlags_WrapKeepBlanks);
|
|
||||||
const char* s_prev = s;
|
|
||||||
s = s_eol;
|
|
||||||
if (cursor_line_no == -1 && s >= cursor_ptr) { cursor_line_start = s_prev; cursor_line_no = line_count; }
|
|
||||||
if (selmin_line_no == -1 && s >= selmin_ptr) { selmin_line_start = s_prev; selmin_line_no = line_count_for_non_wrapped_line; }
|
|
||||||
if (s == cursor_ptr && *cursor_ptr != '\n' && *cursor_ptr != 0)
|
|
||||||
cursor_straddle_word_wrap = true;
|
|
||||||
is_start_of_non_wrapped_line = (*s == '\n');
|
|
||||||
line_count++;
|
|
||||||
if (is_start_of_non_wrapped_line)
|
|
||||||
line_count_for_non_wrapped_line = line_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//IMGUI_DEBUG_LOG("%d\n", selmin_line_no);
|
|
||||||
}
|
|
||||||
if (cursor_line_no == -1)
|
|
||||||
cursor_line_no = line_count;
|
|
||||||
if (cursor_line_start == NULL)
|
|
||||||
cursor_line_start = ImStrbol(cursor_ptr, text_begin);
|
|
||||||
if (selmin_line_no == -1)
|
|
||||||
selmin_line_no = line_count;
|
|
||||||
if (selmin_line_start == NULL)
|
|
||||||
selmin_line_start = ImStrbol(cursor_ptr, text_begin);
|
|
||||||
|
|
||||||
// Calculate 2d position by finding the beginning of the line and measuring distance
|
|
||||||
if (render_cursor)
|
|
||||||
{
|
|
||||||
cursor_offset.x = InputTextCalcTextSize(&g, cursor_line_start, cursor_ptr, text_end, NULL, NULL, ImDrawTextFlags_WrapKeepBlanks).x;
|
|
||||||
cursor_offset.y = cursor_line_no * g.FontSize;
|
|
||||||
if (is_multiline && cursor_straddle_word_wrap && state->LastMoveDirectionLR == ImGuiDir_Left)
|
|
||||||
cursor_offset = ImVec2(0.0f, cursor_offset.y + g.FontSize);
|
|
||||||
}
|
|
||||||
if (selmin_line_no >= 0)
|
|
||||||
select_start_offset_y = selmin_line_no * g.FontSize;
|
|
||||||
|
|
||||||
// Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224)
|
|
||||||
if (is_multiline)
|
|
||||||
{
|
|
||||||
if (is_wordwrap && text_end > text_begin && text_end[-1] != '\n')
|
|
||||||
line_count--;
|
|
||||||
text_size = ImVec2(inner_size.x, line_count * g.FontSize);
|
|
||||||
}
|
|
||||||
state->LineCount = line_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scroll
|
// Scroll
|
||||||
float new_scroll_y = scroll_y;
|
float new_scroll_y = scroll_y;
|
||||||
|
|
@ -5444,7 +5445,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
state->Scroll.y = 0.0f;
|
state->Scroll.x = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertical scroll
|
// Vertical scroll
|
||||||
|
|
@ -5452,7 +5453,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||||
{
|
{
|
||||||
// Test if cursor is vertically visible
|
// Test if cursor is vertically visible
|
||||||
if (cursor_offset.y - g.FontSize < scroll_y)
|
if (cursor_offset.y - g.FontSize < scroll_y)
|
||||||
new_scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
|
new_scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
|
||||||
else if (cursor_offset.y - (inner_size.y - style.FramePadding.y * 2.0f) >= scroll_y)
|
else if (cursor_offset.y - (inner_size.y - style.FramePadding.y * 2.0f) >= scroll_y)
|
||||||
new_scroll_y = cursor_offset.y - inner_size.y + style.FramePadding.y * 2.0f;
|
new_scroll_y = cursor_offset.y - inner_size.y + style.FramePadding.y * 2.0f;
|
||||||
}
|
}
|
||||||
|
|
@ -5471,103 +5472,86 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||||
scroll_y = ImClamp(new_scroll_y, 0.0f, scroll_max_y);
|
scroll_y = ImClamp(new_scroll_y, 0.0f, scroll_max_y);
|
||||||
draw_pos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag
|
draw_pos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag
|
||||||
draw_window->Scroll.y = scroll_y;
|
draw_window->Scroll.y = scroll_y;
|
||||||
|
CalcClipRectVisibleItemsY(clip_rect, draw_pos, g.FontSize, &line_visible_n0, &line_visible_n1);
|
||||||
|
line_visible_n1 = ImMin(line_visible_n1, line_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw selection
|
// Draw selection
|
||||||
const ImVec2 draw_scroll = ImVec2(state->Scroll.x, 0.0f);
|
draw_scroll.x = state->Scroll.x;
|
||||||
if (render_selection)
|
if (render_selection)
|
||||||
{
|
{
|
||||||
const char* text_selected_begin = text_begin + ImMin(state->Stb->select_start, state->Stb->select_end);
|
const ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true here, we are leaving the transparent one for tests.
|
||||||
const char* text_selected_end = text_begin + ImMax(state->Stb->select_start, state->Stb->select_end);
|
const float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection.
|
||||||
|
const float bg_offy_dn = is_multiline ? 0.0f : 2.0f;
|
||||||
|
const float bg_eol_width = IM_TRUNC(g.FontBaked->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines
|
||||||
|
|
||||||
ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f); // FIXME: current code flow mandate that render_cursor is always true here, we are leaving the transparent one for tests.
|
const char* text_selected_begin = buf_display + ImMin(state->Stb->select_start, state->Stb->select_end);
|
||||||
float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection.
|
const char* text_selected_end = buf_display + ImMax(state->Stb->select_start, state->Stb->select_end);
|
||||||
float bg_offy_dn = is_multiline ? 0.0f : 2.0f;
|
for (int line_n = line_visible_n0; line_n < line_visible_n1; line_n++)
|
||||||
float bg_min_width = IM_TRUNC(g.FontBaked->GetCharAdvance((ImWchar)' ') * 0.50f); // So we can see selected empty lines
|
|
||||||
ImVec2 rect_pos = draw_pos - draw_scroll;
|
|
||||||
rect_pos.y += select_start_offset_y;
|
|
||||||
for (const char* p = ImStrbol(text_selected_begin, text_begin); p < text_selected_end; rect_pos.y += g.FontSize)
|
|
||||||
{
|
{
|
||||||
if (rect_pos.y > clip_rect.Max.y + g.FontSize)
|
const char* p = line_index->get_line_begin(buf_display, line_n);
|
||||||
break;
|
const char* p_eol = line_index->get_line_end(buf_display, line_n);
|
||||||
const char* p_eol = is_wordwrap ? ImFontCalcWordWrapPositionEx(g.Font, g.FontSize, p, text_end, wrap_width, ImDrawTextFlags_WrapKeepBlanks) : (const char*)ImMemchr((void*)p, '\n', text_selected_end - p);
|
const bool p_eol_is_wrap = (p_eol < buf_display_end && *p_eol != '\n');
|
||||||
if (p_eol == NULL)
|
if (p_eol_is_wrap)
|
||||||
p_eol = text_selected_end;
|
p_eol++;
|
||||||
const char* p_next = is_wordwrap ? (*p_eol == '\n' ? p_eol + 1 : p_eol) : (p_eol + 1);
|
const char* line_selected_begin = (text_selected_begin > p) ? text_selected_begin : p;
|
||||||
if (rect_pos.y >= clip_rect.Min.y)
|
const char* line_selected_end = (text_selected_end < p_eol) ? text_selected_end : p_eol;
|
||||||
{
|
|
||||||
const char* line_selected_begin = (text_selected_begin > p) ? text_selected_begin : p;
|
|
||||||
const char* line_selected_end = (text_selected_end < p_eol) ? text_selected_end : p_eol;
|
|
||||||
if ((*p_eol == '\n' && text_selected_begin <= p_eol) || (text_selected_begin < p_eol))
|
|
||||||
{
|
|
||||||
ImVec2 rect_offset = CalcTextSize(p, line_selected_begin);
|
|
||||||
ImVec2 rect_size = CalcTextSize(line_selected_begin, line_selected_end);
|
|
||||||
rect_size.x = ImMax(rect_size.x, bg_min_width); // So we can see selected empty lines
|
|
||||||
ImRect rect(rect_pos + ImVec2(rect_offset.x, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_offset.x + rect_size.x, bg_offy_dn));
|
|
||||||
rect.ClipWith(clip_rect);
|
|
||||||
if (rect.Overlaps(clip_rect))
|
|
||||||
draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p = p_next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We test for 'buf_display_max_length' as a way to avoid some pathological cases (e.g. single-line 1 MB string) which would make ImDrawList crash.
|
float rect_width = 0.0f;
|
||||||
// FIXME-OPT: Multiline could submit a smaller amount of contents to AddText() since we already iterated through it.
|
if (line_selected_begin < line_selected_end)
|
||||||
if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length)
|
rect_width += CalcTextSize(line_selected_begin, line_selected_end).x;
|
||||||
{
|
if (text_selected_begin <= p_eol && text_selected_end > p_eol && !p_eol_is_wrap)
|
||||||
ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text);
|
rect_width += bg_eol_width; // So we can see selected empty lines
|
||||||
if (col & IM_COL32_A_MASK)
|
if (rect_width == 0.0f)
|
||||||
g.Font->RenderText(draw_window->DrawList, g.FontSize, draw_pos - draw_scroll, col, clip_rect.AsVec4(), buf_display, buf_display_end, wrap_width, ImDrawTextFlags_WrapKeepBlanks);
|
continue;
|
||||||
//draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, wrap_width, is_multiline ? NULL : &clip_rect.AsVec4());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw blinking cursor
|
ImRect rect;
|
||||||
if (render_cursor)
|
rect.Min.x = draw_pos.x - draw_scroll.x + CalcTextSize(p, line_selected_begin).x;
|
||||||
{
|
rect.Min.y = draw_pos.y - draw_scroll.y + line_n * g.FontSize;
|
||||||
state->CursorAnim += io.DeltaTime;
|
rect.Max.x = rect.Min.x + rect_width;
|
||||||
bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f;
|
rect.Max.y = rect.Min.y + bg_offy_dn + g.FontSize;
|
||||||
ImVec2 cursor_screen_pos = ImTrunc(draw_pos + cursor_offset - draw_scroll);
|
rect.Min.y -= bg_offy_up;
|
||||||
ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f);
|
rect.ClipWith(clip_rect);
|
||||||
if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect))
|
draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color);
|
||||||
draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_InputTextCursor), 1.0f); // FIXME-DPI: Cursor thickness (#7031)
|
|
||||||
|
|
||||||
// Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.)
|
|
||||||
// This is required for some backends (SDL3) to start emitting character/text inputs.
|
|
||||||
// As per #6341, make sure we don't set that on the deactivating frame.
|
|
||||||
if (!is_readonly && g.ActiveId == id)
|
|
||||||
{
|
|
||||||
ImGuiPlatformImeData* ime_data = &g.PlatformImeData; // (this is a public struct, passed to io.Platform_SetImeDataFn() handler)
|
|
||||||
ime_data->WantVisible = true;
|
|
||||||
ime_data->WantTextInput = true;
|
|
||||||
ime_data->InputPos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize);
|
|
||||||
ime_data->InputLineHeight = g.FontSize;
|
|
||||||
ime_data->ViewportId = window->Viewport->ID;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// Find render position for right alignment (single-line only)
|
||||||
|
if (g.ActiveId != id && flags & ImGuiInputTextFlags_ElideLeft)
|
||||||
|
draw_pos.x = ImMin(draw_pos.x, frame_bb.Max.x - CalcTextSize(buf_display, NULL).x - style.FramePadding.x);
|
||||||
|
//draw_scroll.x = state->Scroll.x; // Preserve scroll when inactive?
|
||||||
|
|
||||||
|
// Render text
|
||||||
|
if ((is_multiline || (buf_display_end - buf_display) < buf_display_max_length) && (text_col & IM_COL32_A_MASK) && (line_visible_n0 < line_visible_n1))
|
||||||
|
g.Font->RenderText(draw_window->DrawList, g.FontSize,
|
||||||
|
draw_pos - draw_scroll + ImVec2(0.0f, line_visible_n0 * g.FontSize),
|
||||||
|
text_col, clip_rect.AsVec4(),
|
||||||
|
line_index->get_line_begin(buf_display, line_visible_n0),
|
||||||
|
line_index->get_line_end(buf_display, line_visible_n1 - 1),
|
||||||
|
wrap_width, ImDrawTextFlags_WrapKeepBlanks);
|
||||||
|
|
||||||
|
// Render blinking cursor
|
||||||
|
if (render_cursor)
|
||||||
{
|
{
|
||||||
// Render text only (no selection, no cursor)
|
state->CursorAnim += io.DeltaTime;
|
||||||
if (is_multiline)
|
bool cursor_is_visible = (!g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f;
|
||||||
text_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(&g, buf_display, &buf_display_end, wrap_width) * g.FontSize); // We don't need width
|
ImVec2 cursor_screen_pos = ImTrunc(draw_pos + cursor_offset - draw_scroll);
|
||||||
else if (!is_displaying_hint && g.ActiveId == id)
|
ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f);
|
||||||
buf_display_end = buf_display + state->TextLen;
|
if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect))
|
||||||
else if (!is_displaying_hint)
|
draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_InputTextCursor), 1.0f); // FIXME-DPI: Cursor thickness (#7031)
|
||||||
buf_display_end = buf_display + ImStrlen(buf_display);
|
|
||||||
|
|
||||||
if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length)
|
// Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.)
|
||||||
|
// This is required for some backends (SDL3) to start emitting character/text inputs.
|
||||||
|
// As per #6341, make sure we don't set that on the deactivating frame.
|
||||||
|
if (!is_readonly && g.ActiveId == id)
|
||||||
{
|
{
|
||||||
// Find render position for right alignment
|
ImGuiPlatformImeData* ime_data = &g.PlatformImeData; // (this is a public struct, passed to io.Platform_SetImeDataFn() handler)
|
||||||
if (flags & ImGuiInputTextFlags_ElideLeft)
|
ime_data->WantVisible = true;
|
||||||
draw_pos.x = ImMin(draw_pos.x, frame_bb.Max.x - CalcTextSize(buf_display, NULL).x - style.FramePadding.x);
|
ime_data->WantTextInput = true;
|
||||||
|
ime_data->InputPos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y - g.FontSize);
|
||||||
const ImVec2 draw_scroll = /*state ? ImVec2(state->Scroll.x, 0.0f) :*/ ImVec2(0.0f, 0.0f); // Preserve scroll when inactive?
|
ime_data->InputLineHeight = g.FontSize;
|
||||||
ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text);
|
ime_data->ViewportId = window->Viewport->ID;
|
||||||
if (col & IM_COL32_A_MASK)
|
|
||||||
g.Font->RenderText(draw_window->DrawList, g.FontSize, draw_pos - draw_scroll, col, clip_rect.AsVec4(), buf_display, buf_display_end, wrap_width, ImDrawTextFlags_WrapKeepBlanks);
|
|
||||||
//draw_window->DrawList->AddText(g.Font, g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, wrap_width, is_multiline ? NULL : &clip_rect.AsVec4());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -7371,7 +7355,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
||||||
// - (2) usage will fail with clipped items
|
// - (2) usage will fail with clipped items
|
||||||
// The multi-select API aim to fix those issues, e.g. may be replaced with a BeginSelection() API.
|
// The multi-select API aim to fix those issues, e.g. may be replaced with a BeginSelection() API.
|
||||||
if ((flags & ImGuiSelectableFlags_SelectOnNav) && g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == g.CurrentFocusScopeId)
|
if ((flags & ImGuiSelectableFlags_SelectOnNav) && g.NavJustMovedToId != 0 && g.NavJustMovedToFocusScopeId == g.CurrentFocusScopeId)
|
||||||
if (g.NavJustMovedToId == id)
|
if (g.NavJustMovedToId == id && (g.NavJustMovedToKeyMods & ImGuiMod_Ctrl) == 0)
|
||||||
selected = pressed = auto_selected = true;
|
selected = pressed = auto_selected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -7424,8 +7408,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
||||||
|
|
||||||
// Automatically close popups
|
// Automatically close popups
|
||||||
if (pressed && !auto_selected && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && (g.LastItemData.ItemFlags & ImGuiItemFlags_AutoClosePopups))
|
if (pressed && !auto_selected && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && (g.LastItemData.ItemFlags & ImGuiItemFlags_AutoClosePopups))
|
||||||
if (!(flags & ImGuiSelectableFlags_SelectOnNav) || g.NavJustMovedToId != id)
|
CloseCurrentPopup();
|
||||||
CloseCurrentPopup();
|
|
||||||
|
|
||||||
if (disabled_item && !disabled_global)
|
if (disabled_item && !disabled_global)
|
||||||
EndDisabled();
|
EndDisabled();
|
||||||
|
|
|
||||||
|
|
@ -1154,7 +1154,7 @@ retry:
|
||||||
#endif
|
#endif
|
||||||
case STB_TEXTEDIT_K_LINEEND: {
|
case STB_TEXTEDIT_K_LINEEND: {
|
||||||
stb_textedit_clamp(str, state);
|
stb_textedit_clamp(str, state);
|
||||||
stb_textedit_move_to_first(state);
|
stb_textedit_move_to_last(str, state);
|
||||||
state->cursor = STB_TEXTEDIT_MOVELINEEND(str, state, state->cursor);
|
state->cursor = STB_TEXTEDIT_MOVELINEEND(str, state, state->cursor);
|
||||||
state->has_preferred_x = 0;
|
state->has_preferred_x = 0;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue