From 6881d065b8bb0fc4949c2a65d818f61c1e3c6903 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 30 Apr 2018 15:59:59 +0200 Subject: [PATCH] DragFloat/SliderFloat internal InputScalar trip trailing decoration off the format string when presenting an edit box to the user. (#648) --- CHANGELOG.txt | 2 +- imgui.cpp | 47 ++++++++++++++++++++++++++++++++--------------- imgui_internal.h | 2 +- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 57134352..a1de9d64 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -60,7 +60,7 @@ Other Changes: - InputFloat,InputFloat2,InputFloat3,InputFloat4: Added variations taking a more flexible and consistent optional "const char* format" parameter instead of "int decimal_precision". This allow using custom formats to display values in scientific notation, and is generally more consistent with other API. Obsoleted functions using the optional "int decimal_precision" parameter. (#648) - DragFloat, DragInt: Cancel mouse tweak when current value is initially past the min/max boundaries and mouse is pushing in the same direction (keyboard/gamepad version already did this). -- DragFloat, SliderFloat: Fix to allow input of scientific notation numbers when using CTRL+Click to input the value. (~#648, #1011) +- DragFloat, SliderFloat: Fixes to allow input of scientific notation numbers when using CTRL+Click to input the value. (~#648, #1011) - Style: Changed default style.DisplaySafeAreaPadding values from (4,4) to (3,3) so it is smaller than FramePadding and has no effect on main menu bar on a computer. (#1439) - Misc: Added IMGUI_CHECKVERSION() macro to compare version string and data structure sizes in order to catch issues with mismatching compilation unit settings. (#1695, #1769) - Demo: Fixed Overlay: Added a context menu item to enable freely moving the window. diff --git a/imgui.cpp b/imgui.cpp index 78734d7c..1efce826 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8569,33 +8569,50 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const c SetHoveredID(0); FocusableItemUnregister(window); - char buf[32]; - format = ParseFormatSkipLeadingText(format); - DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, data_ptr, format); + char fmt_buf[32]; + char data_buf[32]; + format = ParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf)); + DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, data_ptr, format); ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); - bool text_value_changed = InputTextEx(label, buf, IM_ARRAYSIZE(buf), bb.GetSize(), flags); + bool value_changed = InputTextEx(label, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags); if (g.ScalarAsInputTextId == 0) // First frame we started displaying the InputText widget { - IM_ASSERT(g.ActiveId == id); // InputText ID expected to match the Slider ID (else we'd need to store them both, which is also possible) + IM_ASSERT(g.ActiveId == id); // InputText ID expected to match the Slider ID g.ScalarAsInputTextId = g.ActiveId; SetHoveredID(id); } - if (text_value_changed) - return DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr, NULL); + if (value_changed) + return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialText.begin(), data_type, data_ptr, NULL); return false; } -const char* ImGui::ParseFormatSkipLeadingText(const char* fmt) +// Extract the format out of a format string with leading or trailing decorations +// fmt = "blah blah" -> return fmt +// fmt = "%.3f" -> return fmt +// fmt = "hello %.3f" -> return fmt + 6 +// fmt = "%.3f hello" -> return buf written with "%.3f" +const char* ImGui::ParseFormatTrimDecorations(const char* fmt, char* buf, int buf_size) { - if (fmt[0] == '%') - return fmt; - while (char c = fmt[0]) + // We don't use strchr() because our strings are usually very short and often start with '%' + const char* fmt_start = fmt; + while (char c = *fmt++) { - if (c == '%' && fmt[1] != '%') - return fmt; - fmt++; + if (c != '%') continue; // Looking for % + if (fmt[0] == '%') { fmt++; continue; } // Ignore "%%" + fmt_start = fmt - 1; + while ((c = *fmt++) != 0) + { + if (c >= 'A' && c <= 'Z' && (c != 'L')) // L is a type modifier, other letters qualify as types aka end of the format + break; + if (c >= 'a' && c <= 'z' && (c != 'h' && c != 'j' && c != 'l' && c != 't' && c != 'w' && c != 'z')) // h/j/l/t/w/z are type modifiers, other letters qualify as types aka end of the format + break; + } + if (fmt[0] == 0) // If we only have leading decoration, we don't need to copy the data. + return fmt_start; + ImStrncpy(buf, fmt_start, ImMin((int)(fmt + 1 - fmt_start), buf_size)); + return buf; } - return fmt; + return fmt_start; } // Parse display precision back from the display format string diff --git a/imgui_internal.h b/imgui_internal.h index 548d7729..8e7f935b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1119,7 +1119,7 @@ namespace ImGui IMGUI_API void PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size); - IMGUI_API const char* ParseFormatSkipLeadingText(const char* format); + IMGUI_API const char* ParseFormatTrimDecorations(const char* format, char* buf, int buf_size); IMGUI_API int ParseFormatPrecision(const char* format, int default_value); IMGUI_API float RoundScalar(float value, int decimal_precision);