From a62f195e8374ce49d6c2f881056fe487843d0ad0 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 May 2018 11:57:51 +0200 Subject: [PATCH 01/22] Internals: Renamed IsCharIsSpace() to IsCharIsBlank*() to match standard terminlogy and added ascii/u16 variations. --- imgui.cpp | 10 +++++----- imgui_draw.cpp | 6 +++--- imgui_internal.h | 3 ++- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 8f727b04b..871c8e769 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8490,7 +8490,7 @@ static size_t GDataTypeSize[ImGuiDataType_COUNT] = // NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess.. static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* scalar_format) { - while (ImCharIsSpace((unsigned int)*buf)) + while (ImCharIsBlankA(*buf)) buf++; // We don't support '-' op because it would conflict with inputing negative value. @@ -8499,7 +8499,7 @@ static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_b if (op == '+' || op == '*' || op == '/') { buf++; - while (ImCharIsSpace((unsigned int)*buf)) + while (ImCharIsBlankA(*buf)) buf++; } else @@ -9771,7 +9771,7 @@ static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* ob r->num_chars = (int)(text_remaining - (text + line_start_idx)); } -static bool is_separator(unsigned int c) { return ImCharIsSpace(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; } +static bool is_separator(unsigned int c) { return ImCharIsBlankW(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; } static int is_word_boundary_from_right(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (is_separator( obj->Text[idx-1] ) && !is_separator( obj->Text[idx] ) ) : 1; } static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; } #ifdef __APPLE__ // FIXME: Move setting to IO structure @@ -9925,7 +9925,7 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f *p_char = (c += (unsigned int)('A'-'a')); if (flags & ImGuiInputTextFlags_CharsNoBlank) - if (ImCharIsSpace(c)) + if (ImCharIsBlankW(c)) return false; } @@ -11826,7 +11826,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag { value_changed = true; char* p = buf; - while (*p == '#' || ImCharIsSpace((unsigned int)*p)) + while (*p == '#' || ImCharIsBlankA(*p)) p++; i[0] = i[1] = i[2] = i[3] = 0; if (alpha) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ea822146e..ae44aab41 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2351,7 +2351,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c } const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX); - if (ImCharIsSpace(c)) + if (ImCharIsBlankW(c)) { if (inside_word) { @@ -2434,7 +2434,7 @@ ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, cons while (s < text_end) { const char c = *s; - if (ImCharIsSpace((unsigned int)c)) { s++; } else if (c == '\n') { s++; break; } else { break; } + if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; } } continue; } @@ -2559,7 +2559,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col while (s < text_end) { const char c = *s; - if (ImCharIsSpace((unsigned int)c)) { s++; } else if (c == '\n') { s++; break; } else { break; } + if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; } } continue; } diff --git a/imgui_internal.h b/imgui_internal.h index 411db886e..a9f100845 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -98,7 +98,8 @@ IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, cons IMGUI_API ImU32 ImHash(const void* data, int data_size, ImU32 seed = 0); // Pass data_size==0 for zero-terminated strings IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, int* out_file_size = NULL, int padding_bytes = 0); IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode); -static inline bool ImCharIsSpace(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } +static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } +static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; } static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; } From 10e3f17235659d31eef02ed767cd5c5b33af8097 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 May 2018 11:59:20 +0200 Subject: [PATCH 02/22] DragFloat/SliderFloat internal InputScalar trim leading/trailing spaces emitted from the format string when presenting an edit box to the user. (#648) Follow up to 6881d065b8bb0fc4949c2a65d818f61c1e3c6903 --- imgui.cpp | 17 +++++++++++++++++ imgui_internal.h | 1 + 2 files changed, 18 insertions(+) diff --git a/imgui.cpp b/imgui.cpp index 871c8e769..467cda768 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1072,6 +1072,22 @@ const char* ImStristr(const char* haystack, const char* haystack_end, const char return NULL; } +// Trim str by offsetting contents when there's leading data + writing a \0 at the trailing position. We use this in situation where the cost is negligible. +void ImStrTrimBlanks(char* buf) +{ + char* p = buf; + while (p[0] == ' ' || p[0] == '\t') // Leading blanks + p++; + char* p_start = p; + while (*p != 0) // Find end of string + p++; + while (p > p_start && (p[-1] == ' ' || p[-1] == '\t')) // Trailing blanks + p--; + if (p_start != buf) // Copy memory if we had leading blanks + memmove(buf, p_start, p - p_start); + buf[p - p_start] = 0; // Zero terminate +} + static const char* ImAtoi(const char* src, int* output) { int negative = 0; @@ -8594,6 +8610,7 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const c 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); + ImStrTrimBlanks(data_buf); ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); 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 diff --git a/imgui_internal.h b/imgui_internal.h index a9f100845..44d1434fc 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -118,6 +118,7 @@ IMGUI_API const char* ImStrchrRange(const char* str_begin, const char* str_end IMGUI_API int ImStrlenW(const ImWchar* str); IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end); +IMGUI_API void ImStrTrimBlanks(char* str); IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3); IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3); From 8a370f64912b1cdb56d0dfcd9bd535adc9075040 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 May 2018 19:46:57 +0200 Subject: [PATCH 03/22] SliderFloat: Fixed grab size and steps with %g format. (#642, #1301) --- imgui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index 467cda768..d9e2b4651 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8689,6 +8689,8 @@ int ImGui::ParseFormatPrecision(const char* fmt, int default_precision) static float GetMinimumStepAtDecimalPrecision(int decimal_precision) { static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f }; + if (decimal_precision < 0) + return FLT_MIN; return (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : powf(10.0f, (float)-decimal_precision); } @@ -8737,7 +8739,7 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v const bool is_non_linear = (power < 1.0f-0.00001f) || (power > 1.0f+0.00001f); const bool is_horizontal = (flags & ImGuiSliderFlags_Vertical) == 0; - const bool is_decimal = ParseFormatPrecision(format, 3) > 0; + const bool is_decimal = ParseFormatPrecision(format, 3) != 0; const float grab_padding = 2.0f; const float slider_sz = is_horizontal ? (frame_bb.GetWidth() - grab_padding * 2.0f) : (frame_bb.GetHeight() - grab_padding * 2.0f); From d9fa1f869ef0cbcd359ed1596bc26310ba64087a Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 May 2018 12:50:34 +0200 Subject: [PATCH 04/22] Comments about using "power curves". Demo tweaks. (#648) --- imgui.cpp | 8 ++++---- imgui.h | 2 +- imgui_demo.cpp | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index d9e2b4651..30201d9ff 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8752,7 +8752,7 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v const float slider_usable_pos_min = (is_horizontal ? frame_bb.Min.x : frame_bb.Min.y) + grab_padding + grab_sz*0.5f; const float slider_usable_pos_max = (is_horizontal ? frame_bb.Max.x : frame_bb.Max.y) - grab_padding - grab_sz*0.5f; - // For logarithmic sliders that cross over sign boundary we want the exponential increase to be symmetric around 0.0f + // For power curve sliders that cross over sign boundary we want the curve to be symmetric around 0.0f float linear_zero_pos = 0.0f; // 0.0->1.0f if (v_min * v_max < 0.0f) { @@ -8827,7 +8827,7 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v float new_value; if (is_non_linear) { - // Account for logarithmic scale on both sides of the zero + // Account for power curve scale on both sides of the zero if (clicked_t < linear_zero_pos) { // Negative: rescale to the negative range before powering @@ -8878,11 +8878,11 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v return value_changed; } -// Use power!=1.0 for logarithmic sliders. // Adjust format to decorate the value with a prefix or a suffix. // "%.3f" 1.234 // "%5.2f secs" 01.23 secs // "Gold: %.0f" Gold: 1 +// Use power != 1.0f for non-linear sliders. bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power) { ImGuiWindow* window = GetCurrentWindow(); @@ -9159,7 +9159,7 @@ bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_s { if (fabsf(power - 1.0f) > 0.001f) { - // Logarithmic curve on both side of 0.0 + // Power curve on both side of 0.0 float v0_abs = v_cur >= 0.0f ? v_cur : -v_cur; float v0_sign = v_cur >= 0.0f ? 1.0f : -1.0f; float v1 = powf(v0_abs, 1.0f / power) + (adjust_delta * v0_sign); diff --git a/imgui.h b/imgui.h index 0f135c84a..5e49704e3 100644 --- a/imgui.h +++ b/imgui.h @@ -361,7 +361,7 @@ namespace ImGui IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0f, double step_fast = 0.0f, const char* format = "%.6f", ImGuiInputTextFlags extra_flags = 0); // Widgets: Sliders (tip: ctrl+click on a slider to input with keyboard. manually input values aren't clamped, can go off-bounds) - IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. Use power!=1.0 for logarithmic sliders + IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. Use power!=1.0 for power curve sliders IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 6717aaaa8..48ca6d98e 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1856,8 +1856,8 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor); ImGui::SameLine(); ShowHelpMarker("Instruct ImGui to render a mouse cursor for you in software. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something)."); - ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); - ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad [beta]", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad); + ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard [beta]", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard); ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos); ImGui::SameLine(); ShowHelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos."); ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange); From 4780ac1ca4035a73afa33b1dc6de4c058d60f410 Mon Sep 17 00:00:00 2001 From: omar Date: Wed, 2 May 2018 14:07:20 +0200 Subject: [PATCH 05/22] Internals: Data types: Added s64, u64 data types. Added support in InputScalar(). Removed internal.h InputScalarEx() to InputScalar(). Removed cheap-relative-operators support in recently added U32 data path, since this is heading toward being legacy code. + Fixed InputDouble parsing code. (#1011, #320, #708) --- imgui.cpp | 120 +++++++++++++++++++++++++++-------------------- imgui.h | 14 ++++-- imgui_demo.cpp | 4 +- imgui_internal.h | 8 ++-- 4 files changed, 86 insertions(+), 60 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 30201d9ff..811aa5fe9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8459,8 +8459,10 @@ void ImGui::BulletText(const char* fmt, ...) static inline int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* data_ptr, const char* format) { - if (data_type == ImGuiDataType_Int32 || data_type == ImGuiDataType_Uint32) - return ImFormatString(buf, buf_size, format, *(const int*)data_ptr); + if (data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32) // Signedness doesn't matter when pushing the argument + return ImFormatString(buf, buf_size, format, *(const ImU32*)data_ptr); + if (data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) // Signedness doesn't matter when pushing the argument + return ImFormatString(buf, buf_size, format, *(const ImU64*)data_ptr); if (data_type == ImGuiDataType_Float) return ImFormatString(buf, buf_size, format, *(const float*)data_ptr); if (data_type == ImGuiDataType_Double) @@ -8472,34 +8474,56 @@ static inline int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType da static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg1, const void* arg2) { IM_ASSERT(op == '+' || op == '-'); - if (data_type == ImGuiDataType_Int32) + switch (data_type) { - if (op == '+') *(int*)output = *(const int*)arg1 + *(const int*)arg2; - else if (op == '-') *(int*)output = *(const int*)arg1 - *(const int*)arg2; - } - else if (data_type == ImGuiDataType_Uint32) - { - if (op == '+') *(unsigned int*)output = *(const unsigned int*)arg1 + *(const unsigned int*)arg2; - else if (op == '-') *(unsigned int*)output = *(const unsigned int*)arg1 - *(const unsigned int*)arg2; - } - else if (data_type == ImGuiDataType_Float) - { - if (op == '+') *(float*)output = *(const float*)arg1 + *(const float*)arg2; - else if (op == '-') *(float*)output = *(const float*)arg1 - *(const float*)arg2; - } - else if (data_type == ImGuiDataType_Double) - { - if (op == '+') *(double*)output = *(const double*)arg1 + *(const double*)arg2; - else if (op == '-') *(double*)output = *(const double*)arg1 - *(const double*)arg2; + case ImGuiDataType_S32: + if (op == '+') *(int*)output = *(const int*)arg1 + *(const int*)arg2; + else if (op == '-') *(int*)output = *(const int*)arg1 - *(const int*)arg2; + return; + case ImGuiDataType_U32: + if (op == '+') *(unsigned int*)output = *(const unsigned int*)arg1 + *(const ImU32*)arg2; + else if (op == '-') *(unsigned int*)output = *(const unsigned int*)arg1 - *(const ImU32*)arg2; + return; + case ImGuiDataType_S64: + if (op == '+') *(ImS64*)output = *(const ImS64*)arg1 + *(const ImS64*)arg2; + else if (op == '-') *(ImS64*)output = *(const ImS64*)arg1 - *(const ImS64*)arg2; + return; + case ImGuiDataType_U64: + if (op == '+') *(ImU64*)output = *(const ImU64*)arg1 + *(const ImU64*)arg2; + else if (op == '-') *(ImU64*)output = *(const ImU64*)arg1 - *(const ImU64*)arg2; + return; + case ImGuiDataType_Float: + if (op == '+') *(float*)output = *(const float*)arg1 + *(const float*)arg2; + else if (op == '-') *(float*)output = *(const float*)arg1 - *(const float*)arg2; + return; + case ImGuiDataType_Double: + if (op == '+') *(double*)output = *(const double*)arg1 + *(const double*)arg2; + else if (op == '-') *(double*)output = *(const double*)arg1 - *(const double*)arg2; + return; + case ImGuiDataType_COUNT: break; } } -static size_t GDataTypeSize[ImGuiDataType_COUNT] = +struct ImGuiDataTypeInfo { - sizeof(int), - sizeof(unsigned int), - sizeof(float), - sizeof(double) + size_t Size; + const char* PrintFmt; // Unused + const char* ScanFmt; +}; + +static const ImGuiDataTypeInfo GDataTypeInfo[ImGuiDataType_COUNT] = +{ + { sizeof(int), "%d", "%d" }, + { sizeof(unsigned int), "%u", "%u" }, +#ifdef _MSC_VER + { sizeof(ImS64), "%I64d","%I64d" }, + { sizeof(ImU64), "%I64u","%I64u" }, +#else + { sizeof(ImS64), "%lld", "%lld" }, + { sizeof(ImU64), "%llu", "%llu" }, +#endif + { sizeof(float), "%f", "%f" }, // float are promoted to double in va_arg + { sizeof(double), "%f", "%lf" }, }; // User can input math operators (e.g. +100) to edit a numerical values. @@ -8525,47 +8549,41 @@ static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_b if (!buf[0]) return false; + // Copy the value in an opaque buffer so we can compare at the end of the function if it changed at all. IM_ASSERT(data_type < ImGuiDataType_COUNT); int data_backup[2]; - IM_ASSERT(GDataTypeSize[data_type] <= sizeof(data_backup)); - memcpy(data_backup, data_ptr, GDataTypeSize[data_type]); + IM_ASSERT(GDataTypeInfo[data_type].Size <= sizeof(data_backup)); + memcpy(data_backup, data_ptr, GDataTypeInfo[data_type].Size); + + if (scalar_format == NULL) + scalar_format = GDataTypeInfo[data_type].ScanFmt; int arg1i = 0; - float arg1f = 0.0f; - if (data_type == ImGuiDataType_Int32) + if (data_type == ImGuiDataType_S32) { - if (!scalar_format) - scalar_format = "%d"; int* v = (int*)data_ptr; int arg0i = *v; + float arg1f = 0.0f; if (op && sscanf(initial_value_buf, scalar_format, &arg0i) < 1) return false; // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (int)(arg0i + arg1i); } // Add (use "+-" to subtract) else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (int)(arg0i * arg1f); } // Multiply else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (int)(arg0i / arg1f); } // Divide - else { if (sscanf(buf, scalar_format, &arg0i) == 1) *v = arg0i; } // Assign integer constant + else { if (sscanf(buf, scalar_format, &arg1i) == 1) *v = arg1i; } // Assign constant } - else if (data_type == ImGuiDataType_Uint32) + else if (data_type == ImGuiDataType_U32 || data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) { - if (!scalar_format) - scalar_format = "%u"; - ImU32* v = (unsigned int*)data_ptr; - ImU32 arg0i = *v; - if (op && sscanf(initial_value_buf, scalar_format, &arg0i) < 1) - return false; - // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision - if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (ImU32)(arg0i + arg1f); } // Add (use "+-" to subtract) - else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (ImU32)(arg0i * arg1f); } // Multiply - else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (ImU32)(arg0i / arg1f); }// Divide - else { if (sscanf(buf, scalar_format, &arg0i) == 1) *v = arg0i; } // Assign integer constant + // Assign constant + // FIXME: We don't bother handling support for legacy operators since they are a little too crappy. Instead we may implement a proper expression evaluator in the future. + sscanf(buf, scalar_format, data_ptr); } else if (data_type == ImGuiDataType_Float) { // For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in scalar_format = "%f"; float* v = (float*)data_ptr; - float arg0f = *v; + float arg0f = *v, arg1f = 0.0f; if (op && sscanf(initial_value_buf, scalar_format, &arg0f) < 1) return false; if (sscanf(buf, scalar_format, &arg1f) < 1) @@ -8579,7 +8597,7 @@ static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_b { scalar_format = "%lf"; // scanf differentiate float/double unlike printf which forces everything to double because of ellipsis double* v = (double*)data_ptr; - double arg0f = *v; + double arg0f = *v, arg1f = 0.0; if (op && sscanf(initial_value_buf, scalar_format, &arg0f) < 1) return false; if (sscanf(buf, scalar_format, &arg1f) < 1) @@ -8589,7 +8607,7 @@ static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_b else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide else { *v = arg1f; } // Assign constant } - return memcmp(data_backup, data_ptr, GDataTypeSize[data_type]) != 0; + return memcmp(data_backup, data_ptr, GDataTypeInfo[data_type].Size) != 0; } // Create text input in place of a slider (when CTRL+Clicking on slider) @@ -10589,7 +10607,7 @@ bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, co } // NB: scalar_format here must be a simple "%xx" format string with no prefix/suffix (unlike the Drag/Slider functions "format" argument) -bool ImGui::InputScalarEx(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* scalar_format, ImGuiInputTextFlags extra_flags) +bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* scalar_format, ImGuiInputTextFlags extra_flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -10648,20 +10666,20 @@ bool ImGui::InputScalarEx(const char* label, ImGuiDataType data_type, void* data bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags extra_flags) { extra_flags |= ImGuiInputTextFlags_CharsScientific; - return InputScalarEx(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), format, extra_flags); + return InputScalar(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), format, extra_flags); } bool ImGui::InputDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags extra_flags) { extra_flags |= ImGuiInputTextFlags_CharsScientific; - return InputScalarEx(label, ImGuiDataType_Double, (void*)v, (void*)(step>0.0 ? &step : NULL), (void*)(step_fast>0.0 ? &step_fast : NULL), format, extra_flags); + return InputScalar(label, ImGuiDataType_Double, (void*)v, (void*)(step>0.0 ? &step : NULL), (void*)(step_fast>0.0 ? &step_fast : NULL), format, extra_flags); } bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags extra_flags) { // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes. const char* format = (extra_flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d"; - return InputScalarEx(label, ImGuiDataType_Int32, (void*)v, (void*)(step>0 ? &step : NULL), (void*)(step_fast>0 ? &step_fast : NULL), format, extra_flags); + return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step>0 ? &step : NULL), (void*)(step_fast>0 ? &step_fast : NULL), format, extra_flags); } bool ImGui::InputFloatN(const char* label, float* v, int components, const char* format, ImGuiInputTextFlags extra_flags) diff --git a/imgui.h b/imgui.h index 5e49704e3..33a30effe 100644 --- a/imgui.h +++ b/imgui.h @@ -72,13 +72,11 @@ struct ImGuiSizeCallbackData; // Structure used to constraint window size struct ImGuiListClipper; // Helper to manually clip large list of items struct ImGuiPayload; // User data payload for drag and drop operations struct ImGuiContext; // ImGui context (opaque) - #ifndef ImTextureID typedef void* ImTextureID; // User data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp) #endif // Typedefs and Enumerations (declared as int for compatibility with old C++ and to not pollute the top of this file) -typedef unsigned int ImU32; // 32-bit unsigned integer (typically used to store packed colors) typedef unsigned int ImGuiID; // Unique ID used by widgets (typically hashed from a stack of string) typedef unsigned short ImWchar; // Character for keyboard input/display typedef int ImGuiCol; // enum: a color identifier for styling // enum ImGuiCol_ @@ -105,12 +103,19 @@ typedef int ImGuiTreeNodeFlags; // flags: for TreeNode*(),CollapsingHeader() typedef int ImGuiWindowFlags; // flags: for Begin*() // enum ImGuiWindowFlags_ typedef int (*ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data); typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); + +// Scalar data types +typedef signed int ImS32; // 32-bit signed integer == int +typedef unsigned int ImU32; // 32-bit unsigned integer (often used to store packed colors) #if defined(_MSC_VER) && !defined(__clang__) -typedef unsigned __int64 ImU64; // 64-bit unsigned integer +typedef signed __int64 ImS64; // 64-bit signed integer +typedef unsigned __int64 ImU64; // 64-bit unsigned integer #else -typedef unsigned long long ImU64; // 64-bit unsigned integer +typedef signed long long ImS64; // 64-bit signed integer +typedef unsigned long long ImU64; // 64-bit unsigned integer #endif +// 2d vector struct ImVec2 { float x, y; @@ -122,6 +127,7 @@ struct ImVec2 #endif }; +// 4d vector (often used to store floating-point colors) struct ImVec4 { float x, y, z, w; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 48ca6d98e..00f13bb09 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -345,8 +345,8 @@ void ImGui::ShowDemoWindow(bool* p_open) static float f0 = 0.001f; ImGui::InputFloat("input float", &f0, 0.01f, 1.0f); - static double d0 = 999999.000001; - ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.6f"); + static double d0 = 999999.00000001; + ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f"); static float f1 = 1.e10f; ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e"); diff --git a/imgui_internal.h b/imgui_internal.h index 44d1434fc..6fbe06477 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -248,8 +248,10 @@ enum ImGuiPlotType enum ImGuiDataType { - ImGuiDataType_Int32, - ImGuiDataType_Uint32, + ImGuiDataType_S32, // int + ImGuiDataType_U32, // unsigned int + ImGuiDataType_S64, // long long / __int64 + ImGuiDataType_U64, // unsigned long long / unsigned __int64 ImGuiDataType_Float, ImGuiDataType_Double, ImGuiDataType_COUNT @@ -1110,7 +1112,7 @@ namespace ImGui IMGUI_API bool InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputFloatN(const char* label, float* v, int components, const char* format, ImGuiInputTextFlags extra_flags); IMGUI_API bool InputIntN(const char* label, int* v, int components, ImGuiInputTextFlags extra_flags); - IMGUI_API bool InputScalarEx(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* format, ImGuiInputTextFlags extra_flags = 0); + IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* format, ImGuiInputTextFlags extra_flags = 0); IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format); IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags); From 3f04fd0644a75b4d91bc2707f4aa93c798eee781 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 May 2018 14:04:25 +0200 Subject: [PATCH 06/22] Internals: DragFloat: Removed DragSpeedScaleFast/DragSpeedScaleSlow since it's not yet usable and Nav version doesn't have an equivalent. --- imgui.cpp | 8 ++++---- imgui_internal.h | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 811aa5fe9..2b63e14ce 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9154,10 +9154,10 @@ bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_s if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid()) { adjust_delta = mouse_drag_delta.x - g.DragLastMouseDelta.x; - if (g.IO.KeyShift && g.DragSpeedScaleFast >= 0.0f) - adjust_delta *= g.DragSpeedScaleFast; - if (g.IO.KeyAlt && g.DragSpeedScaleSlow >= 0.0f) - adjust_delta *= g.DragSpeedScaleSlow; + if (g.IO.KeyAlt) + adjust_delta *= 1.0f/100.0f; + if (g.IO.KeyShift) + adjust_delta *= 10.0f; g.DragLastMouseDelta.x = mouse_drag_delta.x; } if (g.ActiveIdSource == ImGuiInputSource_Nav) diff --git a/imgui_internal.h b/imgui_internal.h index 6fbe06477..9c4c4690b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -671,8 +671,6 @@ struct ImGuiContext float DragCurrentValue; // Currently dragged value, always float, not rounded by end-user precision settings ImVec2 DragLastMouseDelta; float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio - float DragSpeedScaleSlow; - float DragSpeedScaleFast; ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? int TooltipOverrideCount; ImVector PrivateClipboard; // If no custom clipboard handler is defined @@ -776,8 +774,6 @@ struct ImGuiContext DragCurrentValue = 0.0f; DragLastMouseDelta = ImVec2(0.0f, 0.0f); DragSpeedDefaultRatio = 1.0f / 100.0f; - DragSpeedScaleSlow = 1.0f / 100.0f; - DragSpeedScaleFast = 10.0f; ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f); TooltipOverrideCount = 0; PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX); From 93b8580a8daad56afb925a8bc5aab2ec4076b674 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 May 2018 14:05:17 +0200 Subject: [PATCH 07/22] Internals: DragFloat: Fixed power handling. Use an temporary accumulator and no absolute values so we will be able to manipulate double as well as 64-bit integers. (#1011, #708, #320) --- CHANGELOG.txt | 1 + imgui.cpp | 81 +++++++++++++++++++++++++++--------------------- imgui_internal.h | 8 ++--- 3 files changed, 50 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 4554d69de..3cab05089 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -62,6 +62,7 @@ Other Changes: - 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: Fixes to allow input of scientific notation numbers when using CTRL+Click to input the value. (~#648, #1011) - DragFloat, SliderFloat: Rounding-on-write uses the provided format string instead of parsing the precision from the string, which allows for finer uses of %e %g etc. (#648, #642) +- DragFloat: Improved computation when using the power curve. Reduced lost of input precision with small steps. Added an assert than power-curve requires a min/max range. (~#642) - Nav: Fixed hovering a Selectable() with the mouse so that it update the navigation cursor (as it happened in the pre 1.60 navigation branch). (#787) - 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) diff --git a/imgui.cpp b/imgui.cpp index 2b63e14ce..bc1b7a6f9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9142,23 +9142,15 @@ bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_s if (v_speed == 0.0f && (v_max - v_min) != 0.0f && (v_max - v_min) < FLT_MAX) v_speed = (v_max - v_min) * g.DragSpeedDefaultRatio; - if (g.ActiveIdIsJustActivated) - { - // Lock current value on click - g.DragCurrentValue = *v; - g.DragLastMouseDelta = ImVec2(0.f, 0.f); - } - - const ImVec2 mouse_drag_delta = GetMouseDragDelta(0, 1.0f); + // Inputs accumulate into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings float adjust_delta = 0.0f; - if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid()) + if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid() && g.IO.MouseDragMaxDistanceSqr[0] > 1.0f*1.0f) { - adjust_delta = mouse_drag_delta.x - g.DragLastMouseDelta.x; + adjust_delta = g.IO.MouseDelta.x; if (g.IO.KeyAlt) adjust_delta *= 1.0f/100.0f; if (g.IO.KeyShift) adjust_delta *= 10.0f; - g.DragLastMouseDelta.x = mouse_drag_delta.x; } if (g.ActiveIdSource == ImGuiInputSource_Nav) { @@ -9168,41 +9160,55 @@ bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_s } adjust_delta *= v_speed; - // Avoid applying the saturation when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300 - float v_cur = g.DragCurrentValue; - if (v_min < v_max && ((v_cur >= v_max && adjust_delta > 0.0f) || (v_cur <= v_min && adjust_delta < 0.0f))) - adjust_delta = 0.0f; - - if (fabsf(adjust_delta) > 0.0f) + // Clear current value on activation + // Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300. + bool is_just_activated = g.ActiveIdIsJustActivated; + bool is_already_past_limits_and_pushing_outward = (v_min < v_max) && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f)); + if (is_just_activated || is_already_past_limits_and_pushing_outward) { - if (fabsf(power - 1.0f) > 0.001f) + g.DragCurrentAccum = 0.0f; + g.DragCurrentAccumDirty = false; + } + else if (adjust_delta != 0.0f) + { + g.DragCurrentAccum += adjust_delta; + g.DragCurrentAccumDirty = true; + } + + bool value_changed = false; + if (g.DragCurrentAccumDirty) + { + float v_cur = *v; + if (power != 1.0f && v_min != v_max) { - // Power curve on both side of 0.0 - float v0_abs = v_cur >= 0.0f ? v_cur : -v_cur; - float v0_sign = v_cur >= 0.0f ? 1.0f : -1.0f; - float v1 = powf(v0_abs, 1.0f / power) + (adjust_delta * v0_sign); - float v1_abs = v1 >= 0.0f ? v1 : -v1; - float v1_sign = v1 >= 0.0f ? 1.0f : -1.0f; // Crossed sign line - v_cur = powf(v1_abs, power) * v0_sign * v1_sign; // Reapply sign + // Offset + round to user desired precision, with a curve on the v_min..v_max range to get more precision on one side of the range + IM_ASSERT(v_min != v_max); // When using a power curve the drag needs to have known bounds + float v_old_norm_curved = powf((v_cur - v_min) / (v_max - v_min), 1.0f / power); + float v_new_norm_curved = v_old_norm_curved + (g.DragCurrentAccum / (v_max - v_min)); + v_cur = v_min + powf(ImSaturate(v_new_norm_curved), power) * (v_max - v_min); + v_cur = RoundScalarWithFormat(format, v_cur); + float v_cur_norm_curved = powf((v_cur - v_min) / (v_max - v_min), 1.0f / power); + g.DragCurrentAccum -= (v_cur_norm_curved - v_old_norm_curved); // Preserve remainder } else { - v_cur += adjust_delta; + // Offset + round to user desired precision + v_cur += g.DragCurrentAccum; + v_cur = RoundScalarWithFormat(format, v_cur); + g.DragCurrentAccum -= (v_cur - *v); // Preserve remainder } // Clamp - if (v_min < v_max) + if (*v != v_cur && v_min < v_max) v_cur = ImClamp(v_cur, v_min, v_max); - g.DragCurrentValue = v_cur; - } - // Round to user desired precision, then apply - bool value_changed = false; - v_cur = RoundScalarWithFormat(format, v_cur); - if (*v != v_cur) - { - *v = v_cur; - value_changed = true; + // Apply result + if (*v != v_cur) + { + *v = v_cur; + value_changed = true; + } + g.DragCurrentAccumDirty = false; } return value_changed; @@ -9214,6 +9220,9 @@ bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, f if (window->SkipItems) return false; + if (power != 1.0f) + IM_ASSERT(v_min != v_max); // When using a power curve the drag needs to have known bounds + ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; const ImGuiID id = window->GetID(label); diff --git a/imgui_internal.h b/imgui_internal.h index 9c4c4690b..1480ddebe 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -668,8 +668,8 @@ struct ImGuiContext ImGuiID ScalarAsInputTextId; // Temporary text input when CTRL+clicking on a slider, etc. ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets ImVec4 ColorPickerRef; - float DragCurrentValue; // Currently dragged value, always float, not rounded by end-user precision settings - ImVec2 DragLastMouseDelta; + bool DragCurrentAccumDirty; + float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? int TooltipOverrideCount; @@ -771,8 +771,8 @@ struct ImGuiContext ScalarAsInputTextId = 0; ColorEditOptions = ImGuiColorEditFlags__OptionsDefault; - DragCurrentValue = 0.0f; - DragLastMouseDelta = ImVec2(0.0f, 0.0f); + DragCurrentAccumDirty = false; + DragCurrentAccum = 0.0f; DragSpeedDefaultRatio = 1.0f / 100.0f; ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f); TooltipOverrideCount = 0; From 6c932479f2e265c7e1bd73f32725c3f6005a7557 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 May 2018 17:32:50 +0200 Subject: [PATCH 08/22] Internal: DragScalar(), InputScalar() now support signed/unsigned, 32/64 bits, float/double data types. (#320, #643, #708, #1011) --- CHANGELOG.txt | 4 +- imgui.cpp | 208 +++++++++++++++++++++++++++-------------------- imgui_internal.h | 7 +- 3 files changed, 126 insertions(+), 93 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 3cab05089..c9e9e0a0c 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -60,9 +60,10 @@ 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, DragInt: Honor natural type limits (e.g. INT_MAX, FLT_MAX) instead of wrapping around. (#708, #320) - DragFloat, SliderFloat: Fixes to allow input of scientific notation numbers when using CTRL+Click to input the value. (~#648, #1011) - DragFloat, SliderFloat: Rounding-on-write uses the provided format string instead of parsing the precision from the string, which allows for finer uses of %e %g etc. (#648, #642) -- DragFloat: Improved computation when using the power curve. Reduced lost of input precision with small steps. Added an assert than power-curve requires a min/max range. (~#642) +- DragFloat: Improved computation when using the power curve. Improved lost of input precision with very small steps. Added an assert than power-curve requires a min/max range. (~#642) - Nav: Fixed hovering a Selectable() with the mouse so that it update the navigation cursor (as it happened in the pre 1.60 navigation branch). (#787) - 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) @@ -70,6 +71,7 @@ Other Changes: - Examples: Calling IMGUI_CHECKVERSION() in the main.cpp of every example application. - Examples: Allegro 5: Added support for 32-bit indices setup via defining ImDrawIdx, to avoid an unnecessary conversion (Allegro 5 doesn't support 16-bit indices). - Examples: Allegro 5: Renamed bindings from imgui_impl_a5.cpp to imgui_impl_allegro5.cpp. +- Internal: DragScalar(), InputScalar() now support signed/unsigned, 32/64 bits, float/double data types. (#320, #643, #708, #1011) - Various minor fixes, tweaks, refactoring, comments. ----------------------------------------------------------------------- diff --git a/imgui.cpp b/imgui.cpp index bc1b7a6f9..af227be43 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -761,6 +761,10 @@ static void UpdateMovingWindow(); static void UpdateMouseInputs(); static void UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]); static void FocusFrontMostActiveWindow(ImGuiWindow* ignore_window); + +template +static bool DragBehaviorT(ImGuiID id, ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power); +static bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power); } //----------------------------------------------------------------------------- @@ -1088,12 +1092,13 @@ void ImStrTrimBlanks(char* buf) buf[p - p_start] = 0; // Zero terminate } -static const char* ImAtoi(const char* src, int* output) +template +static const char* ImAtoi(const char* src, TYPE* output) { int negative = 0; if (*src == '-') { negative = 1; src++; } if (*src == '+') { src++; } - int v = 0; + TYPE v = 0; while (*src >= '0' && *src <= '9') v = (v * 10) + (*src++ - '0'); *output = negative ? -v : v; @@ -8693,7 +8698,7 @@ int ImGui::ParseFormatPrecision(const char* fmt, int default_precision) int precision = INT_MAX; if (*fmt == '.') { - fmt = ImAtoi(fmt + 1, &precision); + fmt = ImAtoi(fmt + 1, &precision); if (precision < 0 || precision > 99) precision = default_precision; } @@ -9117,15 +9122,10 @@ bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const return SliderIntN(label, v, 4, v_min, v_max, format); } -bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, const char* format, float power) +template +static bool ImGui::DragBehaviorT(ImGuiID id, ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power) { ImGuiContext& g = *GImGui; - const ImGuiStyle& style = g.Style; - - // Draw frame - const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); - RenderNavHighlight(frame_bb, id); - RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); // Process interacting with the drag if (g.ActiveId == id) @@ -9139,10 +9139,11 @@ bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_s return false; // Default tweak speed - if (v_speed == 0.0f && (v_max - v_min) != 0.0f && (v_max - v_min) < FLT_MAX) - v_speed = (v_max - v_min) * g.DragSpeedDefaultRatio; + bool has_min_max = (v_min != v_max) && (v_max - v_max < FLT_MAX); + if (v_speed == 0.0f && has_min_max) + v_speed = (float)((v_max - v_min) * g.DragSpeedDefaultRatio); - // Inputs accumulate into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings + // Inputs accumulates into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings float adjust_delta = 0.0f; if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid() && g.IO.MouseDragMaxDistanceSqr[0] > 1.0f*1.0f) { @@ -9163,7 +9164,7 @@ bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_s // Clear current value on activation // Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300. bool is_just_activated = g.ActiveIdIsJustActivated; - bool is_already_past_limits_and_pushing_outward = (v_min < v_max) && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f)); + bool is_already_past_limits_and_pushing_outward = has_min_max && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f)); if (is_just_activated || is_already_past_limits_and_pushing_outward) { g.DragCurrentAccum = 0.0f; @@ -9175,46 +9176,92 @@ bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_s g.DragCurrentAccumDirty = true; } - bool value_changed = false; - if (g.DragCurrentAccumDirty) + if (!g.DragCurrentAccumDirty) + return false; + + TYPE v_cur = *v; + FLOATTYPE v_old_ref_for_accum_remainder = (FLOATTYPE)0.0f; + + const bool is_power = (power != 1.0f && (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) && has_min_max); + if (is_power) { - float v_cur = *v; - if (power != 1.0f && v_min != v_max) - { - // Offset + round to user desired precision, with a curve on the v_min..v_max range to get more precision on one side of the range - IM_ASSERT(v_min != v_max); // When using a power curve the drag needs to have known bounds - float v_old_norm_curved = powf((v_cur - v_min) / (v_max - v_min), 1.0f / power); - float v_new_norm_curved = v_old_norm_curved + (g.DragCurrentAccum / (v_max - v_min)); - v_cur = v_min + powf(ImSaturate(v_new_norm_curved), power) * (v_max - v_min); - v_cur = RoundScalarWithFormat(format, v_cur); - float v_cur_norm_curved = powf((v_cur - v_min) / (v_max - v_min), 1.0f / power); - g.DragCurrentAccum -= (v_cur_norm_curved - v_old_norm_curved); // Preserve remainder - } - else - { - // Offset + round to user desired precision - v_cur += g.DragCurrentAccum; - v_cur = RoundScalarWithFormat(format, v_cur); - g.DragCurrentAccum -= (v_cur - *v); // Preserve remainder - } - - // Clamp - if (*v != v_cur && v_min < v_max) - v_cur = ImClamp(v_cur, v_min, v_max); - - // Apply result - if (*v != v_cur) - { - *v = v_cur; - value_changed = true; - } - g.DragCurrentAccumDirty = false; + // Offset + round to user desired precision, with a curve on the v_min..v_max range to get more precision on one side of the range + FLOATTYPE v_old_norm_curved = (FLOATTYPE)pow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power); + FLOATTYPE v_new_norm_curved = v_old_norm_curved + (g.DragCurrentAccum / (v_max - v_min)); + v_cur = v_min + (TYPE)pow(ImSaturate((float)v_new_norm_curved), power) * (v_max - v_min); + v_old_ref_for_accum_remainder = v_old_norm_curved; + } + else + { + v_cur += (TYPE)g.DragCurrentAccum; } - return value_changed; + // Round to user desired precision based on format string + char v_str[64]; + ImFormatString(v_str, IM_ARRAYSIZE(v_str), ParseFormatTrimDecorationsLeading(format), v_cur); + if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) + v_cur = (TYPE)atof(v_str); + else + ImAtoi(v_str, (SIGNEDTYPE*)&v_cur); + + // Preserve remainder after rounding has been applied. This also allow slow tweaking of values. + g.DragCurrentAccumDirty = false; + if (is_power) + { + FLOATTYPE v_cur_norm_curved = (FLOATTYPE)pow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power); + g.DragCurrentAccum -= (float)(v_cur_norm_curved - v_old_ref_for_accum_remainder); + } + else + { + g.DragCurrentAccum -= (float)((SIGNEDTYPE)v_cur - (SIGNEDTYPE)*v); + } + + // Lose zero sign for float/double + if (v_cur == (TYPE)-0) + v_cur = (TYPE)0; + + // Clamp values (handle overflow/wrap-around) + if (*v != v_cur && has_min_max) + { + if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f)) + v_cur = v_min; + if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f)) + v_cur = v_max; + } + + // Apply result + if (*v == v_cur) + return false; + *v = v_cur; + return true; } -bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power) +static const ImS32 IM_S32_MIN = 0x80000000; // INT_MIN; +static const ImS32 IM_S32_MAX = 0x7FFFFFFF; // INT_MAX; +static const ImU32 IM_U32_MIN = 0; +static const ImU32 IM_U32_MAX = 0xFFFFFFFF; +static const ImS64 IM_S64_MIN = -9223372036854775807ll - 1ll; +static const ImS64 IM_S64_MAX = 9223372036854775807ll; +static const ImU64 IM_U64_MIN = 0; +static const ImU64 IM_U64_MAX = 0xFFFFFFFFFFFFFFFFull; + +bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power) +{ + switch (data_type) + { + case ImGuiDataType_S32: return DragBehaviorT(id, data_type, (ImS32*)v, v_speed, v_min ? *(const ImS32* )v_min : IM_S32_MIN, v_max ? *(const ImS32* )v_max : IM_S32_MAX, format, power); + case ImGuiDataType_U32: return DragBehaviorT(id, data_type, (ImU32*)v, v_speed, v_min ? *(const ImU32* )v_min : IM_U32_MIN, v_max ? *(const ImU32* )v_max : IM_U32_MAX, format, power); + case ImGuiDataType_S64: return DragBehaviorT(id, data_type, (ImS64*)v, v_speed, v_min ? *(const ImS64* )v_min : IM_S64_MIN, v_max ? *(const ImS64* )v_max : IM_S64_MAX, format, power); + case ImGuiDataType_U64: return DragBehaviorT(id, data_type, (ImU64*)v, v_speed, v_min ? *(const ImU64* )v_min : IM_U64_MIN, v_max ? *(const ImU64* )v_max : IM_U64_MAX, format, power); + case ImGuiDataType_Float: return DragBehaviorT(id, data_type, (float*)v, v_speed, v_min ? *(const float* )v_min : -FLT_MAX, v_max ? *(const float* )v_max : FLT_MAX, format, power); + case ImGuiDataType_Double: return DragBehaviorT(id, data_type, (double*)v, v_speed, v_min ? *(const double*)v_min : -DBL_MAX, v_max ? *(const double*)v_max : DBL_MAX, format, power); + case ImGuiDataType_COUNT: break; + } + IM_ASSERT(0); + return false; +} + +bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -9260,16 +9307,21 @@ bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, f } } if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) - return InputScalarAsWidgetReplacement(frame_bb, id, label, ImGuiDataType_Float, v, format); + return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format); // Actual drag behavior ItemSize(total_bb, style.FramePadding.y); - const bool value_changed = DragBehavior(frame_bb, id, v, v_speed, v_min, v_max, format, power); + const bool value_changed = DragBehavior(id, data_type, v, v_speed, v_min, v_max, format, power); + + // Draw frame + const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); + RenderNavHighlight(frame_bb, id); + RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; - const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), format, *v); - RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.5f)); + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, v, format); + RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label); @@ -9277,7 +9329,7 @@ bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, f return value_changed; } -bool ImGui::DragFloatN(const char* label, float* v, int components, float v_speed, float v_min, float v_max, const char* format, float power) +bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min, const void* v_max, const char* format, float power) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -9288,13 +9340,15 @@ bool ImGui::DragFloatN(const char* label, float* v, int components, float v_spee BeginGroup(); PushID(label); PushMultiItemsWidths(components); + size_t type_size = GDataTypeInfo[data_type].Size; for (int i = 0; i < components; i++) { PushID(i); - value_changed |= DragFloat("##v", &v[i], v_speed, v_min, v_max, format, power); + value_changed |= DragScalar("##v", data_type, v, v_speed, v_min, v_max, format, power); SameLine(0, g.Style.ItemInnerSpacing.x); PopID(); PopItemWidth(); + v = (void*)((char*)v + type_size); } PopID(); @@ -9304,19 +9358,24 @@ bool ImGui::DragFloatN(const char* label, float* v, int components, float v_spee return value_changed; } +bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power) +{ + return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); +} + bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power) { - return DragFloatN(label, v, 2, v_speed, v_min, v_max, format, power); + return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); } bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power) { - return DragFloatN(label, v, 3, v_speed, v_min, v_max, format, power); + return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); } bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power) { - return DragFloatN(label, v, 4, v_speed, v_min, v_max, format, power); + return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); } bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, float power) @@ -9355,46 +9414,19 @@ bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_m return value_changed; } -bool ImGui::DragIntN(const char* label, int* v, int components, float v_speed, int v_min, int v_max, const char* format) -{ - ImGuiWindow* window = GetCurrentWindow(); - if (window->SkipItems) - return false; - - ImGuiContext& g = *GImGui; - bool value_changed = false; - BeginGroup(); - PushID(label); - PushMultiItemsWidths(components); - for (int i = 0; i < components; i++) - { - PushID(i); - value_changed |= DragInt("##v", &v[i], v_speed, v_min, v_max, format); - SameLine(0, g.Style.ItemInnerSpacing.x); - PopID(); - PopItemWidth(); - } - PopID(); - - TextUnformatted(label, FindRenderedTextEnd(label)); - EndGroup(); - - return value_changed; -} - bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* format) { - return DragIntN(label, v, 2, v_speed, v_min, v_max, format); + return DragScalarN(label, ImGuiDataType_S32, v, 2, v_speed, &v_min, &v_max, format); } bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* format) { - return DragIntN(label, v, 3, v_speed, v_min, v_max, format); + return DragScalarN(label, ImGuiDataType_S32, v, 3, v_speed, &v_min, &v_max, format); } bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* format) { - return DragIntN(label, v, 4, v_speed, v_min, v_max, format); + return DragScalarN(label, ImGuiDataType_S32, v, 4, v_speed, &v_min, &v_max, format); } bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* format, const char* format_max) diff --git a/imgui_internal.h b/imgui_internal.h index 1480ddebe..6ae98be0d 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1101,14 +1101,13 @@ namespace ImGui IMGUI_API bool SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* format, float power); IMGUI_API bool SliderIntN(const char* label, int* v, int components, int v_min, int v_max, const char* format); - IMGUI_API bool DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, const char* format, float power); - IMGUI_API bool DragFloatN(const char* label, float* v, int components, float v_speed, float v_min, float v_max, const char* format, float power); - IMGUI_API bool DragIntN(const char* label, int* v, int components, float v_speed, int v_min, int v_max, const char* format); + IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power = 1.0f); + IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min, const void* v_max, const char* format, float power = 1.0f); + IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* v, void* step_ptr, void* step_fast_ptr, const char* format, ImGuiInputTextFlags extra_flags = 0); IMGUI_API bool InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputFloatN(const char* label, float* v, int components, const char* format, ImGuiInputTextFlags extra_flags); IMGUI_API bool InputIntN(const char* label, int* v, int components, ImGuiInputTextFlags extra_flags); - IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* format, ImGuiInputTextFlags extra_flags = 0); IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format); IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags); From 086c3925c49d6a02173b32d9adb39517b6f5653e Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 May 2018 19:36:47 +0200 Subject: [PATCH 09/22] Internals: Fixed DragInt* default format string. InputScalar(), InputScalarN(), removed InputFloatN(), InputInt(). Note that DragInt2/3/4 will %f format strings will currently be broken. (#320, #643, #708, #1011) --- CHANGELOG.txt | 1 + imgui.cpp | 92 ++++++++++++++++-------------------------------- imgui.h | 10 +++--- imgui_demo.cpp | 4 +-- imgui_internal.h | 3 +- 5 files changed, 40 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c9e9e0a0c..f197b3446 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -64,6 +64,7 @@ Other Changes: - DragFloat, SliderFloat: Fixes to allow input of scientific notation numbers when using CTRL+Click to input the value. (~#648, #1011) - DragFloat, SliderFloat: Rounding-on-write uses the provided format string instead of parsing the precision from the string, which allows for finer uses of %e %g etc. (#648, #642) - DragFloat: Improved computation when using the power curve. Improved lost of input precision with very small steps. Added an assert than power-curve requires a min/max range. (~#642) +- DragFloat: The 'power' parameter is only honored if the min/max parameter are also setup. - Nav: Fixed hovering a Selectable() with the mouse so that it update the navigation cursor (as it happened in the pre 1.60 navigation branch). (#787) - 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) diff --git a/imgui.cpp b/imgui.cpp index af227be43..54a107ef9 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8533,7 +8533,7 @@ static const ImGuiDataTypeInfo GDataTypeInfo[ImGuiDataType_COUNT] = // User can input math operators (e.g. +100) to edit a numerical values. // NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess.. -static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* scalar_format) +static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* format) { while (ImCharIsBlankA(*buf)) buf++; @@ -8560,8 +8560,8 @@ static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_b IM_ASSERT(GDataTypeInfo[data_type].Size <= sizeof(data_backup)); memcpy(data_backup, data_ptr, GDataTypeInfo[data_type].Size); - if (scalar_format == NULL) - scalar_format = GDataTypeInfo[data_type].ScanFmt; + if (format == NULL) + format = GDataTypeInfo[data_type].ScanFmt; int arg1i = 0; if (data_type == ImGuiDataType_S32) @@ -8569,29 +8569,29 @@ static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_b int* v = (int*)data_ptr; int arg0i = *v; float arg1f = 0.0f; - if (op && sscanf(initial_value_buf, scalar_format, &arg0i) < 1) + if (op && sscanf(initial_value_buf, format, &arg0i) < 1) return false; // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (int)(arg0i + arg1i); } // Add (use "+-" to subtract) else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (int)(arg0i * arg1f); } // Multiply else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (int)(arg0i / arg1f); } // Divide - else { if (sscanf(buf, scalar_format, &arg1i) == 1) *v = arg1i; } // Assign constant + else { if (sscanf(buf, format, &arg1i) == 1) *v = arg1i; } // Assign constant } else if (data_type == ImGuiDataType_U32 || data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64) { // Assign constant // FIXME: We don't bother handling support for legacy operators since they are a little too crappy. Instead we may implement a proper expression evaluator in the future. - sscanf(buf, scalar_format, data_ptr); + sscanf(buf, format, data_ptr); } else if (data_type == ImGuiDataType_Float) { // For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in - scalar_format = "%f"; + format = "%f"; float* v = (float*)data_ptr; float arg0f = *v, arg1f = 0.0f; - if (op && sscanf(initial_value_buf, scalar_format, &arg0f) < 1) + if (op && sscanf(initial_value_buf, format, &arg0f) < 1) return false; - if (sscanf(buf, scalar_format, &arg1f) < 1) + if (sscanf(buf, format, &arg1f) < 1) return false; if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract) else if (op == '*') { *v = arg0f * arg1f; } // Multiply @@ -8600,12 +8600,12 @@ static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_b } else if (data_type == ImGuiDataType_Double) { - scalar_format = "%lf"; // scanf differentiate float/double unlike printf which forces everything to double because of ellipsis + format = "%lf"; // scanf differentiate float/double unlike printf which forces everything to double because of ellipsis double* v = (double*)data_ptr; double arg0f = *v, arg1f = 0.0; - if (op && sscanf(initial_value_buf, scalar_format, &arg0f) < 1) + if (op && sscanf(initial_value_buf, format, &arg0f) < 1) return false; - if (sscanf(buf, scalar_format, &arg1f) < 1) + if (sscanf(buf, format, &arg1f) < 1) return false; if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract) else if (op == '*') { *v = arg0f * arg1f; } // Multiply @@ -9406,12 +9406,7 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu // NB: v_speed is float to allow adjusting the drag speed with more precision bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format) { - if (!format) - format = "%.0f"; - float v_f = (float)*v; - bool value_changed = DragFloat(label, &v_f, v_speed, (float)v_min, (float)v_max, format); - *v = (int)v_f; - return value_changed; + return DragScalar(label, ImGuiDataType_S32, v, v_speed, &v_min, &v_max, format); } bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* format) @@ -10647,8 +10642,8 @@ bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, co return InputTextEx(label, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data); } -// NB: scalar_format here must be a simple "%xx" format string with no prefix/suffix (unlike the Drag/Slider functions "format" argument) -bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* scalar_format, ImGuiInputTextFlags extra_flags) +// NB: format here must be a simple "%xx" format string with no prefix/suffix (unlike the Drag/Slider functions "format" argument) +bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* format, ImGuiInputTextFlags extra_flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -10658,7 +10653,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p const ImGuiStyle& style = g.Style; char buf[64]; - DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, data_ptr, scalar_format); + DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, data_ptr, format); bool value_changed = false; if ((extra_flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0) @@ -10673,7 +10668,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p PushID(label); PushItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2)); if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) // PushId(label) + "" gives us the expected ID from outside point of view - value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, scalar_format); + value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, format); PopItemWidth(); // Step buttons @@ -10698,7 +10693,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p else { if (InputText(label, buf, IM_ARRAYSIZE(buf), extra_flags)) - value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, scalar_format); + value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, format); } return value_changed; @@ -10723,7 +10718,7 @@ bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiIn return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step>0 ? &step : NULL), (void*)(step_fast>0 ? &step_fast : NULL), format, extra_flags); } -bool ImGui::InputFloatN(const char* label, float* v, int components, const char* format, ImGuiInputTextFlags extra_flags) +bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, void* step_ptr, void* step_fast_ptr, const char* format, ImGuiInputTextFlags extra_flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -10734,13 +10729,15 @@ bool ImGui::InputFloatN(const char* label, float* v, int components, const char* BeginGroup(); PushID(label); PushMultiItemsWidths(components); + size_t type_size = GDataTypeInfo[data_type].Size; for (int i = 0; i < components; i++) { PushID(i); - value_changed |= InputFloat("##v", &v[i], 0, 0, format, extra_flags); + value_changed |= InputScalar("##v", data_type, v, step_ptr, step_fast_ptr, format, extra_flags); SameLine(0, g.Style.ItemInnerSpacing.x); PopID(); PopItemWidth(); + v = (void*)((char*)v + type_size); } PopID(); @@ -10752,17 +10749,17 @@ bool ImGui::InputFloatN(const char* label, float* v, int components, const char* bool ImGui::InputFloat2(const char* label, float v[2], const char* format, ImGuiInputTextFlags extra_flags) { - return InputFloatN(label, v, 2, format, extra_flags); + return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, extra_flags); } bool ImGui::InputFloat3(const char* label, float v[3], const char* format, ImGuiInputTextFlags extra_flags) { - return InputFloatN(label, v, 3, format, extra_flags); + return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, extra_flags); } bool ImGui::InputFloat4(const char* label, float v[4], const char* format, ImGuiInputTextFlags extra_flags) { - return InputFloatN(label, v, 4, format, extra_flags); + return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, extra_flags); } // Prefer using "const char* format" directly, which is more flexible and consistent with other API. @@ -10780,7 +10777,7 @@ bool ImGui::InputFloat2(const char* label, float v[2], int decimal_precision, Im char format[16] = "%f"; if (decimal_precision >= 0) ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); - return InputFloatN(label, v, 2, format, extra_flags); + return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, extra_flags); } bool ImGui::InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags extra_flags) @@ -10788,7 +10785,7 @@ bool ImGui::InputFloat3(const char* label, float v[3], int decimal_precision, Im char format[16] = "%f"; if (decimal_precision >= 0) ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); - return InputFloatN(label, v, 3, format, extra_flags); + return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, extra_flags); } bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags extra_flags) @@ -10796,50 +10793,23 @@ bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision, Im char format[16] = "%f"; if (decimal_precision >= 0) ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision); - return InputFloatN(label, v, 4, format, extra_flags); + return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, extra_flags); } #endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS -bool ImGui::InputIntN(const char* label, int* v, int components, ImGuiInputTextFlags extra_flags) -{ - ImGuiWindow* window = GetCurrentWindow(); - if (window->SkipItems) - return false; - - ImGuiContext& g = *GImGui; - bool value_changed = false; - BeginGroup(); - PushID(label); - PushMultiItemsWidths(components); - for (int i = 0; i < components; i++) - { - PushID(i); - value_changed |= InputInt("##v", &v[i], 0, 0, extra_flags); - SameLine(0, g.Style.ItemInnerSpacing.x); - PopID(); - PopItemWidth(); - } - PopID(); - - TextUnformatted(label, FindRenderedTextEnd(label)); - EndGroup(); - - return value_changed; -} - bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags extra_flags) { - return InputIntN(label, v, 2, extra_flags); + return InputScalarN(label, ImGuiDataType_S32, v, 2, NULL, NULL, "%d", extra_flags); } bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags extra_flags) { - return InputIntN(label, v, 3, extra_flags); + return InputScalarN(label, ImGuiDataType_S32, v, 3, NULL, NULL, "%d", extra_flags); } bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_flags) { - return InputIntN(label, v, 4, extra_flags); + return InputScalarN(label, ImGuiDataType_S32, v, 4, NULL, NULL, "%d", extra_flags); } static float CalcMaxPopupHeightFromItemCount(int items_count) diff --git a/imgui.h b/imgui.h index 33a30effe..dcee1a187 100644 --- a/imgui.h +++ b/imgui.h @@ -347,11 +347,11 @@ namespace ImGui IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); IMGUI_API bool DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); IMGUI_API bool DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", const char* format_max = NULL, float power = 1.0f); - IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%.0f"); // If v_min >= v_max we have no bound - IMGUI_API bool DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%.0f"); - IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%.0f"); - IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%.0f"); - IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%.0f", const char* format_max = NULL); + IMGUI_API bool DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); // If v_min >= v_max we have no bound + IMGUI_API bool DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); + IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); + IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); + IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", const char* format_max = NULL); // Widgets: Input with Keyboard IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 00f13bb09..59c958304 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1008,16 +1008,16 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::InputFloat2("input float2", vec4f); ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f); ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f); - ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); ImGui::InputInt2("input int2", vec4i); + ImGui::DragInt2("drag int2", vec4i, 1, 0, 255); ImGui::SliderInt2("slider int2", vec4i, 0, 255); ImGui::Spacing(); ImGui::InputFloat3("input float3", vec4f); ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f); ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f); - ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); ImGui::InputInt3("input int3", vec4i); + ImGui::DragInt3("drag int3", vec4i, 1, 0, 255); ImGui::SliderInt3("slider int3", vec4i, 0, 255); ImGui::Spacing(); diff --git a/imgui_internal.h b/imgui_internal.h index 6ae98be0d..f612c8af9 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1105,9 +1105,8 @@ namespace ImGui IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min, const void* v_max, const char* format, float power = 1.0f); IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* v, void* step_ptr, void* step_fast_ptr, const char* format, ImGuiInputTextFlags extra_flags = 0); + IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, void* step_ptr, void* step_fast_ptr, const char* format, ImGuiInputTextFlags extra_flags = 0); IMGUI_API bool InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); - IMGUI_API bool InputFloatN(const char* label, float* v, int components, const char* format, ImGuiInputTextFlags extra_flags); - IMGUI_API bool InputIntN(const char* label, int* v, int components, ImGuiInputTextFlags extra_flags); IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format); IMGUI_API void ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags); From 069b284f17ed739988dcaa46d258896d9e422796 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 May 2018 20:22:29 +0200 Subject: [PATCH 10/22] Internals: Tidying up internal helpers. Fixed a case ImParseFormatTrimDecorations() can return an off by one (out of bound) pointer if the format string is invalid. Extracted ImParseFormatFindEnd() out of TrimDecorations so we can use it to find the format type and replace the %f in old Int apis. --- imgui.cpp | 60 ++++++++++++++++++++++++++---------------------- imgui_internal.h | 9 ++++---- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 54a107ef9..9cce29400 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8631,7 +8631,7 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const c char fmt_buf[32]; char data_buf[32]; - format = ParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf)); + format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf)); DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, data_ptr, format); ImStrTrimBlanks(data_buf); ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal); @@ -8647,7 +8647,8 @@ bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const c return false; } -const char* ImGui::ParseFormatTrimDecorationsLeading(const char* fmt) +// We don't use strchr() because our strings are usually very short and often start with '%' +const char* ImParseFormatFindStart(const char* fmt) { while (char c = fmt[0]) { @@ -8660,36 +8661,44 @@ const char* ImGui::ParseFormatTrimDecorationsLeading(const char* fmt) return fmt; } +const char* ImParseFormatFindEnd(const char* fmt) +{ + // Printf/scanf types modifiers: I/L/h/j/l/t/w/z. Other uppercase letters qualify as types aka end of the format. + IM_ASSERT(fmt[0] == '%'); + const unsigned int ignored_uppercase_mask = (1 << ('I'-'A')) | (1 << ('L'-'A')); + const unsigned int ignored_lowercase_mask = (1 << ('h'-'a')) | (1 << ('j'-'a')) | (1 << ('l'-'a')) | (1 << ('t'-'a')) | (1 << ('w'-'a')) | (1 << ('z'-'a')); + for (char c; (c = *fmt) != 0; fmt++) + { + if (c >= 'A' && c <= 'Z' && ((1 << (c - 'A')) & ignored_uppercase_mask) == 0) + return fmt + 1; + if (c >= 'a' && c <= 'z' && ((1 << (c - 'a')) & ignored_lowercase_mask) == 0) + return fmt + 1; + } + return 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) +const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, int buf_size) { - // We don't use strchr() because our strings are usually very short and often start with '%' - const char* fmt_start = ParseFormatTrimDecorationsLeading(fmt); + const char* fmt_start = ImParseFormatFindStart(fmt); if (fmt_start[0] != '%') return fmt; - fmt = fmt_start; - while (char c = *fmt++) - { - 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. + const char* fmt_end = ImParseFormatFindEnd(fmt_start); + if (fmt_end[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)); + ImStrncpy(buf, fmt_start, ImMin((int)(fmt_end + 1 - fmt_start), buf_size)); return buf; } // Parse display precision back from the display format string // FIXME: This is still used by some navigation code path to infer a minimum tweak step, but we should aim to rework widgets so it isn't needed. -int ImGui::ParseFormatPrecision(const char* fmt, int default_precision) +int ImParseFormatPrecision(const char* fmt, int default_precision) { - fmt = ParseFormatTrimDecorationsLeading(fmt); + fmt = ImParseFormatFindStart(fmt); if (fmt[0] != '%') return default_precision; fmt++; @@ -8717,13 +8726,6 @@ static float GetMinimumStepAtDecimalPrecision(int decimal_precision) return (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : powf(10.0f, (float)-decimal_precision); } -float ImGui::RoundScalarWithFormat(const char* format, float value) -{ - char buf[64]; - ImFormatString(buf, IM_ARRAYSIZE(buf), ParseFormatTrimDecorationsLeading(format), value); - return (float)atof(buf); -} - static inline float SliderBehaviorCalcRatioFromValue(float v, float v_min, float v_max, float power, float linear_zero_pos) { if (v_min == v_max) @@ -8762,7 +8764,7 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v const bool is_non_linear = (power < 1.0f-0.00001f) || (power > 1.0f+0.00001f); const bool is_horizontal = (flags & ImGuiSliderFlags_Vertical) == 0; - const bool is_decimal = ParseFormatPrecision(format, 3) != 0; + const bool is_decimal = ImParseFormatPrecision(format, 3) != 0; const float grab_padding = 2.0f; const float slider_sz = is_horizontal ? (frame_bb.GetWidth() - grab_padding * 2.0f) : (frame_bb.GetHeight() - grab_padding * 2.0f); @@ -8877,7 +8879,9 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v } // Round past decimal precision - new_value = RoundScalarWithFormat(format, new_value); + char buf[64]; + ImFormatString(buf, IM_ARRAYSIZE(buf), ImParseFormatFindStart(format), new_value); + new_value = (float)atof(buf); if (*v != new_value) { *v = new_value; @@ -9155,7 +9159,7 @@ static bool ImGui::DragBehaviorT(ImGuiID id, ImGuiDataType data_type, TYPE* v, f } if (g.ActiveIdSource == ImGuiInputSource_Nav) { - int decimal_precision = ParseFormatPrecision(format, 3); + int decimal_precision = ImParseFormatPrecision(format, 3); adjust_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard|ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 1.0f/10.0f, 10.0f).x; v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision)); } @@ -9198,7 +9202,7 @@ static bool ImGui::DragBehaviorT(ImGuiID id, ImGuiDataType data_type, TYPE* v, f // Round to user desired precision based on format string char v_str[64]; - ImFormatString(v_str, IM_ARRAYSIZE(v_str), ParseFormatTrimDecorationsLeading(format), v_cur); + ImFormatString(v_str, IM_ARRAYSIZE(v_str), ImParseFormatFindStart(format), v_cur); if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) v_cur = (TYPE)atof(v_str); else diff --git a/imgui_internal.h b/imgui_internal.h index f612c8af9..3cd5cc1bf 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -121,6 +121,10 @@ IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end IMGUI_API void ImStrTrimBlanks(char* str); IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3); IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3); +IMGUI_API const char* ImParseFormatFindStart(const char* format); +IMGUI_API const char* ImParseFormatFindEnd(const char* format); +IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, int buf_size); +IMGUI_API int ImParseFormatPrecision(const char* format, int default_value); // Helpers: Math // We are keeping those not leaking to the user by default, in the case the user has implicit cast operators between ImVec2 and its own types (when IM_VEC2_CLASS_EXTRA is defined) @@ -1118,11 +1122,6 @@ 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* ParseFormatTrimDecorationsLeading(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 RoundScalarWithFormat(const char* format, float value); - // Shade functions (write over already created vertices) IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawVert* vert_start, ImDrawVert* vert_end, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1); IMGUI_API void ShadeVertsLinearAlphaGradientForLeftToRightText(ImDrawVert* vert_start, ImDrawVert* vert_end, float gradient_p0_x, float gradient_p1_x); From 17d3c6305e798b28fda8598a7aa93dc520aebaec Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 May 2018 21:11:53 +0200 Subject: [PATCH 11/22] Ran a spell checker for sanity. --- CHANGELOG.txt | 129 +++++++++++++++++++++++++------------------------- README.md | 12 ++--- 2 files changed, 71 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index f197b3446..1a3aae0bf 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -49,14 +49,14 @@ Other Changes: - Settings: Fixed saving an empty .ini file if CreateContext/DestroyContext are called without a single call to NewFrame(). (#1741) - Window: Fixed default proportional item width lagging by one frame on resize. -- Window: Fixed popups/tooltips/menus not honoring style.DisplaySafeAreaPadding as well as it should have (part of menus displayed outside the safe area, etc.). +- Window: Fixed pop-ups/tooltips/menus not honoring style.DisplaySafeAreaPadding as well as it should have (part of menus displayed outside the safe area, etc.). - Window: Fixed windows using the ImGuiWindowFlags_NoSavedSettings flag from not using the same default position as other windows. (#1760) - Window: Relaxed the internal stack size checker to allow Push/Begin/Pop/.../End patterns to be used with PushStyleColor, PushStyleVar, PushFont without causing a false positive assert. (#1767) - Columns: Fixed a bug introduced in 1.51 where columns would affect the contents size of their container, often creating feedback loops when ImGuiWindowFlags_AlwaysAutoResize was used. (#1760) - MenuBar: Made BeginMainMenuBar() honor style.DisplaySafeAreaPadding so the text can be made visible on TV settings that don't display all pixels. (#1439) [@dougbinks] -- InputText: On Mac OS X, filter out characters when the Cmd modifier is held. (#1747) [@sivu] -- InputText: On Mac OS X, support Cmd+Shift+Z for Redo. Cmd+Y is also supported as major apps seems to default to support both. (#1765) [@lfnoise] -- InputText: Fixed returning true when edition is cancelled with Esc and the current buffer matches the initial value. +- InputText: On Mac OS X, filter out characters when the CMD modifier is held. (#1747) [@sivu] +- InputText: On Mac OS X, support CMD+SHIFT+Z for Redo. CMD+Y is also supported as major apps seems to default to support both. (#1765) [@lfnoise] +- InputText: Fixed returning true when edition is canceled with ESC and the current buffer matches the initial value. - 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). @@ -65,7 +65,8 @@ Other Changes: - DragFloat, SliderFloat: Rounding-on-write uses the provided format string instead of parsing the precision from the string, which allows for finer uses of %e %g etc. (#648, #642) - DragFloat: Improved computation when using the power curve. Improved lost of input precision with very small steps. Added an assert than power-curve requires a min/max range. (~#642) - DragFloat: The 'power' parameter is only honored if the min/max parameter are also setup. -- Nav: Fixed hovering a Selectable() with the mouse so that it update the navigation cursor (as it happened in the pre 1.60 navigation branch). (#787) +- DragInt: Fixed handling of large integers (we previously passed data around internally as float, which reduced the range of valid integers). +- Nav: Fixed hovering a Selectable() with the mouse so that it update the navigation cursor (as it happened in the pre-1.60 navigation branch). (#787) - 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. @@ -82,15 +83,15 @@ Decorated log: https://github.com/ocornut/imgui/releases/tag/v1.60 The gamepad/keyboard navigation branch (which has been in the work since July 2016) has been merged. Gamepad/keyboard navigation is still marked as Beta and has to be enabled explicitly. -Various internal refactors have also been done, as part of the navigation work and as part of the upcoming viewport/docking work. +Various internal refactoring have also been done, as part of the navigation work and as part of the upcoming viewport/docking work. Breaking Changes: - Obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render(). - e.g. with example back-ends, call ImDrawData* draw_data = ImGui::GetDrawData(); ImGui_ImplXXXX_RenderDrawData(draw_data). + e.g. with example backends, call ImDrawData* draw_data = ImGui::GetDrawData(); ImGui_ImplXXXX_RenderDrawData(draw_data). - Reorganized context handling to be more explicit: (#1599) - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END. - - removed Shutdown() function, as DestroyContext() serve this purpose. If you are using an old back-end from the examples/ folder, remove the line that calls Shutdown(). + - removed Shutdown() function, as DestroyContext() serve this purpose. If you are using an old backend from the examples/ folder, remove the line that calls Shutdown(). - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance. - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts. - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts. @@ -132,23 +133,23 @@ Other Changes: - Context: Added SetAllocatorFunctions() to rewire memory allocators (as a replacement to previous parameters to CreateContext()). Allocators are shared by all contexts and imgui helpers. (#1565, #586, #992, #1007, #1558) - Context: You may pass a ImFontAtlas to CreateContext() to specify a font atlas to share. Shared font atlas are not owned by the context and not destroyed along with it. (#1599) - Context: Added IMGUI_DISABLE_DEFAULT_ALLOCATORS to disable linking with malloc/free. (#1565, #586, #992, #1007, #1558) -- IO: Added io.ConfigFlags for user application to store settings for imgui and for the back-end: +- IO: Added io.ConfigFlags for user application to store settings for imgui and for the backend: - ImGuiConfigFlags_NavEnableKeyboard: Enable keyboard navigation. - - ImGuiConfigFlags_NavEnableGamepad: Enable gamepad navigation (provided ImGuiBackendFlags_HasGamepad is also set by back-end). + - ImGuiConfigFlags_NavEnableGamepad: Enable gamepad navigation (provided ImGuiBackendFlags_HasGamepad is also set by backend). - ImGuiConfigFlags_NavEnableSetMousePos: Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. - - ImGuiConfigFlags_NoMouseCursorChange: Instruct back-end to not alter mouse cursor shape and visibility (by default the example back-end use mouse cursor API of the platform when available) - - ImGuiConfigFlags_NoMouse: Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information passed by the back-end. + - ImGuiConfigFlags_NoMouseCursorChange: Instruct backend to not alter mouse cursor shape and visibility (by default the example backend use mouse cursor API of the platform when available) + - ImGuiConfigFlags_NoMouse: Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information passed by the backend. - ImGuiConfigFlags_IsSRGB, ImGuiConfigFlags_IsTouchScreen: Flags for general application use. -- IO: Added io.BackendFlags for back-end to store its capabilities (currently: _HasGamepad, _HasMouseCursors, _HasSetMousePos). This will be used more in the next version. +- IO: Added io.BackendFlags for backend to store its capabilities (currently: _HasGamepad, _HasMouseCursors, _HasSetMousePos). This will be used more in the next version. - IO: Added ImGuiKey_Insert, ImGuiKey_Space keys. Setup in all example bindings. (#1541) - IO: Added Horizontal Mouse Wheel support for horizontal scrolling. (#1463) [@tseeker] - IO: Added IsAnyMouseDown() helper which is helpful for bindings to handle mouse capturing. - Window: Clicking on a window with the ImGuiWIndowFlags_NoMove flags takes an ActiveId so we can't hover something else when dragging afterwards. (#1381, #1337) - Window: IsWindowHovered(): Added ImGuiHoveredFlags_AnyWindow, ImGuiFocusedFlags_AnyWindow flags (See Breaking Changes). Added to demo. (#1382) -- Window: Added SetNextWindowBgAlpha() helper. Particularly helpul since the legacy 5-parameters version of Begin() has been marked as obsolete in 1.53. (#1567) +- Window: Added SetNextWindowBgAlpha() helper. Particularly helpful since the legacy 5-parameters version of Begin() has been marked as obsolete in 1.53. (#1567) - Window: Fixed SetNextWindowContentSize() with 0.0f on Y axis (or SetNextWindowContentWidth()) overwriting the contents size. Got broken on Dec 10 (1.53). (#1363) - ArrowButton: Added ArrowButton() given a cardinal direction (e.g. ImGuiDir_Left). -- InputText: Added alternative clipboard shortcuts: Shift+Delete (cut), Ctrl+Insert (copy), Shift+Insert (paste). (#1541) +- InputText: Added alternative clipboard shortcuts: Shift+Delete (cut), CTRL+Insert (copy), Shift+Insert (paste). (#1541) - InputText: Fixed losing Cursor X position when clicking outside on an item that's submitted after the InputText(). It was only noticeable when restoring focus programmatically. (#1418, #1554) - InputText: Added ImGuiInputTextFlags_CharsScientific flag to also allow 'e'/'E' for input of values using scientific notation. Automatically used by InputFloat. - Style: Default style is now StyleColorsDark(), instead of the old StyleColorsClassic(). (#707) @@ -156,7 +157,7 @@ Other Changes: - Style: Exposed ImGuiStyleVar_WindowTitleAlign, ImGuiStyleVar_ScrollbarSize, ImGuiStyleVar_ScrollbarRounding, ImGuiStyleVar_GrabRounding + added an assert to reduce accidental breakage. (#1181) - Style: Added style.MouseCursorScale help when using the software mouse cursor facility. (#939). - Style: Close button nows display a cross before hovering. Fixed cross positioning being a little off. Uses button colors for highlight when hovering. (#707) -- Popup: OpenPopup() Always reopen existing popup. (Removed imgui_internal.h's OpenPopupEx() which was used for this.) (#1497, #1533). +- Popup: OpenPopup() Always reopen existing pop-ups. (Removed imgui_internal.h's OpenPopupEx() which was used for this.) (#1497, #1533). - Popup: BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid(), OpenPopupOnItemClick() all react on mouse release instead of mouse press. (~#439) - Popup: Better handling of user mistakenly calling OpenPopup() every frame (with reopen_existing option). The error will now be more visible and easier to understand. (#1497) - Popup: BeginPopup(): Exposed extra_flags parameter that are passed through to Begin(). (#1533) @@ -190,7 +191,7 @@ Other Changes: - ImFontAtlas: Moved mouse cursor data out of ImGuiContext, fix drawing them with multiple contexts. Also remove the last remaining undesirable dependency on ImGui in imgui_draw.cpp. (#939) - ImFontAtlas: Added ImFontAtlasFlags_NoPowerOfTwoHeight flag to disable padding font height to nearest power of two. (#1613) - ImFontAtlas: Added ImFontAtlasFlags_NoMouseCursors flag to disable baking software mouse cursors, mostly to save texture memory on very low end hardware. (#1613) -- ImDrawList: Fixed AddRect() with antialiasing disabled (lower-right corner pixel was often missing, rounding looks a little better.) (#1646) +- ImDrawList: Fixed AddRect() with anti-aliasing disabled (lower-right corner pixel was often missing, rounding looks a little better.) (#1646) - ImDrawList: Added CloneOutput() helper to facilitate the cloning of ImDrawData or ImDrawList for multi-threaded rendering. - Misc: Functions passed to libc qsort are explicitly marked cdecl to support compiling with vectorcall as the default calling convention. (#1230, #1611) [@RandyGaul] - Misc: ImVec2: added [] operator. This is becoming desirable for some code working of either axes independently. Better adding it sooner than later. @@ -202,7 +203,7 @@ Other Changes: - Misc: Added IMGUI_USER_CONFIG to define a custom configuration filename. (#255, #1573, #1144, #41) - Misc: Added IMGUI_STB_TRUETYPE_FILENAME and IMGUI_STB_RECT_PACK_FILENAME compile time directives to use another version of the stb_ files. - Misc: Updated stb_rect_pack from 0.10 to 0.11 (minor changes). - (Those flags are not used by ImGui itself, they only exists to make it easy for the engine/back-end to pass information to the application in a standard manner.) + (Those flags are not used by ImGui itself, they only exists to make it easy for the engine/backend to pass information to the application in a standard manner.) - Metrics: Added display of Columns state. - Demo: Improved Selectable() examples. (#1528) - Demo: Tweaked the Child demos, added a menu bar to the second child to test some navigation functions. @@ -212,7 +213,7 @@ Other Changes: - Examples: Using Dark theme by default. (#707). Tweaked demo code. - Examples: Added support for horizontal mouse wheel for API that allows it. (#1463) [@tseeker] - Examples: All examples now setup the io.BackendFlags to signify they can honor mouse cursors, gamepad, etc. -- Examples: DirectX10: Fixed erroneous call to io.Fonts->ClearInputData() + ClearTexData() that was left in DX10 example but removed in 1.47 (Nov 2015) in every other back-ends. (#1733) +- Examples: DirectX10: Fixed erroneous call to io.Fonts->ClearInputData() + ClearTexData() that was left in DX10 example but removed in 1.47 (Nov 2015) in every other backends. (#1733) - Examples: DirectX12: Added DirectX 12 example. (#301) [@jdm3] - Examples: OpenGL3+GLFW,SDL: Changed GLSL shader version from 330 to 150. (#1466, #1504) - Examples: OpenGL3+GLFW,SDL: Added a way to override the GLSL version string in the Init function. (#1466, #1504). @@ -227,9 +228,9 @@ Other Changes: - Examples: GLFW: Don't attempt to change the mouse cursor input mode if it is set to GLFW_CURSOR_DISABLED by the application. (#1202) [@PhilCK] - Examples: SDL: Added support for mouse cursor shapes. (#1626) [@olls] - Examples: SDL: Using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging (SDL 2.0.4+ only, otherwise using SDL_WINDOW_INPUT_FOCUS instead of previously SDL_WINDOW_MOUSE_FOCUS). (#1559) -- Examples: SDL: Enabled vsync by default so people don't come at us with demoes running at 2000 FPS burning a cpu core. -- Examples: SDL: Using SDL_GetPerformanceCounter() / SDL_GetPerformanceFrequency() to handle framerate over 1000 FPS properly. (#996) -- Examples: SDL: Using scancode exclusively instead of a confusing mixture of scancodes and keycodes. +- Examples: SDL: Enabled vsync by default so people don't come at us when the examples are running at 2000 FPS and burning a CPU core. +- Examples: SDL: Using SDL_GetPerformanceCounter() / SDL_GetPerformanceFrequency() to handle frame-rate over 1000 FPS properly. (#996) +- Examples: SDL: Using scan-code exclusively instead of a confusing mixture of scan-codes and key-codes. - Examples: SDL: Visual Studio: Added .vcxproj file. Using %SDL2_DIR% in the default .vcxproj and build files instead of %SDL_DIR%, the earlier being more standard. - Examples: Vulkan: Visual Studio: Added .vcxproj file. - Examples: Apple: Fixed filenames in OSX xcode project. Various other Mac friendly fixes. [@gerryhernandez etc.] @@ -257,7 +258,7 @@ Breaking Changes: Use `ImGui::ShowStyleEditor()` to look them up. Please note that the style system will keep evolving (hopefully stabilizing in Q1 2018), and so custom styles will probably subtly break over time. It is recommended that you use the `StyleColorsClassic()`, `StyleColorsDark()`, `StyleColorsLight()` functions. Also see `ShowStyleSelector()`. -- Style: Removed `ImGuiCol_ComboBg` in favor of combo boxes using `ImGuiCol_PopupBg` for consistency. Combo are normal popups. +- Style: Removed `ImGuiCol_ComboBg` in favor of combo boxes using `ImGuiCol_PopupBg` for consistency. Combo are normal pop-ups. - Style: Renamed `ImGuiCol_ChildWindowBg` to `ImGuiCol_ChildBg`. - Style: Renamed `style.ChildWindowRounding` to `style.ChildRounding`, `ImGuiStyleVar_ChildWindowRounding` to `ImGuiStyleVar_ChildRounding`. - Removed obsolete redirection functions: SetScrollPosHere() - marked obsolete in v1.42, July 2015. @@ -288,11 +289,11 @@ Other Changes: - Style: Made the ScaleAllSizes() helper rounds down every values so they are aligned on integers. - Focus: Added SetItemDefaultFocus(), which in the current (master) branch behave the same as doing `if (IsWindowAppearing()) SetScrollHere()`. In the navigation branch this will also set the default focus. Prefer using this when creating combo boxes with `BeginCombo()` so your code will be forward-compatible with gamepad/keyboard navigation features. (#787) -- Combo: Popup grows horizontally to accomodate for contents that is larger then the parent combo button. +- Combo: Pop-up grows horizontally to accommodate for contents that is larger then the parent combo button. - Combo: Added BeginCombo()/EndCombo() API which allows use to submit content of any form and manage your selection state without relying on indices. -- Combo: Added ImGuiComboFlags_PopupAlignLeft flag to BeginCombo() to prioritize keeping the popup on the left side (for small-button-looking combos). -- Combo: Added ImGuiComboFlags_HeightSmall, ImGuiComboFlags_HeightLarge, ImGuiComboFlags_HeightLargest to easily provide desired popup height. -- Combo: You can use SetNextWindowSizeConstraints() before BeginCombo() to specify specific popup width/height constraints. +- Combo: Added ImGuiComboFlags_PopupAlignLeft flag to BeginCombo() to prioritize keeping the pop-up on the left side (for small-button-looking combos). +- Combo: Added ImGuiComboFlags_HeightSmall, ImGuiComboFlags_HeightLarge, ImGuiComboFlags_HeightLargest to easily provide desired pop-up height. +- Combo: You can use SetNextWindowSizeConstraints() before BeginCombo() to specify specific pop-up width/height constraints. - Combo: Offset popup position by border size so that a double border isn't so visible. (#707) - Combo: Recycling windows by using a stack number instead of a unique id, wasting less memory (like menus do). - InputText: Added ImGuiInputTextFlags_NoUndoRedo flag. (#1506, #1508) [@ibachar] @@ -303,11 +304,11 @@ Other Changes: - Window: Made it possible to use SetNextWindowPos() on a child window. - Window: Fixed a one frame glitch. When an appearing window claimed the focus themselves, the title bar wouldn't use the focused color for one frame. - Window: Added ImGuiWindowFlags_ResizeFromAnySide flag to resize from any borders or from the lower-left corner of a window. This requires your backend to honor GetMouseCursor() requests for full usability. (#822) -- Window: Sizing fixes when useing SetNextWindowSize() on individual axises. +- Window: Sizing fixes when using SetNextWindowSize() on individual axises. - Window: Hide new window for one frame until they calculate their size. Also fixes SetNextWindowPos() given a non-zero pivot. (#1694) -- Window: Made mouse wheel scrolling accomodate better to windows that are smaller than the scroll step. +- Window: Made mouse wheel scrolling accommodate better to windows that are smaller than the scroll step. - Window: SetNextWindowContentSize() adjust for the size of decorations (title bar/menu bar), but _not_ for borders are we consistently make borders not affect layout. - If you need a non-child window of an exact size with border enabled but zero window padding, you'll need to accodomate for the border size yourself. + If you need a non-child window of an exact size with border enabled but zero window padding, you'll need to accommodate for the border size yourself. - Window: Using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set. (#1380, #1502) - Window: Active Modal window always set the WantCaptureKeyboard flag. (#744) - Window: Moving window doesn't use accumulating MouseDelta so straying out of imgui boundaries keeps moved imgui window at the same cursor-relative position. @@ -320,7 +321,7 @@ Other Changes: - IsWindowHovered(): Always return true when current window is being moved. (#1382) - Scrollbar: Fixed issues with vertical scrollbar flickering/appearing, typically when manually resizing and using a pattern of filling available height (e.g. full sized BeginChild). - Scrollbar: Minor graphical fix for when scrollbar don't have enough visible space to display the full grab. -- Scrolling: Fixed padding and scrolling asymetry where lower/right sides of a window wouldn't use WindowPadding properly + causing minor scrolling glitches. +- Scrolling: Fixed padding and scrolling asymmetry where lower/right sides of a window wouldn't use WindowPadding properly + causing minor scrolling glitches. - Tree: TreePush with zero arguments was ambiguous. Resolved by making it call TreePush(const void*). [@JasonWilkins] - Tree: Renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. (#600, #1330) - MenuBar: Fixed minor rendering issues on the right size when resizing a window very small and using rounded window corners. @@ -331,19 +332,19 @@ Other Changes: - Columns: Columns width is no longer lost when dragging a column to the right side of the window, until releasing the mouse button you have a chance to save them. (#1499, #125). [@ggtucker] - Columns: Fixed dragging when using a same of columns multiple times in the frame. (#125) - Indent(), Unindent(): Allow passing negative values. -- ColorEdit4(): Made IsItemActive() return true when picker popup is active. (#1489) +- ColorEdit4(): Made IsItemActive() return true when picker pop-up is active. (#1489) - ColorEdit4(): Tweaked tooltip so that the color button aligns more correctly with text. - ColorEdit4(): Support drag and drop. Color buttons can be used as drag sources, and ColorEdit widgets as drag targets. (#143) -- ColorPicker4(): Fixed continously returning true when holding mouse button on the sat/value/alpha locations. We only return true on value change. (#1489) +- ColorPicker4(): Fixed continuously returning true when holding mouse button on the sat/value/alpha locations. We only return true on value change. (#1489) - NewFrame(): using literal strings in the most-frequently firing IM_ASSERT expressions to increase the odd of programmers seeing them (especially those who don't use a debugger). - NewFrame() now asserts if neither Render or EndFrame have been called. Exposed EndFrame(). Made it legal to call EndFrame() more than one. (#1423) -- ImGuiStorage: Added BuildSortByKey() helper to rebuild storage from stratch. +- ImGuiStorage: Added BuildSortByKey() helper to rebuild storage from scratch. - ImFont: Added GetDebugName() helper. - ImFontAtlas: Added missing Thai punctuation in the GetGlyphRangesThai() ranges. (#1396) [@nProtect] - ImDrawList: Removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Anti-aliasing is controlled via the regular style.AntiAliased flags. - ImDrawList: Added ImDrawList::AddImageRounded() helper. (#845) [@thedmd] -- ImDrawList: Refactored to make ImDrawList independant of ImGui. Removed static variable in PathArcToFast() which caused linking issues to some. -- ImDrawList: Exposed ImDrawCornerFlags, replaced occurences of ~0 with an explicit ImDrawCornerFlags_All. NB: Inversed BotLeft (prev 1<<3, now 1<<2) and BotRight (prev 1<<2, now 1<<3). +- ImDrawList: Refactored to make ImDrawList independent of ImGui. Removed static variable in PathArcToFast() which caused linking issues to some. +- ImDrawList: Exposed ImDrawCornerFlags, replaced occurrences of ~0 with an explicit ImDrawCornerFlags_All. NB: Inversed BotLeft (prev 1<<3, now 1<<2) and BotRight (prev 1<<2, now 1<<3). - ImVector: Added ImVector::push_front() helper. - ImVector: Added ImVector::contains() helper. - ImVector: insert() uses grow_capacity() instead of using grow policy inconsistent with push_back(). @@ -357,9 +358,9 @@ Other Changes: - Demo: Added ShowFontSelector() showing loaded fonts. - Demo: Added ShowStyleSelector() to select among default styles. (#707) - Demo: Renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). -- Demo: Style Editor: Added a "Simplified settings" sections with checkboxes for border size and frame rounding. (#707, #1019) +- Demo: Style Editor: Added a "Simplified settings" sections with check-boxes for border size and frame rounding. (#707, #1019) - Demo: Style Editor: Added combo box to select stock styles and select current font when multiple are loaded. (#707) -- Demo: Style Editor: Using local storage so Save/Revert button makes more sense without code passing its storage. Aadded horizontal scroll bar. Fixed Save/Revert button to be always accessible. (#1211) +- Demo: Style Editor: Using local storage so Save/Revert button makes more sense without code passing its storage. Added horizontal scroll bar. Fixed Save/Revert button to be always accessible. (#1211) - Demo: Console: Fixed context menu issue. (#1404) - Demo: Console: Fixed incorrect positioning which was hidden by a minor scroll issue (this would affect people who copied the Console code as is). - Demo: Constrained Resize: Added more test cases. (#1417) @@ -396,7 +397,7 @@ Other Changes: - Combo, InputFloat, InputInt: Made the small button on the right side align properly with the equivalent colored button of ColorEdit4(). - IO: Tweaked logic for `io.WantCaptureMouse` so it now outputs false when e.g. hovering over void while an InputText() is active. (#621) [@pdoane] - IO: Fixed `io.WantTextInput` from mistakenly outputting true when an activated Drag or Slider was previously turned into an InputText(). (#1317) -- Misc: Added flags to `IsItemHovered()`, `IsWindowHovered()` to access advanced hovering-test behavior. Generally useful for popups and drag'n drop behaviors: (relates to ~#439, #1013, #143, #925) +- Misc: Added flags to `IsItemHovered()`, `IsWindowHovered()` to access advanced hovering-test behavior. Generally useful for pop-ups and drag and drop behaviors: (relates to ~#439, #1013, #143, #925) - `ImGuiHoveredFlags_AllowWhenBlockedByPopup` - `ImGuiHoveredFlags_AllowWhenBlockedByActiveItem` - `ImGuiHoveredFlags_AllowWhenOverlapped` @@ -404,10 +405,10 @@ Other Changes: - Input: Added `IsMousePosValid()` helper. - Input: Added `GetKeyPressedAmount()` to easily measure press count when the repeat rate is faster than the frame rate. - Input/Focus: Disabled TAB and Shift+TAB when CTRL key is held. -- Checkbox: Now rendering a tick mark instead of a full square. +- CheckBox: Now rendering a tick mark instead of a full square. - ColorEdit4: Added "Copy as..." option in context menu. (#346) - ColorPicker: Improved ColorPicker hue wheel color interpolation. (#1313) [@thevaber] -- ColorButton: Reduced bordering artefact that would be particularly visible with an opaque Col_FrameBg and FrameRounding enabled. +- ColorButton: Reduced bordering artifact that would be particularly visible with an opaque Col_FrameBg and FrameRounding enabled. - ColorButton: Fixed rendering color button with a checkerboard if the transparency comes from the global style.Alpha and not from the actual source color. - TreeNode: Added `ImGuiTreeNodeFlags_FramePadding` flag to conveniently create a tree node with full padding at the beginning of a line, without having to call `AlignTextToFramePadding()`. - Trees: Fixed calling `SetNextTreeNodeOpen()` on a collapsed window leaking to the first tree node item of the next frame. @@ -420,7 +421,7 @@ Other Changes: - Windows: Fixed calling `Begin()` more than once per frame setting `window_just_activated_by_user` which in turn would set enable the Appearing condition for that frame. - Windows: The implicit "Debug" window now uses a "Debug##Default" identifier instead of "Debug" to allow user creating a window called "Debug" without losing their custom flags. - Windows: Made the `ImGuiWindowFlags_NoMove` flag properly inherited from parent to child. In a setup with ParentWindow (no flag) -> Child (NoMove) -> SubChild (no flag), the user won't be able to move the parent window by clicking on SubChild. (#1381) -- Popups: Popups can be closed with a right-click anywhere, without altering focus under the popup. (~#439) +- Popups: Pop-ups can be closed with a right-click anywhere, without altering focus under the pop-up. (~#439) - Popups: `BeginPopupContextItem()`, `BeginPopupContextWindow()` are now setup to allow reopening a context menu by right-clicking again. (~#439) - Popups: `BeginPopupContextItem()` now supports a NULL string identifier and uses the last item ID if available. - Popups: Added `OpenPopupOnItemClick()` helper which mimic `BeginPopupContextItem()` but doesn't do the BeginPopup(). @@ -463,7 +464,7 @@ Beta Navigation Branch: - Nav: MainMenuBar now releases focus when user gets out of the menu layer. (#787) - Nav: When applying focus to a window with only menus, the menu layer is automatically activated. (#787) - Nav: Added `ImGuiNavInput_KeyMenu` (~Alt key) aside from ImGuiNavInput_PadMenu input as it is one differentiator of pad vs keyboard that was detrimental to the keyboard experience. Although isn't officially supported, it makes the current experience better. (#787) -- Nav: Move requests now wrap vertically inside Menus and Popups. (#787) +- Nav: Move requests now wrap vertically inside Menus and Pop-ups. (#787) - Nav: Allow to collapse tree nodes with NavLeft and open them with NavRight. (#787, #1079). - Nav: It's now possible to navigate sibling of a menu-bar while navigating inside one of their child. If a Left<>Right navigation request fails to find a match we forward the request to the root menu. (#787, #126) - Nav: Fixed `SetItemDefaultFocus` from stealing default focus when we are initializing default focus for a menu bar layer. (#787) @@ -490,7 +491,7 @@ Work on dear imgui has been gradually resuming. It means that fixes and new feat - Renamed `ImGuiCol_Columns***` enums to `ImGuiCol_Separator***`. Kept redirection enums (will obsolete). - Renamed `ImGuiSetCond***` types and enums to `ImGuiCond***`. Kept redirection enums (will obsolete). - Renamed `GetStyleColName()` to `GetStyleColorName()` for consistency. Unlikely to be used by end-user! -- Added `PushStyleColor(ImGuiCol idx, ImU32 col)` overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix. +- Added `PushStyleColor(ImGuiCol idx, ImU32 col)` overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicitly to fix. - Marked the weird `IMGUI_ONCE_UPON_A_FRAME` helper macro as obsolete. Prefer using the more explicit `ImGuiOnceUponAFrame`. - Changed `ColorEdit4(const char* label, float col[4], bool show_alpha = true)` signature to `ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)`, where flags 0x01 is a safe no-op (hello dodgy backward compatibility!). The new `ColorEdit4`/`ColorPicker4` functions have lots of available flags! Check and run the demo window, under "Color/Picker Widgets", to understand the various new options. - Changed signature of `ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)` to `ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0))`. This function was rarely used and was very dodgy (no explicit ID!). @@ -521,15 +522,15 @@ Other Changes: - Columns: Dragging a column preserve its width by default. (#913) [@ggtucker] - Columns: Fixed first column appearing wider than others. (#1266) - Columns: Fixed allocating space on the right-most side with the assumption of a vertical scrollbar. The space is only allocated when needed. (#125, #913, #893, #1138) -- Columns: Fixed the right-most column from registering its content width to the parent window, which led to various issues when using auto-resizing window or e.g. horizonal scrolling. (#519, #125, #913) +- Columns: Fixed the right-most column from registering its content width to the parent window, which led to various issues when using auto-resizing window or e.g. horizontal scrolling. (#519, #125, #913) - Columns: Refactored some of the columns code internally toward a better API (not yet exposed) + minor optimizations. (#913) [@ggtucker, @ocornut] -- Popups: Most popups windows can be moved by the user after appearing (if they don't have explicit positions provided by caller, or e.g. sub-menu popup). The previous restriction was totally arbitrary. (#1252) +- Popups: Most pop-ups windows can be moved by the user after appearing (if they don't have explicit positions provided by caller, or e.g. sub-menu pop-up). The previous restriction was totally arbitrary. (#1252) - Tooltip: `SetTooltip()` is expanded immediately into a window, honoring current font / styling setting. Add internal mechanism to override tooltips. (#862) - PlotHistogram: bars are drawn based on zero-line, so negative values are going under. (#828) - Scrolling: Fixed return values of `GetScrollMaxX()`, `GetScrollMaxY()` when both scrollbars were enabled. Tweak demo to display more data. (#1271) [@degracode] - Scrolling: Fixes for Vertical Scrollbar not automatically getting enabled if enabled Horizontal Scrollbar straddle the vertical limit. (#1271, #246) - Scrolling: `SetScrollHere()`, `SetScrollFromPosY()`: Fixed Y scroll aiming when Horizontal Scrollbar is enabled. (#665). -- [Windows] Clipboard: Fixed not closing win32 clipboard on early open failure path. (#1264) +- [Windows] Clipboard: Fixed not closing Win32 clipboard on early open failure path. (#1264) - Removed an unnecessary dependency on int64_t which failed on some older compilers. - Demo: Rearranged everything under Widgets in a more consistent way. - Demo: Columns: Added Horizontal Scrolling demo. Tweaked another Columns demo. (#519, #125, #913) @@ -558,7 +559,7 @@ Other Changes: - InputText(): Got rid of individual OSX-specific options in ImGuiIO, added a single io.OSXBehaviors flag. (#473, #650) - InputText(): Fixed pressing home key on last character when it isn't a trailing \n (#588, #815) - InputText(): Fixed state corruption/crash bug in stb_textedit.h redo logic when exhausting undo/redo char buffer. (#715. #681) -- InputTextMultiline(): Fixed Ctrl+DownArrow moving scrolling out of bounds. +- InputTextMultiline(): Fixed CTRL+DownArrow moving scrolling out of bounds. - InputTextMultiline(): Scrollbar fix for when input and latched internal buffers differs in a way that affects vertical scrollbar existence. (#725) - ImFormatString(): Fixed an overflow handling bug with implementation of vsnprintf() that do not return -1. (#793) - BeginChild(const char*) now applies stack id to provided label, consistent with other widgets. (#894, #713) @@ -585,7 +586,7 @@ Other Changes: - Word-wrapping: Fixed a bug where we never wrapped after a 1 character word. [@sronsse] - Word-wrapping: Fixed TextWrapped() overriding wrap position if one is already set. (#690) - Word-wrapping: Fixed incorrect testing for negative wrap coordinates, they are perfectly legal. (#706) -- ImGuiListClipper: fixed automatic-height calc path dumbly having user display element 0 twice. (#661, #716) +- ImGuiListClipper: Fixed automatic-height calc path dumbly having user display element 0 twice. (#661, #716) - ImGuiListClipper: Fix to behave within column. (#661, #662, #716) - ImDrawList: Renamed ImDrawList::PathFill() to ImDrawList::PathFillConvex() for clarity. (BREAKING API) - Columns: End() avoid calling Columns(1) if no columns set is open, not sure why it wasn't the case already (pros: faster, cons: exercise less code). @@ -641,7 +642,7 @@ Breaking Changes: - Renamed `SetNextTreeNodeOpened()` to `SetNextTreeNodeOpen()` for consistency, no redirection. - Removed confusing set of `GetInternalState()`, `GetInternalStateSize()`, `SetInternalState()` functions. Now using `CreateContext()`, `DestroyContext()`, `GetCurrentContext()`, `SetCurrentContext()`. If you were using multiple contexts the change should be obvious and trivial. - Obsoleted old signature of `CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false)`, as extra parameters were badly designed and rarely used. Most uses were using 1 parameter and shouldn't affect you. You can replace the "default_open = true" flag in new API with `CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen)`. -- Changed `ImDrawList::PushClipRect(ImVec4 rect)` to `ImDraw::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false)`. Note that higher-level `ImGui::PushClipRect()` is preferable because it will clip at logic/widget level, whereas `ImDrawList::PushClipRect()` only affect your renderer. +- Changed `ImDrawList::PushClipRect(ImVec4 rect)` to `ImDraw::PushClipRect(ImVec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false)`. Note that higher-level `ImGui::PushClipRect()` is preferable because it will clip at logic/widget level, whereas `ImDrawList::PushClipRect()` only affect your renderer. - Title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore (see #655). If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you. However if your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar. This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color. (Or If this is confusing, just pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color.) @@ -659,7 +660,7 @@ Other changes: - Added PushClipRect()/PopClipRect() (previously part of imgui_internal.h). Changed ImDrawList::PushClipRect() prototype. (#610) - Added IsRootWindowOrAnyChildHovered() helper. (#615) - Added TreeNodeEx() functions. (#581, #600, #190) -- Added ImGuiTreeNodeFlags_Selected flag to display treenode as "selected". (#581, #190) +- Added ImGuiTreeNodeFlags_Selected flag to display TreeNode as "selected". (#581, #190) - Added ImGuiTreeNodeFlags_AllowOverlapMode flag. (#600) - Added ImGuiTreeNodeFlags_NoTreePushOnOpen flag (#590). - Added ImGuiTreeNodeFlags_NoAutoOpenOnLog flag (previously private). @@ -676,9 +677,9 @@ Other changes: - Fixed MenuBar missing lower border when borders are enabled. - InputText(): Fixed clipping of cursor rendering in case it gets out of the box (which can be forced w/ ImGuiInputTextFlags_NoHorizontalScroll. (#601) - Style: Changed default IndentSpacing from 22 to 21. (#581, #324) -- Style: Fixed TitleBg/TitleBgActive color being rendered above WindowBg color, which was inconsistent and causing visual artefact. (#655) +- Style: Fixed TitleBg/TitleBgActive color being rendered above WindowBg color, which was inconsistent and causing visual artifact. (#655) This broke the meaning of TitleBg and TitleBgActive. Only affect values where Alpha<1.0f. Fixed default theme. Read comments in "API BREAKING CHANGES" section to convert. -- Relative rendering of order of Child windows creation is preserved, to allow more control with overlapping childs. (#595) +- Relative rendering of order of Child windows creation is preserved, to allow more control with overlapping children. (#595) - Fixed GetWindowContentRegionMax() being off by ScrollbarSize amount when explicit SizeContents is set. - Indent(), Unindent(): optional non-default indenting width. (#324, #581) - Bullet(), BulletText(): Slightly bigger. Less polygons. @@ -687,8 +688,8 @@ Other changes: - BeginGroup(): fixed using within Columns set. (#630) - Fixed a lag in reading the currently hovered window when dragging a window. (#635) - Obsoleted 4 parameters version of CollapsingHeader(). Refactored code into TreeNodeBehavior. (#600, #579) -- Scrollbar: minor fix for top-right rounding of scrollbar background when window has menubar but no title bar. -- MenuItem(): checkmark render in disabled color when menu item is disabled. +- Scrollbar: minor fix for top-right rounding of scrollbar background when window has menu bar but no title bar. +- MenuItem(): the check mark renders in disabled color when menu item is disabled. - Fixed clipping rectangle floating point representation to ensure renderer-side float point operations yield correct results in typical DirectX/GL settings. (#582, 597) - Fixed GetFrontMostModalRootWindow(), fixing missing fade-out when a combo pop was used stacked over a modal window. (#604) - ImDrawList: Added AddQuad(), AddQuadFilled() helpers. @@ -697,7 +698,7 @@ Other changes: - ImFont: Added AddRemapChar() helper. (#609) - ImFontConfig: Clarified persistence requirement of GlyphRanges array. (#651) - ImGuiStorage: Added bool helper functions for completeness. -- AddFontFromMemoryCompressedTTF(): Fix font config propagation. (#587) +- AddFontFromMemoryCompressedTTF(): Fix ImFontConfig propagation. (#587) - Renamed majority of use of the word "opened" to "open" for clarity. Renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(). (#625, #579) - Examples: OpenGL3: Saving/restoring glActiveTexture() state. (#602) - Examples: DirectX9: save/restore all device state. @@ -705,7 +706,7 @@ Other changes: - Examples: DirectX10/X11: Apply depth-stencil state (no use of depth buffer). (#640, #636) - Examples: DirectX11/X11: Added comments on removing dependency on D3DCompiler. (#638) - Examples: SDL: Initialize video+timer subsystem only. -- Examples: Apple/iOS: lowered xcode project deployment target from 10.7 to 10.11. (#598, #575) +- Examples: Apple/iOS: lowered XCode project deployment target from 10.7 to 10.11. (#598, #575) ----------------------------------------------------------------------- @@ -715,7 +716,7 @@ Decorated log: https://github.com/ocornut/imgui/releases/tag/v1.48 Breaking Changes: - Consistently honoring exact width passed to PushItemWidth() (when positive), previously it would add extra FramePadding.x*2 over that width. Some hand-tuned layout may be affected slightly. (#346) -- Style: removed `style.WindowFillAlphaDefault` which was confusing and redundant, baked alpha into `ImGuiCol_WindowBg` color. If you had a custom WindowBg color but didn't change WindowFillAlphaDefault, multiply WindowBg alpha component by 0.7. Renamed `ImGuiCol_TooltipBg` to `ImGuiCol_PopupBG`, applies to other types of popups. `bg_alpha` parameter of 5-parameters version of Begin() is an override. (#337) +- Style: removed `style.WindowFillAlphaDefault` which was confusing and redundant, baked alpha into `ImGuiCol_WindowBg` color. If you had a custom WindowBg color but didn't change WindowFillAlphaDefault, multiply WindowBg alpha component by 0.7. Renamed `ImGuiCol_TooltipBg` to `ImGuiCol_PopupBG`, applies to other types of pop-ups. `bg_alpha` parameter of 5-parameters version of Begin() is an override. (#337) - InputText(): Added BufTextLen field in ImGuiTextEditCallbackData. Requesting user to update it if the buffer is modified in the callback. Added a temporary length-check assert to minimize panic for the 3 people using the callback. (#541) - Renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete). (#340) @@ -724,7 +725,7 @@ Other Changes: - Consistently honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. Some hand-tuned layout may be affected slightly. (#346) - Fixed clipping of child windows within parent not taking account of child outer clipping boundaries (including scrollbar, etc.). (#506) - TextUnformatted(): Fixed rare crash bug with large blurb of text (2k+) not finished with a '\n' and fully above the clipping Y line. (#535) -- IO: Added 'KeySuper' field to hold Cmd keyboard modifiers for OS X. Updated all examples accordingly. (#473) +- IO: Added 'KeySuper' field to hold CMD keyboard modifiers for OS X. Updated all examples accordingly. (#473) - Added ImGuiWindowFlags_ForceVerticalScrollbar, ImGuiWindowFlags_ForceHorizontalScrollbar flags. (#476) - Added IM_COL32 macros to generate a U32 packed color, convenient for direct use of ImDrawList api. (#346) - Added GetFontTexUvWhitePixel() helper, convenient for direct use of ImDrawList api. @@ -735,11 +736,11 @@ Other Changes: - Fixed InputTextMultiLine(), ListBox(), BeginChildFrame(), ProgressBar(): outer frame not honoring bordering. (#462, #503) - Fixed Image(), ImageButtion() rendering a rectangle 1 px too large on each axis. (#457) - SetItemAllowOverlap(): Promoted from imgui_internal.h to public imgui.h api. (#517) -- Combo(): Right-most button stays highlighted when popup is open. -- Combo(): Display popup above if there's isn't enough space below / or select largest side. (#505) +- Combo(): Right-most button stays highlighted when pop-up is open. +- Combo(): Display pop-up above if there's isn't enough space below / or select largest side. (#505) - DragFloat(), SliderFloat(), InputFloat(): fixed cases of erroneously returning true repeatedly after a text input modification (e.g. "0.0" --> "0.000" would keep returning true). (#564) - DragFloat(): Always apply value when mouse is held/widget active, so that an always-reseting variable (e.g. non saved local) can be passed. -- InputText(): OS X friendly behaviors: Word movement uses Alt key; Shortcuts uses Cmd key; Double-clicking text select a single word; Jumping to next word sets cursor to end of current word instead of beginning of current word. (@zhiayang), (#473) +- InputText(): OS X friendly behaviors: Word movement uses ALT key; Shortcuts uses CMD key; Double-clicking text select a single word; Jumping to next word sets cursor to end of current word instead of beginning of current word. (@zhiayang), (#473) - InputText(): Added BufTextLen in ImGuiTextEditCallbackData. Requesting user to maintain it if buffer is modified. Zero-ing structure properly before use. (#541) - CheckboxFlags(): Added support for testing/setting multiple flags at the same time. (@DMartinek) (#555) - TreeNode(), CollapsingHeader() fixed not being able to use "##" sequence in a formatted label. @@ -758,7 +759,7 @@ Other Changes: - ImDrawList: Allow AddText(ImFont\* font, float font_size, ...) variant to take NULL/0.0f as default. - ImFontAtlas: heuristic increase default texture width up for large number of glyphs. (#491) - ImTextBuffer: Fixed empty() helper which was utterly broken. -- Metrics: allow to inspect individual triangles in drawcalls. +- Metrics: allow to inspect individual triangles in draw calls. - Demo: added more draw primitives in the Custom Rendering example. (#457) - Demo: extra comments and example for PushItemWidth(-1) patterns. - Demo: InputText password demo filters out blanks. (#515) @@ -773,7 +774,7 @@ Other Changes: - Examples: SDL2+OpenGL3: Fix context creation options. Made ImGui_ImplSdlGL3_NewFrame() signature match GL2 one. (#468, #463) - Examples: SDL2+OpenGL2/3: Fix for high-dpi displays. (@nickgravelyn) - Various extra comments and clarification in the code. -- Various other fixes and optimisations. +- Various other fixes and optimizations. ----------------------------------------------------------------------- diff --git a/README.md b/README.md index ee1636919..76ca6dffd 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Dear ImGui is a bloat-free graphical user interface library for C++. It outputs Dear ImGui is designed to enable fast iterations and to empower programmers to create content creation tools and visualization / debug tools (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal, and lacks certain features normally found in more high-level libraries. -Dear ImGui is particularly suited to integration in games engine (for tooling), realtime 3D applications, fullscreen applications, embedded applications, or any applications on consoles platforms where operating system features are non-standard. +Dear ImGui is particularly suited to integration in games engine (for tooling), real-time 3D applications, fullscreen applications, embedded applications, or any applications on consoles platforms where operating system features are non-standard. Dear ImGui is self-contained within a few files that you can easily copy and compile into your application/engine: - imgui.cpp @@ -98,7 +98,7 @@ Demo Binaries You should be able to build the examples from sources (tested on Windows/Mac/Linux). If you don't, let me know! If you want to have a quick look at some Dear ImGui features, you can download Windows binaries of the demo app here: - [imgui-demo-binaries-20180407.zip](http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20180407.zip) (Windows binaries, Dear ImGui 1.60 built 2018/04/07, 5 executables) -The demo applications are unfortunately not yet DPI aware so expect some blurryness on a 4K screen. For DPI awareness you can load/reload your font at different scale, and scale your Style with `style.ScaleAllSizes()`. +The demo applications are unfortunately not yet DPI aware so expect some blurriness on a 4K screen. For DPI awareness you can load/reload your font at different scale, and scale your Style with `style.ScaleAllSizes()`. Bindings -------- @@ -204,7 +204,7 @@ The Immediate Mode GUI paradigm may at first appear unusual to some users. This - [A presentation by Rickard Gustafsson and Johannes Algelind](http://www.cse.chalmers.se/edu/year/2011/course/TDA361/Advanced%20Computer%20Graphics/IMGUI.pdf). - [Jari Komppa's tutorial on building an ImGui library](http://iki.fi/sol/imgui/). - [Casey Muratori's original video that popularized the concept](https://mollyrocket.com/861). -- [Nicolas Guillemot's CppCon'16 flashtalk about Dear ImGui](https://www.youtube.com/watch?v=LSRJ1jZq90k). +- [Nicolas Guillemot's CppCon'16 flash-talk about Dear ImGui](https://www.youtube.com/watch?v=LSRJ1jZq90k). - [Thierry Excoffier's Zero Memory Widget](http://perso.univ-lyon1.fr/thierry.excoffier/ZMW/). See the [Links page](https://github.com/ocornut/imgui/wiki/Links) for third-party bindings to different languages and frameworks. @@ -249,9 +249,9 @@ See the FAQ in imgui.cpp for answers. You can control Dear ImGui with a gamepad, see the explanation in imgui.cpp about how to use the navigation feature (short version: map your gamepad inputs into the `io.NavInputs[]` array and set `io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad`). -You can share your computer mouse seamlessy with your console/tablet/phone using [Synergy](http://synergy-project.org). This is the prefered solution for developer productivity. In particular, their [micro-synergy-client](https://github.com/symless/micro-synergy-client) repo there is _uSynergy.c_ sources for a small embeddable that you can use on any platform to connect to your host PC using Synergy 1.x. You may also use a third party solution such as [Remote ImGui](https://github.com/JordiRos/remoteimgui). +You can share your computer mouse seamlessly with your console/tablet/phone using [Synergy](http://synergy-project.org). This is the preferred solution for developer productivity. In particular, their [micro-synergy-client](https://github.com/symless/micro-synergy-client) repo there is _uSynergy.c_ sources for a small embeddable that you can use on any platform to connect to your host PC using Synergy 1.x. You may also use a third party solution such as [Remote ImGui](https://github.com/JordiRos/remoteimgui). -For touch inputs, you can increase the hit box of widgets (via the _style.TouchPadding_ setting) to accommodate a little for the lack of precision of touch inputs, but it is recommended you use a mouse or gamepad to allow optimising for screen real-estate and precision. +For touch inputs, you can increase the hit box of widgets (via the _style.TouchPadding_ setting) to accommodate a little for the lack of precision of touch inputs, but it is recommended you use a mouse or gamepad to allow optimizing for screen real-estate and precision. Can you create elaborate/serious tools with Dear ImGui? @@ -261,7 +261,7 @@ Dear ImGui is very programmer centric and the immediate-mode GUI paradigm might Can you reskin the look of Dear ImGui? -You can alter the look of the interface to some degree: changing colors, sizes, padding, rounding, fonts. However, as Dear ImGui is designed and optimised to create debug tools, the amount of skinning you can apply is limited. There is only so much you can stray away from the default look and feel of the interface. Below is a screenshot from [LumixEngine](https://github.com/nem0/LumixEngine) with custom colors + a docking/tabs extension (both of which you can find in the Issues section and will eventually be merged): +You can alter the look of the interface to some degree: changing colors, sizes, padding, rounding, fonts. However, as Dear ImGui is designed and optimized to create debug tools, the amount of skinning you can apply is limited. There is only so much you can stray away from the default look and feel of the interface. Below is a screenshot from [LumixEngine](https://github.com/nem0/LumixEngine) with custom colors + a docking/tabs extension (both of which you can find in the Issues section and will eventually be merged): ![LumixEngine](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v151/lumix-201710-rearranged.png) From 76404397472ab238bf00cdcdfdc6a6aadb75f30e Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 May 2018 21:28:59 +0200 Subject: [PATCH 12/22] DragInt: Patch old format strings to replace %f by %d when using the DragInt() entry point. (#320, #643, #708, #1011) --- CHANGELOG.txt | 4 ++++ TODO.txt | 2 +- imgui.cpp | 34 +++++++++++++++++++++++++++++++--- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 1a3aae0bf..a1b0a19a6 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -42,6 +42,10 @@ VERSION 1.61 WIP Breaking Changes: (IN PROGRESS, WILL ADD TO THIS LIST AS WE WORK ON 1.61) + - DragInt: The default compile-time format string has been changed from "%.0f" to "%d", we are not using integers internally any more. + If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format. + To honor backward-compatibility, the DragInt() code will currently parse and modify format strings to replace %*f with %d, giving time to users to upgrade their code. + If you have IMGUI_DISABLE_OBSOLETE_FUNCTIONS enabled, the code will instead assert! You may run a reg-exp search on your codebase for e.g. "DragInt.*%f" to you find them. - Misc: IM_DELETE() helper function added in 1.60 doesn't set the input pointer to NULL, more consistent with standard expectation and allows passing r-value. Other Changes: diff --git a/TODO.txt b/TODO.txt index 2ddd1cf90..9ba704fda 100644 --- a/TODO.txt +++ b/TODO.txt @@ -131,8 +131,8 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - slider: tint background based on value (e.g. v_min -> v_max, or use 0.0f either side of the sign) - slider: precision dragging - slider: step option (#1183) + - slider: int data passing through a float - knob: rotating knob widget (#942) - - slider & drag: int data passing through a float - drag float: up/down axis - drag float: added leeway on edge (e.g. a few invisible steps past the clamp limits) diff --git a/imgui.cpp b/imgui.cpp index 9cce29400..bdb11ce19 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -262,6 +262,10 @@ Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code. Also read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2018/05/03 (1.61) - DragInt: The default compile-time format string has been changed from "%.0f" to "%d", we are not using integers internally any more. + If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format. + To honor backward-compatibility, the DragInt() code will currently parse and modify format strings to replace %*f with %d, giving time to users to upgrade their code. + If you have IMGUI_DISABLE_OBSOLETE_FUNCTIONS enabled, the code will instead assert! You may run a reg-exp search on your codebase for e.g. "DragInt.*%f" to help you find them. - 2018/04/28 (1.61) - obsoleted InputFloat() functions taking an optional "int decimal_precision" in favor of an equivalent and more flexible "const char* format", consistent with other functions. Kept redirection functions (will obsolete). - 2018/04/09 (1.61) - IM_DELETE() helper function added in 1.60 doesn't clear the input _pointer_ reference, more consistent with expectation and allows passing r-value. - 2018/03/20 (1.60) - Renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some binding ahead of merging the Nav branch). @@ -8664,7 +8668,8 @@ const char* ImParseFormatFindStart(const char* fmt) const char* ImParseFormatFindEnd(const char* fmt) { // Printf/scanf types modifiers: I/L/h/j/l/t/w/z. Other uppercase letters qualify as types aka end of the format. - IM_ASSERT(fmt[0] == '%'); + if (fmt[0] != '%') + return fmt; const unsigned int ignored_uppercase_mask = (1 << ('I'-'A')) | (1 << ('L'-'A')); const unsigned int ignored_lowercase_mask = (1 << ('h'-'a')) | (1 << ('j'-'a')) | (1 << ('l'-'a')) | (1 << ('t'-'a')) | (1 << ('w'-'a')) | (1 << ('z'-'a')); for (char c; (c = *fmt) != 0; fmt++) @@ -9265,6 +9270,28 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_s return false; } +// FIXME-LEGACY: Prior to 1.61 our DragInt() function internally used floats and because of this the compile-time default value for format was "%.0f". +// Even though we changed the compile-time default, we expect users to have carried %f around, which would break DragInt() calls. +// To honor backward compatibility we are rewriting the format string, unless IMGUI_DISABLE_OBSOLETE_FUNCTIONS is enabled. Note that calling code has a fast-path that return "%d" if the string is "%.0f". +static const char* PatchFormatStringFloatToInt(const char* fmt) +{ + const char* fmt_start = ImParseFormatFindStart(fmt); + const char* fmt_end = ImParseFormatFindEnd(fmt_start); + if (fmt_end > fmt_start && fmt_end[-1] == 'f') + { +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (fmt_start == fmt && fmt_end[0] == 0) + return "%d"; + ImGuiContext& g = *GImGui; + ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%.*s%%d%s", (int)(fmt_start - fmt), fmt, fmt_end); // Honor leading and trailing decorations + return g.TempBuffer; +#else + IM_ASSERT(0 && "DragInt(): Invalid format string!"); // Old versions used a default parameter of "%.0f", please replace with e.g. "%d" +#endif + } + return fmt; +} + bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power) { ImGuiWindow* window = GetCurrentWindow(); @@ -9292,8 +9319,9 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa } const bool hovered = ItemHoverable(frame_bb, id); - if (!format) - format = "%.3f"; + // Patch old "%.0f" format string to use "%d", read function comments for more details. + if (data_type == ImGuiDataType_S32) + format = (strcmp(format, "%.0f") == 0) ? "%d" : PatchFormatStringFloatToInt(format); // Tabbing or CTRL-clicking on Drag turns it into an input box bool start_text_input = false; From 0699ae161ff80d1f2294c7ec12e6a6e02c95b8b7 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 May 2018 21:49:38 +0200 Subject: [PATCH 13/22] DragInt, DragScalar: Actually made the fast-past handle the now-most-common case.. --- imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui.cpp b/imgui.cpp index bdb11ce19..22d77b2da 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9320,7 +9320,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa const bool hovered = ItemHoverable(frame_bb, id); // Patch old "%.0f" format string to use "%d", read function comments for more details. - if (data_type == ImGuiDataType_S32) + if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) format = (strcmp(format, "%.0f") == 0) ? "%d" : PatchFormatStringFloatToInt(format); // Tabbing or CTRL-clicking on Drag turns it into an input box From f47c756755ecf2bdbfb7578567170bf687d57134 Mon Sep 17 00:00:00 2001 From: omar Date: Thu, 3 May 2018 21:53:26 +0200 Subject: [PATCH 14/22] Internals: Missing const, some renaming. Tweak legacy fast path. --- imgui.cpp | 26 ++++++++++++++------------ imgui_internal.h | 4 ++-- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 22d77b2da..2e723863f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9271,19 +9271,21 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_s } // FIXME-LEGACY: Prior to 1.61 our DragInt() function internally used floats and because of this the compile-time default value for format was "%.0f". -// Even though we changed the compile-time default, we expect users to have carried %f around, which would break DragInt() calls. -// To honor backward compatibility we are rewriting the format string, unless IMGUI_DISABLE_OBSOLETE_FUNCTIONS is enabled. Note that calling code has a fast-path that return "%d" if the string is "%.0f". +// Even though we changed the compile-time default, we expect users to have carried %f around, which would break the display of DragInt() calls. +// To honor backward compatibility we are rewriting the format string, unless IMGUI_DISABLE_OBSOLETE_FUNCTIONS is enabled. What could possibly go wrong?! static const char* PatchFormatStringFloatToInt(const char* fmt) { - const char* fmt_start = ImParseFormatFindStart(fmt); - const char* fmt_end = ImParseFormatFindEnd(fmt_start); + if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '0' && fmt[3] == 'f' && fmt[4] == 0) // Fast legacy path for "%.0f" which is expected to be the most common case. + return "%d"; + const char* fmt_start = ImParseFormatFindStart(fmt); // Find % (if any, and ignore %%) + const char* fmt_end = ImParseFormatFindEnd(fmt_start); // Find end of format specifier, which itself is an exercise of confidence/recklessness (because snprintf is dependent on libc or user). if (fmt_end > fmt_start && fmt_end[-1] == 'f') { #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS if (fmt_start == fmt && fmt_end[0] == 0) return "%d"; ImGuiContext& g = *GImGui; - ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%.*s%%d%s", (int)(fmt_start - fmt), fmt, fmt_end); // Honor leading and trailing decorations + ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%.*s%%d%s", (int)(fmt_start - fmt), fmt, fmt_end); // Honor leading and trailing decorations, but lose alignment/precision. return g.TempBuffer; #else IM_ASSERT(0 && "DragInt(): Invalid format string!"); // Old versions used a default parameter of "%.0f", please replace with e.g. "%d" @@ -9321,7 +9323,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa // Patch old "%.0f" format string to use "%d", read function comments for more details. if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) - format = (strcmp(format, "%.0f") == 0) ? "%d" : PatchFormatStringFloatToInt(format); + format = PatchFormatStringFloatToInt(format); // Tabbing or CTRL-clicking on Drag turns it into an input box bool start_text_input = false; @@ -10675,7 +10677,7 @@ bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, co } // NB: format here must be a simple "%xx" format string with no prefix/suffix (unlike the Drag/Slider functions "format" argument) -bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* format, ImGuiInputTextFlags extra_flags) +bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags extra_flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -10692,7 +10694,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p extra_flags |= ImGuiInputTextFlags_CharsDecimal; extra_flags |= ImGuiInputTextFlags_AutoSelectAll; - if (step_ptr) + if (step != NULL) { const float button_size = GetFrameHeight(); @@ -10707,13 +10709,13 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p SameLine(0, style.ItemInnerSpacing.x); if (ButtonEx("-", ImVec2(button_size, button_size), ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups)) { - DataTypeApplyOp(data_type, '-', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr); + DataTypeApplyOp(data_type, '-', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast ? step_fast : step); value_changed = true; } SameLine(0, style.ItemInnerSpacing.x); if (ButtonEx("+", ImVec2(button_size, button_size), ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups)) { - DataTypeApplyOp(data_type, '+', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr); + DataTypeApplyOp(data_type, '+', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast ? step_fast : step); value_changed = true; } SameLine(0, style.ItemInnerSpacing.x); @@ -10750,7 +10752,7 @@ bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiIn return InputScalar(label, ImGuiDataType_S32, (void*)v, (void*)(step>0 ? &step : NULL), (void*)(step_fast>0 ? &step_fast : NULL), format, extra_flags); } -bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, void* step_ptr, void* step_fast_ptr, const char* format, ImGuiInputTextFlags extra_flags) +bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags extra_flags) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -10765,7 +10767,7 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, in for (int i = 0; i < components; i++) { PushID(i); - value_changed |= InputScalar("##v", data_type, v, step_ptr, step_fast_ptr, format, extra_flags); + value_changed |= InputScalar("##v", data_type, v, step, step_fast, format, extra_flags); SameLine(0, g.Style.ItemInnerSpacing.x); PopID(); PopItemWidth(); diff --git a/imgui_internal.h b/imgui_internal.h index 3cd5cc1bf..f27f0a7a6 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1108,8 +1108,8 @@ namespace ImGui IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power = 1.0f); IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min, const void* v_max, const char* format, float power = 1.0f); - IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* v, void* step_ptr, void* step_fast_ptr, const char* format, ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, void* step_ptr, void* step_fast_ptr, const char* format, ImGuiInputTextFlags extra_flags = 0); + IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* v, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags extra_flags = 0); + IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags extra_flags = 0); IMGUI_API bool InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format); From dcd26f1295de206f5fcdd40959c1bbaa7608d9d8 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 4 May 2018 15:29:33 +0200 Subject: [PATCH 15/22] DragFloat, DragInt: Default format string is none is passed to the function. Fixed demo using old style %.0f. --- imgui.cpp | 5 ++++- imgui_demo.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 2e723863f..0bfd81c2f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -9321,8 +9321,11 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa } const bool hovered = ItemHoverable(frame_bb, id); + // Default format string when passing NULL // Patch old "%.0f" format string to use "%d", read function comments for more details. - if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) + if (format == NULL) + format = GDataTypeInfo[data_type].PrintFmt; + else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) format = PatchFormatStringFloatToInt(format); // Tabbing or CTRL-clicking on Drag turns it into an input box diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 59c958304..7150802a4 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -361,7 +361,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::DragInt("drag int", &i1, 1); ImGui::SameLine(); ShowHelpMarker("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input value."); - ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%.0f%%"); + ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%"); static float f1=1.00f, f2=0.0067f; ImGui::DragFloat("drag float", &f1, 0.005f); @@ -996,7 +996,7 @@ void ImGui::ShowDemoWindow(bool* p_open) static float begin = 10, end = 90; static int begin_i = 100, end_i = 1000; ImGui::DragFloatRange2("range", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%"); - ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %.0f units", "Max: %.0f units"); + ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units"); ImGui::TreePop(); } @@ -1371,9 +1371,9 @@ void ImGui::ShowDemoWindow(bool* p_open) static int track_line = 50, scroll_to_px = 200; ImGui::Checkbox("Track", &track); ImGui::PushItemWidth(100); - ImGui::SameLine(130); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line = %.0f"); + ImGui::SameLine(130); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line = %d"); bool scroll_to = ImGui::Button("Scroll To Pos"); - ImGui::SameLine(130); scroll_to |= ImGui::DragInt("##pos_y", &scroll_to_px, 1.00f, 0, 9999, "Y = %.0f px"); + ImGui::SameLine(130); scroll_to |= ImGui::DragInt("##pos_y", &scroll_to_px, 1.00f, 0, 9999, "Y = %d px"); ImGui::PopItemWidth(); if (scroll_to) track = false; From f4c16fbb995afacbf00f1c74fbd29192f02dc49b Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 4 May 2018 15:31:17 +0200 Subject: [PATCH 16/22] Internals: Data types: Made format string optional. DragBehavior: Moved a bit of code outside of the template. Slider tidying up. Removed unnecessary call to fabsf(). --- imgui.cpp | 123 +++++++++++++++++++++++++---------------------- imgui_demo.cpp | 2 +- imgui_internal.h | 9 ++-- 3 files changed, 70 insertions(+), 64 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0bfd81c2f..78b8562b6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -713,6 +713,15 @@ #define IMGUI_CDECL #endif +static const ImS32 IM_S32_MIN = 0x80000000; // INT_MIN; +static const ImS32 IM_S32_MAX = 0x7FFFFFFF; // INT_MAX; +static const ImU32 IM_U32_MIN = 0; +static const ImU32 IM_U32_MAX = 0xFFFFFFFF; +static const ImS64 IM_S64_MIN = -9223372036854775807ll - 1ll; +static const ImS64 IM_S64_MAX = 9223372036854775807ll; +static const ImU64 IM_U64_MIN = 0; +static const ImU64 IM_U64_MAX = 0xFFFFFFFFFFFFFFFFull; + //------------------------------------------------------------------------- // Forward Declarations //------------------------------------------------------------------------- @@ -767,8 +776,10 @@ static void UpdateManualResize(ImGuiWindow* window, const ImVec2& si static void FocusFrontMostActiveWindow(ImGuiWindow* ignore_window); template -static bool DragBehaviorT(ImGuiID id, ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power); +static bool DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power); static bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power); + +static bool SliderBehavior(const ImRect& bb, ImGuiID id, float* v, float v_min, float v_max, const char* format, float power, ImGuiSliderFlags flags = 0); } //----------------------------------------------------------------------------- @@ -8736,9 +8747,9 @@ static inline float SliderBehaviorCalcRatioFromValue(float v, float v_min, float if (v_min == v_max) return 0.0f; - const bool is_non_linear = (power < 1.0f-0.00001f) || (power > 1.0f+0.00001f); + const bool is_power = (power != 1.0f); const float v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min); - if (is_non_linear) + if (is_power) { if (v_clamped < 0.0f) { @@ -8756,7 +8767,7 @@ static inline float SliderBehaviorCalcRatioFromValue(float v, float v_min, float return (v_clamped - v_min) / (v_max - v_min); } -bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, const char* format, float power, ImGuiSliderFlags flags) +static bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, float* v, float v_min, float v_max, const char* format, float power, ImGuiSliderFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -8764,32 +8775,32 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v // Draw frame const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); - RenderNavHighlight(frame_bb, id); - RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding); + RenderNavHighlight(bb, id); + RenderFrame(bb.Min, bb.Max, frame_col, true, style.FrameRounding); - const bool is_non_linear = (power < 1.0f-0.00001f) || (power > 1.0f+0.00001f); + const bool is_power = (power != 1.0f); const bool is_horizontal = (flags & ImGuiSliderFlags_Vertical) == 0; const bool is_decimal = ImParseFormatPrecision(format, 3) != 0; const float grab_padding = 2.0f; - const float slider_sz = is_horizontal ? (frame_bb.GetWidth() - grab_padding * 2.0f) : (frame_bb.GetHeight() - grab_padding * 2.0f); + const float slider_sz = is_horizontal ? (bb.GetWidth() - grab_padding * 2.0f) : (bb.GetHeight() - grab_padding * 2.0f); float grab_sz; if (is_decimal) grab_sz = ImMin(style.GrabMinSize, slider_sz); else grab_sz = ImMin(ImMax(1.0f * (slider_sz / ((v_min < v_max ? v_max - v_min : v_min - v_max) + 1.0f)), style.GrabMinSize), slider_sz); // Integer sliders, if possible have the grab size represent 1 unit const float slider_usable_sz = slider_sz - grab_sz; - const float slider_usable_pos_min = (is_horizontal ? frame_bb.Min.x : frame_bb.Min.y) + grab_padding + grab_sz*0.5f; - const float slider_usable_pos_max = (is_horizontal ? frame_bb.Max.x : frame_bb.Max.y) - grab_padding - grab_sz*0.5f; + const float slider_usable_pos_min = (is_horizontal ? bb.Min.x : bb.Min.y) + grab_padding + grab_sz*0.5f; + const float slider_usable_pos_max = (is_horizontal ? bb.Max.x : bb.Max.y) - grab_padding - grab_sz*0.5f; // For power curve sliders that cross over sign boundary we want the curve to be symmetric around 0.0f float linear_zero_pos = 0.0f; // 0.0->1.0f if (v_min * v_max < 0.0f) { // Different sign - const float linear_dist_min_to_0 = powf(fabsf(0.0f - v_min), 1.0f/power); - const float linear_dist_max_to_0 = powf(fabsf(v_max - 0.0f), 1.0f/power); - linear_zero_pos = linear_dist_min_to_0 / (linear_dist_min_to_0+linear_dist_max_to_0); + const float linear_dist_min_to_0 = powf(v_min >= 0.0f ? v_min : -v_min, 1.0f/power); + const float linear_dist_max_to_0 = powf(v_max >= 0.0f ? v_max : -v_max, 1.0f/power); + linear_zero_pos = linear_dist_min_to_0 / (linear_dist_min_to_0 + linear_dist_max_to_0); } else { @@ -8829,19 +8840,19 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v else if (delta != 0.0f) { clicked_t = SliderBehaviorCalcRatioFromValue(*v, v_min, v_max, power, linear_zero_pos); - if (!is_decimal && !is_non_linear) + if (is_decimal || is_power) + { + delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds + if (IsNavInputDown(ImGuiNavInput_TweakSlow)) + delta /= 10.0f; + } + else { if (fabsf(v_max - v_min) <= 100.0f || IsNavInputDown(ImGuiNavInput_TweakSlow)) delta = ((delta < 0.0f) ? -1.0f : +1.0f) / (v_max - v_min); // Gamepad/keyboard tweak speeds in integer steps else delta /= 100.0f; } - else - { - delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds - if (IsNavInputDown(ImGuiNavInput_TweakSlow)) - delta /= 10.0f; - } if (IsNavInputDown(ImGuiNavInput_TweakFast)) delta *= 10.0f; set_new_value = true; @@ -8854,8 +8865,8 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v if (set_new_value) { - float new_value; - if (is_non_linear) + float v_new; + if (is_power) { // Account for power curve scale on both sides of the zero if (clicked_t < linear_zero_pos) @@ -8863,7 +8874,7 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v // Negative: rescale to the negative range before powering float a = 1.0f - (clicked_t / linear_zero_pos); a = powf(a, power); - new_value = ImLerp(ImMin(v_max,0.0f), v_min, a); + v_new = ImLerp(ImMin(v_max,0.0f), v_min, a); } else { @@ -8874,22 +8885,22 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v else a = clicked_t; a = powf(a, power); - new_value = ImLerp(ImMax(v_min,0.0f), v_max, a); + v_new = ImLerp(ImMax(v_min,0.0f), v_max, a); } } else { // Linear slider - new_value = ImLerp(v_min, v_max, clicked_t); + v_new = ImLerp(v_min, v_max, clicked_t); } // Round past decimal precision char buf[64]; - ImFormatString(buf, IM_ARRAYSIZE(buf), ImParseFormatFindStart(format), new_value); - new_value = (float)atof(buf); - if (*v != new_value) + ImFormatString(buf, IM_ARRAYSIZE(buf), ImParseFormatFindStart(format), v_new); + v_new = (float)atof(buf); + if (*v != v_new) { - *v = new_value; + *v = v_new; value_changed = true; } } @@ -8902,9 +8913,9 @@ bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); ImRect grab_bb; if (is_horizontal) - grab_bb = ImRect(ImVec2(grab_pos - grab_sz*0.5f, frame_bb.Min.y + grab_padding), ImVec2(grab_pos + grab_sz*0.5f, frame_bb.Max.y - grab_padding)); + grab_bb = ImRect(grab_pos - grab_sz*0.5f, bb.Min.y + grab_padding, grab_pos + grab_sz*0.5f, bb.Max.y - grab_padding); else - grab_bb = ImRect(ImVec2(frame_bb.Min.x + grab_padding, grab_pos - grab_sz*0.5f), ImVec2(frame_bb.Max.x - grab_padding, grab_pos + grab_sz*0.5f)); + grab_bb = ImRect(bb.Min.x + grab_padding, grab_pos - grab_sz*0.5f, bb.Max.x - grab_padding, grab_pos + grab_sz*0.5f); window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding); return value_changed; @@ -9132,21 +9143,10 @@ bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const } template -static bool ImGui::DragBehaviorT(ImGuiID id, ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power) +static bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power) { ImGuiContext& g = *GImGui; - // Process interacting with the drag - if (g.ActiveId == id) - { - if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0]) - ClearActiveID(); - else if (g.ActiveIdSource == ImGuiInputSource_Nav && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) - ClearActiveID(); - } - if (g.ActiveId != id) - return false; - // Default tweak speed bool has_min_max = (v_min != v_max) && (v_max - v_max < FLT_MAX); if (v_speed == 0.0f && has_min_max) @@ -9245,25 +9245,27 @@ static bool ImGui::DragBehaviorT(ImGuiID id, ImGuiDataType data_type, TYPE* v, f return true; } -static const ImS32 IM_S32_MIN = 0x80000000; // INT_MIN; -static const ImS32 IM_S32_MAX = 0x7FFFFFFF; // INT_MAX; -static const ImU32 IM_U32_MIN = 0; -static const ImU32 IM_U32_MAX = 0xFFFFFFFF; -static const ImS64 IM_S64_MIN = -9223372036854775807ll - 1ll; -static const ImS64 IM_S64_MAX = 9223372036854775807ll; -static const ImU64 IM_U64_MIN = 0; -static const ImU64 IM_U64_MAX = 0xFFFFFFFFFFFFFFFFull; - bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power) { + ImGuiContext& g = *GImGui; + if (g.ActiveId == id) + { + if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0]) + ClearActiveID(); + else if (g.ActiveIdSource == ImGuiInputSource_Nav && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated) + ClearActiveID(); + } + if (g.ActiveId != id) + return false; + switch (data_type) { - case ImGuiDataType_S32: return DragBehaviorT(id, data_type, (ImS32*)v, v_speed, v_min ? *(const ImS32* )v_min : IM_S32_MIN, v_max ? *(const ImS32* )v_max : IM_S32_MAX, format, power); - case ImGuiDataType_U32: return DragBehaviorT(id, data_type, (ImU32*)v, v_speed, v_min ? *(const ImU32* )v_min : IM_U32_MIN, v_max ? *(const ImU32* )v_max : IM_U32_MAX, format, power); - case ImGuiDataType_S64: return DragBehaviorT(id, data_type, (ImS64*)v, v_speed, v_min ? *(const ImS64* )v_min : IM_S64_MIN, v_max ? *(const ImS64* )v_max : IM_S64_MAX, format, power); - case ImGuiDataType_U64: return DragBehaviorT(id, data_type, (ImU64*)v, v_speed, v_min ? *(const ImU64* )v_min : IM_U64_MIN, v_max ? *(const ImU64* )v_max : IM_U64_MAX, format, power); - case ImGuiDataType_Float: return DragBehaviorT(id, data_type, (float*)v, v_speed, v_min ? *(const float* )v_min : -FLT_MAX, v_max ? *(const float* )v_max : FLT_MAX, format, power); - case ImGuiDataType_Double: return DragBehaviorT(id, data_type, (double*)v, v_speed, v_min ? *(const double*)v_min : -DBL_MAX, v_max ? *(const double*)v_max : DBL_MAX, format, power); + case ImGuiDataType_S32: return DragBehaviorT(data_type, (ImS32*)v, v_speed, v_min ? *(const ImS32* )v_min : IM_S32_MIN, v_max ? *(const ImS32* )v_max : IM_S32_MAX, format, power); + case ImGuiDataType_U32: return DragBehaviorT(data_type, (ImU32*)v, v_speed, v_min ? *(const ImU32* )v_min : IM_U32_MIN, v_max ? *(const ImU32* )v_max : IM_U32_MAX, format, power); + case ImGuiDataType_S64: return DragBehaviorT(data_type, (ImS64*)v, v_speed, v_min ? *(const ImS64* )v_min : IM_S64_MIN, v_max ? *(const ImS64* )v_max : IM_S64_MAX, format, power); + case ImGuiDataType_U64: return DragBehaviorT(data_type, (ImU64*)v, v_speed, v_min ? *(const ImU64* )v_min : IM_U64_MIN, v_max ? *(const ImU64* )v_max : IM_U64_MAX, format, power); + case ImGuiDataType_Float: return DragBehaviorT(data_type, (float*)v, v_speed, v_min ? *(const float* )v_min : -FLT_MAX, v_max ? *(const float* )v_max : FLT_MAX, format, power); + case ImGuiDataType_Double: return DragBehaviorT(data_type, (double*)v, v_speed, v_min ? *(const double*)v_min : -DBL_MAX, v_max ? *(const double*)v_max : DBL_MAX, format, power); case ImGuiDataType_COUNT: break; } IM_ASSERT(0); @@ -9323,6 +9325,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa // Default format string when passing NULL // Patch old "%.0f" format string to use "%d", read function comments for more details. + IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); if (format == NULL) format = GDataTypeInfo[data_type].PrintFmt; else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) @@ -10689,6 +10692,10 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; + IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); + if (format == NULL) + format = GDataTypeInfo[data_type].PrintFmt; + char buf[64]; DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, data_ptr, format); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 7150802a4..9aa087fdc 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -375,7 +375,7 @@ void ImGui::ShowDemoWindow(bool* p_open) static float f1=0.123f, f2=0.0f; ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f"); - ImGui::SliderFloat("slider log float", &f2, -10.0f, 10.0f, "%.4f", 3.0f); + ImGui::SliderFloat("slider float (curve)", &f2, -10.0f, 10.0f, "%.4f", 2.0f); static float angle = 0.0f; ImGui::SliderAngle("slider angle", &angle); } diff --git a/imgui_internal.h b/imgui_internal.h index f27f0a7a6..07cbdb1e4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1101,15 +1101,14 @@ namespace ImGui IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0); IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos, float radius); - IMGUI_API bool SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, const char* format, float power, ImGuiSliderFlags flags = 0); IMGUI_API bool SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* format, float power); IMGUI_API bool SliderIntN(const char* label, int* v, int components, int v_min, int v_max, const char* format); - IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power = 1.0f); - IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min, const void* v_max, const char* format, float power = 1.0f); + IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); + IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); - IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* v, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags extra_flags = 0); + IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* v, const void* step, const void* step_fast, const char* format = NULL, ImGuiInputTextFlags extra_flags = 0); + IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step, const void* step_fast, const char* format = NULL, ImGuiInputTextFlags extra_flags = 0); IMGUI_API bool InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format); From 944f414cc6f04da05d780236ac25b83b40828a70 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 4 May 2018 18:13:27 +0200 Subject: [PATCH 17/22] Internals: A few selected math helpers are now using template to handle all supported types. Added ImPow() to wrap float/double in a standard manner without calling pow(double) when not needed in Drag code. --- imgui.cpp | 20 ++++++++++---------- imgui_internal.h | 27 +++++++++++++-------------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 78b8562b6..9ab3b0832 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8739,7 +8739,7 @@ static float GetMinimumStepAtDecimalPrecision(int decimal_precision) static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f }; if (decimal_precision < 0) return FLT_MIN; - return (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : powf(10.0f, (float)-decimal_precision); + return (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision); } static inline float SliderBehaviorCalcRatioFromValue(float v, float v_min, float v_max, float power, float linear_zero_pos) @@ -8754,12 +8754,12 @@ static inline float SliderBehaviorCalcRatioFromValue(float v, float v_min, float if (v_clamped < 0.0f) { const float f = 1.0f - (v_clamped - v_min) / (ImMin(0.0f,v_max) - v_min); - return (1.0f - powf(f, 1.0f/power)) * linear_zero_pos; + return (1.0f - ImPow(f, 1.0f/power)) * linear_zero_pos; } else { const float f = (v_clamped - ImMax(0.0f,v_min)) / (v_max - ImMax(0.0f,v_min)); - return linear_zero_pos + powf(f, 1.0f/power) * (1.0f - linear_zero_pos); + return linear_zero_pos + ImPow(f, 1.0f/power) * (1.0f - linear_zero_pos); } } @@ -8798,8 +8798,8 @@ static bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, float* v, float if (v_min * v_max < 0.0f) { // Different sign - const float linear_dist_min_to_0 = powf(v_min >= 0.0f ? v_min : -v_min, 1.0f/power); - const float linear_dist_max_to_0 = powf(v_max >= 0.0f ? v_max : -v_max, 1.0f/power); + const float linear_dist_min_to_0 = ImPow(v_min >= 0.0f ? v_min : -v_min, 1.0f/power); + const float linear_dist_max_to_0 = ImPow(v_max >= 0.0f ? v_max : -v_max, 1.0f/power); linear_zero_pos = linear_dist_min_to_0 / (linear_dist_min_to_0 + linear_dist_max_to_0); } else @@ -8873,7 +8873,7 @@ static bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, float* v, float { // Negative: rescale to the negative range before powering float a = 1.0f - (clicked_t / linear_zero_pos); - a = powf(a, power); + a = ImPow(a, power); v_new = ImLerp(ImMin(v_max,0.0f), v_min, a); } else @@ -8884,7 +8884,7 @@ static bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, float* v, float a = (clicked_t - linear_zero_pos) / (1.0f - linear_zero_pos); else a = clicked_t; - a = powf(a, power); + a = ImPow(a, power); v_new = ImLerp(ImMax(v_min,0.0f), v_max, a); } } @@ -9195,9 +9195,9 @@ static bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed if (is_power) { // Offset + round to user desired precision, with a curve on the v_min..v_max range to get more precision on one side of the range - FLOATTYPE v_old_norm_curved = (FLOATTYPE)pow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power); + FLOATTYPE v_old_norm_curved = ImPow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power); FLOATTYPE v_new_norm_curved = v_old_norm_curved + (g.DragCurrentAccum / (v_max - v_min)); - v_cur = v_min + (TYPE)pow(ImSaturate((float)v_new_norm_curved), power) * (v_max - v_min); + v_cur = v_min + (TYPE)ImPow(ImSaturate((float)v_new_norm_curved), power) * (v_max - v_min); v_old_ref_for_accum_remainder = v_old_norm_curved; } else @@ -9217,7 +9217,7 @@ static bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed g.DragCurrentAccumDirty = false; if (is_power) { - FLOATTYPE v_cur_norm_curved = (FLOATTYPE)pow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power); + FLOATTYPE v_cur_norm_curved = ImPow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power); g.DragCurrentAccum -= (float)(v_cur_norm_curved - v_old_ref_for_accum_remainder); } else diff --git a/imgui_internal.h b/imgui_internal.h index 07cbdb1e4..7f6e8ef06 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -126,8 +126,9 @@ IMGUI_API const char* ImParseFormatFindEnd(const char* format); IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, int buf_size); IMGUI_API int ImParseFormatPrecision(const char* format, int default_value); -// Helpers: Math -// We are keeping those not leaking to the user by default, in the case the user has implicit cast operators between ImVec2 and its own types (when IM_VEC2_CLASS_EXTRA is defined) +// Helpers: ImVec2/ImVec4 operators +// We are keeping those disabled by default so they don't leak in user space, to allow user enabling implicit cast operators between ImVec2 and their own types (using IM_VEC2_CLASS_EXTRA etc.) +// We unfortunately don't have a unary- operator for ImVec2 because this would needs to be defined inside the class itself. #ifdef IMGUI_DEFINE_MATH_OPERATORS static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x*rhs, lhs.y*rhs); } static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x/rhs, lhs.y/rhs); } @@ -144,23 +145,19 @@ static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x*rhs.x, lhs.y*rhs.y, lhs.z*rhs.z, lhs.w*rhs.w); } #endif -static inline int ImMin(int lhs, int rhs) { return lhs < rhs ? lhs : rhs; } -static inline int ImMax(int lhs, int rhs) { return lhs >= rhs ? lhs : rhs; } -static inline float ImMin(float lhs, float rhs) { return lhs < rhs ? lhs : rhs; } -static inline float ImMax(float lhs, float rhs) { return lhs >= rhs ? lhs : rhs; } +// Helpers: Maths +template static inline T ImMin(T lhs, T rhs) { return lhs < rhs ? lhs : rhs; } +template static inline T ImMax(T lhs, T rhs) { return lhs >= rhs ? lhs : rhs; } +template static inline T ImClamp(T v, T mn, T mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } +template static inline T ImLerp(T a, T b, float t) { return (T)(a + (b - a) * t); } +template static inline void ImSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; } static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); } static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); } -static inline int ImClamp(int v, int mn, int mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } -static inline float ImClamp(float v, float mn, float mx) { return (v < mn) ? mn : (v > mx) ? mx : v; } -static inline ImVec2 ImClamp(const ImVec2& f, const ImVec2& mn, ImVec2 mx) { return ImVec2(ImClamp(f.x,mn.x,mx.x), ImClamp(f.y,mn.y,mx.y)); } -static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; } -static inline void ImSwap(int& a, int& b) { int tmp = a; a = b; b = tmp; } -static inline void ImSwap(float& a, float& b) { float tmp = a; a = b; b = tmp; } -static inline int ImLerp(int a, int b, float t) { return (int)(a + (b - a) * t); } -static inline float ImLerp(float a, float b, float t) { return a + (b - a) * t; } +static inline ImVec2 ImClamp(const ImVec2& v, const ImVec2& mn, ImVec2 mx) { return ImVec2((v.x < mn.x) ? mn.x : (v.x > mx.x) ? mx.x : v.x, (v.y < mn.y) ? mn.y : (v.y > mx.y) ? mx.y : v.y); } static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); } static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); } static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); } +static inline float ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; } static inline float ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; } static inline float ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; } static inline float ImInvLength(const ImVec2& lhs, float fail_value) { float d = lhs.x*lhs.x + lhs.y*lhs.y; if (d > 0.0f) return 1.0f / sqrtf(d); return fail_value; } @@ -170,6 +167,8 @@ static inline float ImDot(const ImVec2& a, const ImVec2& b) static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); } static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; } static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } +static inline float ImPow(float x, float y) { return powf(x, y); } +static inline double ImPow(double x, double y) { return pow(x, y); } //----------------------------------------------------------------------------- // Types From 3e8087458d7232b522ce10583c44b62bd1729012 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 4 May 2018 20:41:21 +0200 Subject: [PATCH 18/22] SliderScalar, VSliderScalar(): Support for any data types. Tested with various ranges/limits. Note that Drag/Slider/Input currently fail if the format string doesn't preview the actual value. Will fix next. (#320, #643, #708, #1011) --- imgui.cpp | 279 ++++++++++++++++++++++++++--------------------- imgui.h | 12 +- imgui_internal.h | 7 +- 3 files changed, 167 insertions(+), 131 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9ab3b0832..e9eb8b9ae 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -779,7 +779,9 @@ template static bool DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power); static bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power); -static bool SliderBehavior(const ImRect& bb, ImGuiID id, float* v, float v_min, float v_max, const char* format, float power, ImGuiSliderFlags flags = 0); +template +static bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiSliderFlags flags); +static bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags = 0); } //----------------------------------------------------------------------------- @@ -8742,32 +8744,34 @@ static float GetMinimumStepAtDecimalPrecision(int decimal_precision) return (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision); } -static inline float SliderBehaviorCalcRatioFromValue(float v, float v_min, float v_max, float power, float linear_zero_pos) +template +static inline float SliderBehaviorCalcRatioFromValue(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, float power, float linear_zero_pos) { if (v_min == v_max) return 0.0f; - const bool is_power = (power != 1.0f); - const float v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min); + const bool is_power = (power != 1.0f) && (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double); + const TYPE v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min); if (is_power) { if (v_clamped < 0.0f) { - const float f = 1.0f - (v_clamped - v_min) / (ImMin(0.0f,v_max) - v_min); + const float f = 1.0f - (float)((v_clamped - v_min) / (ImMin((TYPE)0, v_max) - v_min)); return (1.0f - ImPow(f, 1.0f/power)) * linear_zero_pos; } else { - const float f = (v_clamped - ImMax(0.0f,v_min)) / (v_max - ImMax(0.0f,v_min)); + const float f = (float)((v_clamped - ImMax((TYPE)0, v_min)) / (v_max - ImMax((TYPE)0, v_min))); return linear_zero_pos + ImPow(f, 1.0f/power) * (1.0f - linear_zero_pos); } } // Linear slider - return (v_clamped - v_min) / (v_max - v_min); + return (float)((FLOATTYPE)(v_clamped - v_min) / (FLOATTYPE)(v_max - v_min)); } -static bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, float* v, float v_min, float v_max, const char* format, float power, ImGuiSliderFlags flags) +template +static bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiSliderFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -8778,29 +8782,29 @@ static bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, float* v, float RenderNavHighlight(bb, id); RenderFrame(bb.Min, bb.Max, frame_col, true, style.FrameRounding); - const bool is_power = (power != 1.0f); const bool is_horizontal = (flags & ImGuiSliderFlags_Vertical) == 0; - const bool is_decimal = ImParseFormatPrecision(format, 3) != 0; + const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); + const bool is_power = (power != 1.0f) && is_decimal; const float grab_padding = 2.0f; const float slider_sz = is_horizontal ? (bb.GetWidth() - grab_padding * 2.0f) : (bb.GetHeight() - grab_padding * 2.0f); - float grab_sz; - if (is_decimal) - grab_sz = ImMin(style.GrabMinSize, slider_sz); - else - grab_sz = ImMin(ImMax(1.0f * (slider_sz / ((v_min < v_max ? v_max - v_min : v_min - v_max) + 1.0f)), style.GrabMinSize), slider_sz); // Integer sliders, if possible have the grab size represent 1 unit + float grab_sz = style.GrabMinSize; + SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max); + if (!is_decimal && v_range >= 0) // v_range < 0 may happen on integer overflows + grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit + grab_sz = ImMin(grab_sz, slider_sz); const float slider_usable_sz = slider_sz - grab_sz; const float slider_usable_pos_min = (is_horizontal ? bb.Min.x : bb.Min.y) + grab_padding + grab_sz*0.5f; const float slider_usable_pos_max = (is_horizontal ? bb.Max.x : bb.Max.y) - grab_padding - grab_sz*0.5f; // For power curve sliders that cross over sign boundary we want the curve to be symmetric around 0.0f - float linear_zero_pos = 0.0f; // 0.0->1.0f - if (v_min * v_max < 0.0f) + float linear_zero_pos; // 0.0->1.0f + if (is_power && v_min * v_max < 0.0f) { // Different sign - const float linear_dist_min_to_0 = ImPow(v_min >= 0.0f ? v_min : -v_min, 1.0f/power); - const float linear_dist_max_to_0 = ImPow(v_max >= 0.0f ? v_max : -v_max, 1.0f/power); - linear_zero_pos = linear_dist_min_to_0 / (linear_dist_min_to_0 + linear_dist_max_to_0); + const FLOATTYPE linear_dist_min_to_0 = ImPow(v_min >= 0 ? (FLOATTYPE)v_min : -(FLOATTYPE)v_min, (FLOATTYPE)1.0f/power); + const FLOATTYPE linear_dist_max_to_0 = ImPow(v_max >= 0 ? (FLOATTYPE)v_max : -(FLOATTYPE)v_max, (FLOATTYPE)1.0f/power); + linear_zero_pos = (float)(linear_dist_min_to_0 / (linear_dist_min_to_0 + linear_dist_max_to_0)); } else { @@ -8839,7 +8843,7 @@ static bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, float* v, float } else if (delta != 0.0f) { - clicked_t = SliderBehaviorCalcRatioFromValue(*v, v_min, v_max, power, linear_zero_pos); + clicked_t = SliderBehaviorCalcRatioFromValue(data_type, *v, v_min, v_max, power, linear_zero_pos); if (is_decimal || is_power) { delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds @@ -8848,8 +8852,8 @@ static bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, float* v, float } else { - if (fabsf(v_max - v_min) <= 100.0f || IsNavInputDown(ImGuiNavInput_TweakSlow)) - delta = ((delta < 0.0f) ? -1.0f : +1.0f) / (v_max - v_min); // Gamepad/keyboard tweak speeds in integer steps + if (v_max - v_min <= 100.0f || v_max - v_min >= -100.0f || IsNavInputDown(ImGuiNavInput_TweakSlow)) + delta = ((delta < 0.0f) ? -1.0f : +1.0f) / (float)(v_max - v_min); // Gamepad/keyboard tweak speeds in integer steps else delta /= 100.0f; } @@ -8865,7 +8869,7 @@ static bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, float* v, float if (set_new_value) { - float v_new; + TYPE v_new; if (is_power) { // Account for power curve scale on both sides of the zero @@ -8874,7 +8878,7 @@ static bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, float* v, float // Negative: rescale to the negative range before powering float a = 1.0f - (clicked_t / linear_zero_pos); a = ImPow(a, power); - v_new = ImLerp(ImMin(v_max,0.0f), v_min, a); + v_new = ImLerp(ImMin(v_max, (TYPE)0), v_min, a); } else { @@ -8885,19 +8889,39 @@ static bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, float* v, float else a = clicked_t; a = ImPow(a, power); - v_new = ImLerp(ImMax(v_min,0.0f), v_max, a); + v_new = ImLerp(ImMax(v_min, (TYPE)0), v_max, a); } } else { // Linear slider - v_new = ImLerp(v_min, v_max, clicked_t); + if (is_decimal) + { + v_new = ImLerp(v_min, v_max, clicked_t); + } + else + { + // For integer values we want the clicking position to match the grab box so we round above + // This code is carefully tuned to work with large values (e.g. high ranges of U64) while preserving this property.. + FLOATTYPE v_new_off_f = (v_max - v_min) * clicked_t; + TYPE v_new_off_floor = (TYPE)(v_new_off_f); + TYPE v_new_off_round = (TYPE)(v_new_off_f + (FLOATTYPE)0.5); + if (!is_decimal && v_new_off_floor < v_new_off_round) + v_new = v_min + v_new_off_round; + else + v_new = v_min + v_new_off_floor; + } } - // Round past decimal precision - char buf[64]; - ImFormatString(buf, IM_ARRAYSIZE(buf), ImParseFormatFindStart(format), v_new); - v_new = (float)atof(buf); + // Round to user desired precision based on format string + char v_str[64]; + ImFormatString(v_str, IM_ARRAYSIZE(v_str), ImParseFormatFindStart(format), v_new); + if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) + v_new = (TYPE)atof(v_str); + else + ImAtoi(v_str, (SIGNEDTYPE*)&v_new); + + // Apply result if (*v != v_new) { *v = v_new; @@ -8907,7 +8931,7 @@ static bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, float* v, float } // Draw - float grab_t = SliderBehaviorCalcRatioFromValue(*v, v_min, v_max, power, linear_zero_pos); + float grab_t = SliderBehaviorCalcRatioFromValue(data_type, *v, v_min, v_max, power, linear_zero_pos); if (!is_horizontal) grab_t = 1.0f - grab_t; const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t); @@ -8921,12 +8945,60 @@ static bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, float* v, float return value_changed; } -// Adjust format to decorate the value with a prefix or a suffix. -// "%.3f" 1.234 -// "%5.2f secs" 01.23 secs -// "Gold: %.0f" Gold: 1 -// Use power != 1.0f for non-linear sliders. -bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power) +static bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags) +{ + switch (data_type) + { + case ImGuiDataType_S32: + IM_ASSERT(*(const ImS32*)v_min >= IM_S32_MIN/2 && *(const ImS32*)v_max <= IM_S32_MAX/2); + return SliderBehaviorT(bb, id, data_type, (ImS32*)v, *(const ImS32*)v_min, *(const ImS32*)v_max, format, power, flags); + case ImGuiDataType_U32: + IM_ASSERT(*(const ImU32*)v_min <= IM_U32_MAX/2); + return SliderBehaviorT(bb, id, data_type, (ImU32*)v, *(const ImU32*)v_min, *(const ImU32*)v_max, format, power, flags); + case ImGuiDataType_S64: + IM_ASSERT(*(const ImS64*)v_min >= IM_S64_MIN/2 && *(const ImS64*)v_max <= IM_S64_MAX/2); + return SliderBehaviorT(bb, id, data_type, (ImS64*)v, *(const ImS64*)v_min, *(const ImS64*)v_max, format, power, flags); + case ImGuiDataType_U64: + IM_ASSERT(*(const ImU64*)v_min <= IM_U64_MAX/2); + return SliderBehaviorT(bb, id, data_type, (ImU64*)v, *(const ImU64*)v_min, *(const ImU64*)v_max, format, power, flags); + case ImGuiDataType_Float: + IM_ASSERT(*(const float*)v_min >= -FLT_MAX/2.0f && *(const float*)v_max <= FLT_MAX/2.0f); + return SliderBehaviorT(bb, id, data_type, (float*)v, *(const float*)v_min, *(const float*)v_max, format, power, flags); + case ImGuiDataType_Double: + IM_ASSERT(*(const double*)v_min >= -DBL_MAX/2.0f && *(const double*)v_max <= DBL_MAX/2.0f); + return SliderBehaviorT(bb, id, data_type, (double*)v, *(const double*)v_min, *(const double*)v_max, format, power, flags); + case ImGuiDataType_COUNT: + break; + } + IM_ASSERT(0); + return false; +} + +// FIXME-LEGACY: Prior to 1.61 our DragInt() function internally used floats and because of this the compile-time default value for format was "%.0f". +// Even though we changed the compile-time default, we expect users to have carried %f around, which would break the display of DragInt() calls. +// To honor backward compatibility we are rewriting the format string, unless IMGUI_DISABLE_OBSOLETE_FUNCTIONS is enabled. What could possibly go wrong?! +static const char* PatchFormatStringFloatToInt(const char* fmt) +{ + if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '0' && fmt[3] == 'f' && fmt[4] == 0) // Fast legacy path for "%.0f" which is expected to be the most common case. + return "%d"; + const char* fmt_start = ImParseFormatFindStart(fmt); // Find % (if any, and ignore %%) + const char* fmt_end = ImParseFormatFindEnd(fmt_start); // Find end of format specifier, which itself is an exercise of confidence/recklessness (because snprintf is dependent on libc or user). + if (fmt_end > fmt_start && fmt_end[-1] == 'f') + { +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS + if (fmt_start == fmt && fmt_end[0] == 0) + return "%d"; + ImGuiContext& g = *GImGui; + ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%.*s%%d%s", (int)(fmt_start - fmt), fmt, fmt_end); // Honor leading and trailing decorations, but lose alignment/precision. + return g.TempBuffer; +#else + IM_ASSERT(0 && "DragInt(): Invalid format string!"); // Old versions used a default parameter of "%.0f", please replace with e.g. "%d" +#endif + } + return fmt; +} + +bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -8947,14 +9019,19 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c ItemSize(total_bb, style.FramePadding.y); return false; } - const bool hovered = ItemHoverable(frame_bb, id); - if (!format) - format = "%.3f"; + // Default format string when passing NULL + // Patch old "%.0f" format string to use "%d", read function comments for more details. + IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); + if (format == NULL) + format = GDataTypeInfo[data_type].PrintFmt; + else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) + format = PatchFormatStringFloatToInt(format); // Tabbing or CTRL-clicking on Slider turns it into an input box bool start_text_input = false; const bool tab_focus_requested = FocusableItemRegister(window, id); + const bool hovered = ItemHoverable(frame_bb, id); if (tab_focus_requested || (hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || (g.NavInputId == id && g.ScalarAsInputTextId != id)) { SetActiveID(id, window); @@ -8968,15 +9045,15 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c } } if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) - return InputScalarAsWidgetReplacement(frame_bb, id, label, ImGuiDataType_Float, v, format); + return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format); // Actual slider behavior + render grab ItemSize(total_bb, style.FramePadding.y); - const bool value_changed = SliderBehavior(frame_bb, id, v, v_min, v_max, format, power); + const bool value_changed = SliderBehavior(frame_bb, id, data_type, v, v_min, v_max, format, power); // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; - const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), format, *v); + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, v, format); RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.5f)); if (label_size.x > 0.0f) @@ -8985,7 +9062,12 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c return value_changed; } -bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, float power) +bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power) +{ + return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); +} + +bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -9002,11 +9084,16 @@ bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float ItemSize(bb, style.FramePadding.y); if (!ItemAdd(frame_bb, id)) return false; + + // Default format string when passing NULL + // Patch old "%.0f" format string to use "%d", read function comments for more details. + IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT); + if (format == NULL) + format = GDataTypeInfo[data_type].PrintFmt; + else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) + format = PatchFormatStringFloatToInt(format); + const bool hovered = ItemHoverable(frame_bb, id); - - if (!format) - format = "%.3f"; - if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavInputId == id) { SetActiveID(id, window); @@ -9016,12 +9103,12 @@ bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float } // Actual slider behavior + render grab - bool value_changed = SliderBehavior(frame_bb, id, v, v_min, v_max, format, power, ImGuiSliderFlags_Vertical); + bool value_changed = SliderBehavior(frame_bb, id, data_type, v, v_min, v_max, format, power, ImGuiSliderFlags_Vertical); // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. // For the vertical slider we allow centered text to overlap the frame padding char value_buf[64]; - char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), format, *v); + const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, v, format); RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.0f)); if (label_size.x > 0.0f) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -9039,26 +9126,21 @@ bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, fl bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* format) { - if (!format) - format = "%.0f"; - float v_f = (float)*v; - bool value_changed = SliderFloat(label, &v_f, (float)v_min, (float)v_max, format, 1.0f); - *v = (int)v_f; - return value_changed; + return SliderScalar(label, ImGuiDataType_S32, v, &v_min, &v_max, format); +} + +bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, float power) +{ + return VSliderScalar(label, size, ImGuiDataType_Float, v, &v_min, &v_max, format, power); } bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format) { - if (!format) - format = "%.0f"; - float v_f = (float)*v; - bool value_changed = VSliderFloat(label, size, &v_f, (float)v_min, (float)v_max, format, 1.0f); - *v = (int)v_f; - return value_changed; + return VSliderScalar(label, size, ImGuiDataType_S32, v, &v_min, &v_max, format); } // Add multiple sliders on 1 line for compact edition of multiple components -bool ImGui::SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* format, float power) +bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, float power) { ImGuiWindow* window = GetCurrentWindow(); if (window->SkipItems) @@ -9069,77 +9151,51 @@ bool ImGui::SliderFloatN(const char* label, float* v, int components, float v_mi BeginGroup(); PushID(label); PushMultiItemsWidths(components); + size_t type_size = GDataTypeInfo[data_type].Size; for (int i = 0; i < components; i++) { PushID(i); - value_changed |= SliderFloat("##v", &v[i], v_min, v_max, format, power); + value_changed |= SliderScalar("##v", data_type, v, v_min, v_max, format, power); SameLine(0, g.Style.ItemInnerSpacing.x); PopID(); PopItemWidth(); + v = (void*)((char*)v + type_size); } PopID(); TextUnformatted(label, FindRenderedTextEnd(label)); EndGroup(); - return value_changed; } bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power) { - return SliderFloatN(label, v, 2, v_min, v_max, format, power); + return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); } bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power) { - return SliderFloatN(label, v, 3, v_min, v_max, format, power); + return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); } bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power) { - return SliderFloatN(label, v, 4, v_min, v_max, format, power); -} - -bool ImGui::SliderIntN(const char* label, int* v, int components, int v_min, int v_max, const char* format) -{ - ImGuiWindow* window = GetCurrentWindow(); - if (window->SkipItems) - return false; - - ImGuiContext& g = *GImGui; - bool value_changed = false; - BeginGroup(); - PushID(label); - PushMultiItemsWidths(components); - for (int i = 0; i < components; i++) - { - PushID(i); - value_changed |= SliderInt("##v", &v[i], v_min, v_max, format); - SameLine(0, g.Style.ItemInnerSpacing.x); - PopID(); - PopItemWidth(); - } - PopID(); - - TextUnformatted(label, FindRenderedTextEnd(label)); - EndGroup(); - - return value_changed; + return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); } bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format) { - return SliderIntN(label, v, 2, v_min, v_max, format); + return SliderScalarN(label, ImGuiDataType_S32, v, 2, &v_min, &v_max, format); } bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format) { - return SliderIntN(label, v, 3, v_min, v_max, format); + return SliderScalarN(label, ImGuiDataType_S32, v, 3, &v_min, &v_max, format); } bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format) { - return SliderIntN(label, v, 4, v_min, v_max, format); + return SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format); } template @@ -9272,30 +9328,6 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_s return false; } -// FIXME-LEGACY: Prior to 1.61 our DragInt() function internally used floats and because of this the compile-time default value for format was "%.0f". -// Even though we changed the compile-time default, we expect users to have carried %f around, which would break the display of DragInt() calls. -// To honor backward compatibility we are rewriting the format string, unless IMGUI_DISABLE_OBSOLETE_FUNCTIONS is enabled. What could possibly go wrong?! -static const char* PatchFormatStringFloatToInt(const char* fmt) -{ - if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '0' && fmt[3] == 'f' && fmt[4] == 0) // Fast legacy path for "%.0f" which is expected to be the most common case. - return "%d"; - const char* fmt_start = ImParseFormatFindStart(fmt); // Find % (if any, and ignore %%) - const char* fmt_end = ImParseFormatFindEnd(fmt_start); // Find end of format specifier, which itself is an exercise of confidence/recklessness (because snprintf is dependent on libc or user). - if (fmt_end > fmt_start && fmt_end[-1] == 'f') - { -#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - if (fmt_start == fmt && fmt_end[0] == 0) - return "%d"; - ImGuiContext& g = *GImGui; - ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%.*s%%d%s", (int)(fmt_start - fmt), fmt, fmt_end); // Honor leading and trailing decorations, but lose alignment/precision. - return g.TempBuffer; -#else - IM_ASSERT(0 && "DragInt(): Invalid format string!"); // Old versions used a default parameter of "%.0f", please replace with e.g. "%d" -#endif - } - return fmt; -} - bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power) { ImGuiWindow* window = GetCurrentWindow(); @@ -9394,7 +9426,6 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* v, int TextUnformatted(label, FindRenderedTextEnd(label)); EndGroup(); - return value_changed; } diff --git a/imgui.h b/imgui.h index dcee1a187..2ce227544 100644 --- a/imgui.h +++ b/imgui.h @@ -341,6 +341,7 @@ namespace ImGui // Widgets: Drags (tip: ctrl+click on a drag box to input with keyboard. manually input values aren't clamped, can go off-bounds) // For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x + // Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. // Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision). IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); // If v_min >= v_max we have no bound IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); @@ -367,17 +368,18 @@ namespace ImGui IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0f, double step_fast = 0.0f, const char* format = "%.6f", ImGuiInputTextFlags extra_flags = 0); // Widgets: Sliders (tip: ctrl+click on a slider to input with keyboard. manually input values aren't clamped, can go off-bounds) + // Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. IMGUI_API bool SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. Use power!=1.0 for power curve sliders IMGUI_API bool SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); IMGUI_API bool SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); IMGUI_API bool SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); IMGUI_API bool SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f); - IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = "%.0f"); - IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%.0f"); - IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%.0f"); - IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%.0f"); + IMGUI_API bool SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = "%d"); + IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%d"); + IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%d"); + IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%d"); IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); - IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%.0f"); + IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%d"); // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little colored preview square that can be left-clicked to open a picker, and right-clicked to open an option menu.) // Note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can the pass the address of a first float element out of a contiguous structure, e.g. &myvector.x diff --git a/imgui_internal.h b/imgui_internal.h index 7f6e8ef06..8d3e17e7e 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -169,6 +169,8 @@ static inline float ImLinearSweep(float current, float target, float speed) static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); } static inline float ImPow(float x, float y) { return powf(x, y); } static inline double ImPow(double x, double y) { return pow(x, y); } +static inline float ImFmod(float x, float y) { return fmodf(x, y); } +static inline double ImFmod(double x, double y) { return fmod(x, y); } //----------------------------------------------------------------------------- // Types @@ -1100,8 +1102,9 @@ namespace ImGui IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0); IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos, float radius); - IMGUI_API bool SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* format, float power); - IMGUI_API bool SliderIntN(const char* label, int* v, int components, int v_min, int v_max, const char* format); + IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); + IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); + IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); From c5fb92955524204d4aff7c9fe850645b8a37fa2a Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 4 May 2018 21:02:26 +0200 Subject: [PATCH 19/22] Data types: Fixed empty format string (or no % specifier) breaking the parsing back of values. --- imgui.cpp | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index e9eb8b9ae..9251b47c0 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8744,6 +8744,21 @@ static float GetMinimumStepAtDecimalPrecision(int decimal_precision) return (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : ImPow(10.0f, (float)-decimal_precision); } +template +static inline TYPE RoundScalarWithFormat(const char* format, ImGuiDataType data_type, TYPE v) +{ + const char* fmt_start = ImParseFormatFindStart(format); + if (fmt_start[0] != '%' || fmt_start[1] == '%') // Don't apply if the value is not visible in the format string + return v; + char v_str[64]; + ImFormatString(v_str, IM_ARRAYSIZE(v_str), fmt_start, v); + if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) + v = (TYPE)atof(v_str); + else + ImAtoi(v_str, (SIGNEDTYPE*)&v); + return v; +} + template static inline float SliderBehaviorCalcRatioFromValue(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max, float power, float linear_zero_pos) { @@ -8914,12 +8929,7 @@ static bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType d } // Round to user desired precision based on format string - char v_str[64]; - ImFormatString(v_str, IM_ARRAYSIZE(v_str), ImParseFormatFindStart(format), v_new); - if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) - v_new = (TYPE)atof(v_str); - else - ImAtoi(v_str, (SIGNEDTYPE*)&v_new); + v_new = RoundScalarWithFormat(format, data_type, v_new); // Apply result if (*v != v_new) @@ -9262,12 +9272,7 @@ static bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed } // Round to user desired precision based on format string - char v_str[64]; - ImFormatString(v_str, IM_ARRAYSIZE(v_str), ImParseFormatFindStart(format), v_cur); - if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) - v_cur = (TYPE)atof(v_str); - else - ImAtoi(v_str, (SIGNEDTYPE*)&v_cur); + v_cur = RoundScalarWithFormat(format, data_type, v_cur); // Preserve remainder after rounding has been applied. This also allow slow tweaking of values. g.DragCurrentAccumDirty = false; From 8da0d42ef28934cf3786037fb83235b4d1c8df56 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 4 May 2018 21:35:23 +0200 Subject: [PATCH 20/22] Moved DragScalar, InputScalar, SliderScalar to imgui.h as well as ImGuiDataType (#320, #643, #708, #1011) --- CHANGELOG.txt | 6 ++++-- TODO.txt | 1 - imgui.h | 20 ++++++++++++++++++++ imgui_internal.h | 20 -------------------- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index a1b0a19a6..6a56bf129 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -63,13 +63,16 @@ Other Changes: - InputText: Fixed returning true when edition is canceled with ESC and the current buffer matches the initial value. - 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) +- Added DragScalar, DragScalarN: supports signed/unsigned, 32/64 bits, float/double data types. (#320, #643, #708, #1011) +- Added InputScalar, InputScalarN: supports signed/unsigned, 32/64 bits, float/double data types. (#320, #643, #708, #1011) +- Added SliderScalar, SliderScalarN: supports signed/unsigned, 32/64 bits, float/double data types. (#320, #643, #708, #1011) - 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, DragInt: Honor natural type limits (e.g. INT_MAX, FLT_MAX) instead of wrapping around. (#708, #320) - DragFloat, SliderFloat: Fixes to allow input of scientific notation numbers when using CTRL+Click to input the value. (~#648, #1011) - DragFloat, SliderFloat: Rounding-on-write uses the provided format string instead of parsing the precision from the string, which allows for finer uses of %e %g etc. (#648, #642) - DragFloat: Improved computation when using the power curve. Improved lost of input precision with very small steps. Added an assert than power-curve requires a min/max range. (~#642) - DragFloat: The 'power' parameter is only honored if the min/max parameter are also setup. -- DragInt: Fixed handling of large integers (we previously passed data around internally as float, which reduced the range of valid integers). +- DragInt, SliderInt: Fixed handling of large integers (we previously passed data around internally as float, which reduced the range of valid integers). - Nav: Fixed hovering a Selectable() with the mouse so that it update the navigation cursor (as it happened in the pre-1.60 navigation branch). (#787) - 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) @@ -77,7 +80,6 @@ Other Changes: - Examples: Calling IMGUI_CHECKVERSION() in the main.cpp of every example application. - Examples: Allegro 5: Added support for 32-bit indices setup via defining ImDrawIdx, to avoid an unnecessary conversion (Allegro 5 doesn't support 16-bit indices). - Examples: Allegro 5: Renamed bindings from imgui_impl_a5.cpp to imgui_impl_allegro5.cpp. -- Internal: DragScalar(), InputScalar() now support signed/unsigned, 32/64 bits, float/double data types. (#320, #643, #708, #1011) - Various minor fixes, tweaks, refactoring, comments. ----------------------------------------------------------------------- diff --git a/TODO.txt b/TODO.txt index 9ba704fda..29a60e4d8 100644 --- a/TODO.txt +++ b/TODO.txt @@ -131,7 +131,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - slider: tint background based on value (e.g. v_min -> v_max, or use 0.0f either side of the sign) - slider: precision dragging - slider: step option (#1183) - - slider: int data passing through a float - knob: rotating knob widget (#942) - drag float: up/down axis - drag float: added leeway on edge (e.g. a few invisible steps past the clamp limits) diff --git a/imgui.h b/imgui.h index 2ce227544..467bda3ca 100644 --- a/imgui.h +++ b/imgui.h @@ -80,6 +80,7 @@ typedef void* ImTextureID; // User data to identify a texture (this is typedef unsigned int ImGuiID; // Unique ID used by widgets (typically hashed from a stack of string) typedef unsigned short ImWchar; // Character for keyboard input/display typedef int ImGuiCol; // enum: a color identifier for styling // enum ImGuiCol_ +typedef int ImGuiDataType; // enum: a primary data type // enum ImGuiDataType_ typedef int ImGuiDir; // enum: a cardinal direction // enum ImGuiDir_ typedef int ImGuiCond; // enum: a condition for Set*() // enum ImGuiCond_ typedef int ImGuiKey; // enum: a key identifier (ImGui-side enum) // enum ImGuiKey_ @@ -353,6 +354,8 @@ namespace ImGui IMGUI_API bool DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); IMGUI_API bool DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d"); IMGUI_API bool DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", const char* format_max = NULL); + IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); + IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); // Widgets: Input with Keyboard IMGUI_API bool InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); @@ -366,6 +369,8 @@ namespace ImGui IMGUI_API bool InputInt3(const char* label, int v[3], ImGuiInputTextFlags extra_flags = 0); IMGUI_API bool InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_flags = 0); IMGUI_API bool InputDouble(const char* label, double* v, double step = 0.0f, double step_fast = 0.0f, const char* format = "%.6f", ImGuiInputTextFlags extra_flags = 0); + IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* v, const void* step, const void* step_fast, const char* format = NULL, ImGuiInputTextFlags extra_flags = 0); + IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step, const void* step_fast, const char* format = NULL, ImGuiInputTextFlags extra_flags = 0); // Widgets: Sliders (tip: ctrl+click on a slider to input with keyboard. manually input values aren't clamped, can go off-bounds) // Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc. @@ -378,8 +383,11 @@ namespace ImGui IMGUI_API bool SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%d"); IMGUI_API bool SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%d"); IMGUI_API bool SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%d"); + IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); + IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); IMGUI_API bool VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); IMGUI_API bool VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%d"); + IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little colored preview square that can be left-clicked to open a picker, and right-clicked to open an option menu.) // Note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can the pass the address of a first float element out of a contiguous structure, e.g. &myvector.x @@ -708,6 +716,18 @@ enum ImGuiDragDropFlags_ #define IMGUI_PAYLOAD_TYPE_COLOR_3F "_COL3F" // float[3]: Standard type for colors, without alpha. User code may use this type. #define IMGUI_PAYLOAD_TYPE_COLOR_4F "_COL4F" // float[4]: Standard type for colors. User code may use this type. +// A primary data type +enum ImGuiDataType_ +{ + ImGuiDataType_S32, // int + ImGuiDataType_U32, // unsigned int + ImGuiDataType_S64, // long long, __int64 + ImGuiDataType_U64, // unsigned long long, unsigned __int64 + ImGuiDataType_Float, // float + ImGuiDataType_Double, // double + ImGuiDataType_COUNT +}; + // A cardinal direction enum ImGuiDir_ { diff --git a/imgui_internal.h b/imgui_internal.h index 8d3e17e7e..d11e60776 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -251,17 +251,6 @@ enum ImGuiPlotType ImGuiPlotType_Histogram }; -enum ImGuiDataType -{ - ImGuiDataType_S32, // int - ImGuiDataType_U32, // unsigned int - ImGuiDataType_S64, // long long / __int64 - ImGuiDataType_U64, // unsigned long long / unsigned __int64 - ImGuiDataType_Float, - ImGuiDataType_Double, - ImGuiDataType_COUNT -}; - enum ImGuiInputSource { ImGuiInputSource_None = 0, @@ -1102,15 +1091,6 @@ namespace ImGui IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0); IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos, float radius); - IMGUI_API bool SliderScalar(const char* label, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); - IMGUI_API bool SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); - IMGUI_API bool VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); - - IMGUI_API bool DragScalar(const char* label, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); - IMGUI_API bool DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float v_speed, const void* v_min, const void* v_max, const char* format = NULL, float power = 1.0f); - - IMGUI_API bool InputScalar(const char* label, ImGuiDataType data_type, void* v, const void* step, const void* step_fast, const char* format = NULL, ImGuiInputTextFlags extra_flags = 0); - IMGUI_API bool InputScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* step, const void* step_fast, const char* format = NULL, ImGuiInputTextFlags extra_flags = 0); IMGUI_API bool InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format); From 5f464877ed7cb953bfd327507ef3fe8fca03ff02 Mon Sep 17 00:00:00 2001 From: omar Date: Mon, 7 May 2018 10:35:18 +0200 Subject: [PATCH 21/22] Internals: Declaring DragBehavior, SliderBehavior in there (no warantee given) as they may be useful to custom widgets. --- imgui.cpp | 4 +--- imgui_internal.h | 3 +++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 9251b47c0..3097e7c69 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -777,11 +777,9 @@ static void FocusFrontMostActiveWindow(ImGuiWindow* ignore_window); template static bool DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power); -static bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power); template static bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiSliderFlags flags); -static bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags = 0); } //----------------------------------------------------------------------------- @@ -8955,7 +8953,7 @@ static bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType d return value_changed; } -static bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags) +bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags) { switch (data_type) { diff --git a/imgui_internal.h b/imgui_internal.h index d11e60776..df5b06484 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1091,6 +1091,9 @@ namespace ImGui IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0); IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos, float radius); + IMGUI_API bool DragBehavior(ImGuiID id, ImGuiDataType data_type, void* v, float v_speed, const void* v_min, const void* v_max, const char* format, float power); + IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags = 0); + IMGUI_API bool InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback = NULL, void* user_data = NULL); IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format); From 4cabf599c4f9c15a175c2347e1aa052ec69de8c8 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 8 May 2018 23:35:26 +0200 Subject: [PATCH 22/22] Data types: Fix format srtings with leading blanks. Fix ColorEdit4() to not use obsolete formats (when using IMGUI_DISABLE_OBSOLETE_FUNCTIONS) (#643) --- imgui.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 3097e7c69..530c04bff 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8750,10 +8750,13 @@ static inline TYPE RoundScalarWithFormat(const char* format, ImGuiDataType data_ return v; char v_str[64]; ImFormatString(v_str, IM_ARRAYSIZE(v_str), fmt_start, v); + const char* p = v_str; + while (*p == ' ') + p++; if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) - v = (TYPE)atof(v_str); + v = (TYPE)atof(p); else - ImAtoi(v_str, (SIGNEDTYPE*)&v); + ImAtoi(p, (SIGNEDTYPE*)&v); return v; } @@ -11910,9 +11913,9 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag const char* ids[4] = { "##X", "##Y", "##Z", "##W" }; const char* fmt_table_int[3][4] = { - { "%3.0f", "%3.0f", "%3.0f", "%3.0f" }, // Short display - { "R:%3.0f", "G:%3.0f", "B:%3.0f", "A:%3.0f" }, // Long display for RGBA - { "H:%3.0f", "S:%3.0f", "V:%3.0f", "A:%3.0f" } // Long display for HSVA + { "%3d", "%3d", "%3d", "%3d" }, // Short display + { "R:%3d", "G:%3d", "B:%3d", "A:%3d" }, // Long display for RGBA + { "H:%3d", "S:%3d", "V:%3d", "A:%3d" } // Long display for HSVA }; const char* fmt_table_float[3][4] = {