From d5c9b509ec0e06318186f25212ffb2ba12177692 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 8 Jan 2014 17:04:10 +0100 Subject: Fix issues with float precision in numinput, like 'R 123' who would show additional 'noise' digits. Expose float precision helper in UI_interface.h API, so that numinput can use this helper as numbuttons already do. Reviewed By: campbellbarton Differential Revision: https://developer.blender.org/D186 --- source/blender/editors/include/UI_interface.h | 5 ++ source/blender/editors/interface/interface.c | 59 ++-------------------- source/blender/editors/interface/interface_utils.c | 56 ++++++++++++++++++++ source/blender/editors/util/numinput.c | 5 +- 4 files changed, 70 insertions(+), 55 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 735e7f35d61..10a4b383694 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -941,4 +941,9 @@ void UI_template_fix_linking(void); bool UI_editsource_enable_check(void); void UI_editsource_active_but_test(uiBut *but); +/* Float precision helpers */ +#define UI_PRECISION_FLOAT_MAX 7 + +int uiFloatPrecisionCalc(int prec, double value); + #endif /* __UI_INTERFACE_H__ */ diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index e6e175284d0..24924564ab4 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -78,9 +78,6 @@ #include "interface_intern.h" -#define PRECISION_FLOAT_MAX 7 -#define PRECISION_FLOAT_MAX_POW 10000000 /* pow(10, PRECISION_FLOAT_MAX) */ - /* avoid unneeded calls to ui_get_but_val */ #define UI_BUT_VALUE_UNSET DBL_MAX #define UI_GET_BUT_VALUE_INIT(_but, _value) if (_value == DBL_MAX) { (_value) = ui_get_but_val(_but); } (void)0 @@ -432,67 +429,21 @@ void uiExplicitBoundsBlock(uiBlock *block, int minx, int miny, int maxx, int max block->bounds_type = UI_BLOCK_BOUNDS_NONE; } -/* ************** LINK LINE DRAWING ************* */ - -/* link line drawing is not part of buttons or theme.. so we stick with it here */ - static int ui_but_float_precision(uiBut *but, double value) { int prec; - const double pow10_neg[PRECISION_FLOAT_MAX + 1] = {1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001}; /* first check if prec is 0 and fallback to a simple default */ if ((prec = (int)but->a2) == -1) { prec = (but->hardmax < 10.001f) ? 3 : 2; } - BLI_assert(prec <= PRECISION_FLOAT_MAX); - BLI_assert(pow10_neg[prec] == pow(10, -prec)); - - /* check on the number of decimal places need to display - * the number, this is so 0.00001 is not displayed as 0.00, - * _but_, this is only for small values si 10.0001 will not get - * the same treatment */ - value = ABS(value); - if ((value < pow10_neg[prec]) && - (value > (1.0 / PRECISION_FLOAT_MAX_POW))) - { - int value_i = (int)((value * PRECISION_FLOAT_MAX_POW) + 0.5); - if (value_i != 0) { - const int prec_span = 3; /* show: 0.01001, 5 would allow 0.0100001 for eg. */ - int test_prec; - int prec_min = -1; - int dec_flag = 0; - int i = PRECISION_FLOAT_MAX; - while (i && value_i) { - if (value_i % 10) { - dec_flag |= 1 << i; - prec_min = i; - } - value_i /= 10; - i--; - } - - /* even though its a small value, if the second last digit is not 0, use it */ - test_prec = prec_min; - - dec_flag = (dec_flag >> (prec_min + 1)) & ((1 << prec_span) - 1); - - while (dec_flag) { - test_prec++; - dec_flag = dec_flag >> 1; - } - - if (test_prec > prec) { - prec = test_prec; - } - } - } + return uiFloatPrecisionCalc(prec, value); +} - CLAMP(prec, 0, PRECISION_FLOAT_MAX); +/* ************** LINK LINE DRAWING ************* */ - return prec; -} +/* link line drawing is not part of buttons or theme.. so we stick with it here */ static void ui_draw_linkline(uiLinkLine *line, int highlightActiveLines) { @@ -1803,7 +1754,7 @@ static void ui_get_but_string_unit(uiBut *but, char *str, int len_max, double va if (float_precision == -1) { /* Sanity checks */ precision = (int)but->a2; - if (precision > PRECISION_FLOAT_MAX) precision = PRECISION_FLOAT_MAX; + if (precision > UI_PRECISION_FLOAT_MAX) precision = UI_PRECISION_FLOAT_MAX; else if (precision == -1) precision = 2; } else { diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index e1f39b1d556..812eb9345ac 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -36,6 +36,7 @@ #include "DNA_object_types.h" #include "BLI_utildefines.h" +#include "BLI_math.h" #include "BLI_string.h" #include "BLF_translation.h" @@ -224,3 +225,58 @@ int uiIconFromID(ID *id) return (ptr.type) ? RNA_struct_ui_icon(ptr.type) : ICON_NONE; } + +/********************************** Misc **************************************/ + +/** + * Returns the best "UI" precision for given floating value, so that e.g. 10.000001 rather gets drawn as '10'... + */ +int uiFloatPrecisionCalc(int prec, double value) +{ + static const double pow10_neg[UI_PRECISION_FLOAT_MAX + 1] = {1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7}; + static const double max_pow = 10000000.0; /* pow(10, UI_PRECISION_FLOAT_MAX) */ + + BLI_assert(prec <= UI_PRECISION_FLOAT_MAX); + BLI_assert(pow10_neg[prec] == pow(10, -prec)); + + /* check on the number of decimal places need to display the number, this is so 0.00001 is not displayed as 0.00, + * _but_, this is only for small values si 10.0001 will not get the same treatment. + */ + value = ABS(value); + if ((value < pow10_neg[prec]) && (value > (1.0 / max_pow))) { + int value_i = (int)((value * max_pow) + 0.5); + if (value_i != 0) { + const int prec_span = 3; /* show: 0.01001, 5 would allow 0.0100001 for eg. */ + int test_prec; + int prec_min = -1; + int dec_flag = 0; + int i = UI_PRECISION_FLOAT_MAX; + while (i && value_i) { + if (value_i % 10) { + dec_flag |= 1 << i; + prec_min = i; + } + value_i /= 10; + i--; + } + + /* even though its a small value, if the second last digit is not 0, use it */ + test_prec = prec_min; + + dec_flag = (dec_flag >> (prec_min + 1)) & ((1 << prec_span) - 1); + + while (dec_flag) { + test_prec++; + dec_flag = dec_flag >> 1; + } + + if (test_prec > prec) { + prec = test_prec; + } + } + } + + CLAMP(prec, 0, UI_PRECISION_FLOAT_MAX); + + return prec; +} diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c index 2828973e91d..b9459d57f26 100644 --- a/source/blender/editors/util/numinput.c +++ b/source/blender/editors/util/numinput.c @@ -45,6 +45,7 @@ #endif #include "ED_numinput.h" +#include "UI_interface.h" /* NumInput.val_flag[] */ @@ -80,13 +81,15 @@ void outputNumInput(NumInput *n, char *str) { short i, j; const int ln = NUM_STR_REP_LEN; - const int prec = 4; /* draw-only, and avoids too much issues with radian->degrees conversion. */ + int prec = 2; /* draw-only, and avoids too much issues with radian->degrees conversion. */ for (j = 0; j <= n->idx_max; j++) { /* if AFFECTALL and no number typed and cursor not on number, use first number */ i = (n->flag & NUM_AFFECT_ALL && n->idx != j && !(n->val_flag[j] & NUM_EDITED)) ? 0 : j; if (n->val_flag[i] & NUM_EDITED) { + /* Get the best precision, allows us to draw '10.0001' as '10' instead! */ + prec = uiFloatPrecisionCalc(prec, (double)n->val[i]); if (i == n->idx) { const char *heading_exp = "", *trailing_exp = ""; char before_cursor[NUM_STR_REP_LEN]; -- cgit v1.2.3