eez-open / studio

Cross-platform low-code GUI and automation
https://www.envox.eu/studio/studio-introduction/
GNU General Public License v3.0
534 stars 91 forks source link

LVGL flow: measurement specific widget #227

Open fietser28 opened 1 year ago

fietser28 commented 1 year ago

A very common use case is to display and/or set measurement values (e.g. voltage, current, power, temperature,...) These have a specific way of displaying. I'm thinking of the following properties:

Nice to have: support styles for the different parts of the widget (digits before decimal point, digits behind decimal point, scale part of unit, unit, cursor)

fietser28 commented 1 year ago

I currently have the code below. It implements bullets 1,2 (it always shows prefix now) ,3 (excl. trailing zero's) and 4. It depends on sprintf and math functions like log10, pow, min, max.

static const char* SIScalePrefixes[] =        { "p", "n","\u03bc", "m", " ", "k", "M", "G", "T" };  
static const int   SIScalePrefixExponents[] = {-12,  -9,    -6,    -3,   0,   3 ,  6,   9,  12  };
static const int   SIScalePrefixExponentsBase = 4; // Index of 0 exponent
static const int   SIScaleprefixExpLast = sizeof(SIScalePrefixExponents)/sizeof(SIScalePrefixExponents[0]) - 1;

void value2str(char* str, float value, int accuracy_exp, int total_digits, int after_point, 
                bool show_prefix, const char* unit) 
    {
    // 0 is special case
    if (value == 0.0f)
    {
        sprintf(str, " 0  %s", unit);
        return;
    }

    // Determine sign
    char sign = value < 0.0f ? '-' : ' ';

    // Find exponent
    int exponentRaw = floor(log10(abs(value)));
    int exponent = std::max(exponentRaw, SIScalePrefixExponents[0]); // Lower limit of exponent
    exponent = std::min(exponent, SIScalePrefixExponents[SIScaleprefixExpLast]); // Upper limit of exponent
    exponent = std::max(exponent, accuracy_exp); // Don't go below accuracy

    // Find prefix, exponent and mantissa to nearest enginering scale.
    int exponentIndex = floor((float)exponent * 3.0f)/9 + SIScalePrefixExponentsBase;
    exponentIndex = std::max(exponentIndex, (int)ceil(accuracy_exp / 3) + SIScalePrefixExponentsBase);
    const char* prefix = SIScalePrefixes[exponentIndex];

    float mantissa = abs(value) / pow(10, SIScalePrefixExponents[exponentIndex]);                                 // raw mantissa

    // Determine the number of digits after .
    int fraction_digits = std::min(after_point, total_digits - (exponentRaw - exponent +1 ));
    fraction_digits = std::min(fraction_digits, SIScalePrefixExponents[exponentIndex] - accuracy_exp);

    // Format the string.
    sprintf(str, "%c%.*f%s%s", sign, fraction_digits, mantissa, SIScalePrefixes[exponentIndex], unit);

    } // value2str