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
This commit is contained in:
Bastien Montagne 2014-01-08 17:04:10 +01:00
parent 8305fd8841
commit d5c9b509ec
Notes: blender-bot 2023-09-13 04:07:41 +02:00
Referenced by issue #112309, python - max property precision is showing unused digits.
4 changed files with 71 additions and 56 deletions

View File

@ -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__ */

View File

@ -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,68 +429,22 @@ 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;
}
}
}
CLAMP(prec, 0, PRECISION_FLOAT_MAX);
return prec;
return uiFloatPrecisionCalc(prec, value);
}
/* ************** LINK LINE DRAWING ************* */
/* 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)
{
rcti rect;
@ -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 {

View File

@ -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;
}

View File

@ -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];