It is currently April 26th, 2024, 12:28 pm

How to print exactly 'n' digits.

Tips and Tricks from the Rainmeter Community
Orum
Posts: 1
Joined: July 31st, 2010, 4:03 pm

How to print exactly 'n' digits.

Post by Orum »

I wanted to be able to print exactly 'n' digits (in my case, 3), regardless of what the value of the number is. E.g., if the measure value is "155551", it would print "156 K"; if it's "15551", you would print "15.6 K"; and if it's "1551", print "1.55 K", and so on and so forth. The problem is, this is not easy to do in rainmeter! As you will see, this is not for the faint of heart.

In this example, there are a few things to note:
  • I consider 1 KB to equal 1024 bytes (you can change a few constants if you want it the other way 'round).
  • There is a substantial delay, because calc measures lag behind a cycle, and I use several tiers to accomplish this.
  • This is an example that uses cumulative network download as the "parent" measure.
  • Certain style elements MUST be correct for it to display properly, and they are highlighted.
  • The names are not very descriptive, so change them to your liking.
  • This is very ugly but I don't know of a better way to do it.
That said, let's look at the config...
; Measures

[MeasureTotalDownload]
Measure=NetIn
Cumulative=1

[CalcThreeA]
Measure=Calc
Formula=MeasureTotalDownload < 1000 ? 0 : (MeasureTotalDownload < 1024000 ? 1 : (MeasureTotalDownload < 1048576000 ? 2 : (MeasureTotalDownload < 1073741824000 ? 3 : 4)))

[CalcThreeB]
Measure=Calc
Formula=MeasureTotalDownload / 1024 ** CalcThreeA

[CalcThreeC]
Measure=Calc
Formula=CalcThreeA
Substitute="0":" B","1":" KB","2":" MB","3":" GB","4":" TB"

[CalcThreeD]
Measure=Calc
Formula=FLOOR(CalcThreeB) < 100 ? FLOOR((CalcThreeB % 1) * 10) : 1000
Substitute="1000":"","0":".0","1":".1","2":".2","3":".3","4":".4","5":".5","6":".6","7":".7","8":".8","9":".9"

[CalcThreeE]
Measure=Calc
Formula=FLOOR(CalcThreeB) < 10 ? FLOOR((CalcThreeB % 0.1) * 100) : 1000
Substitute="1000":""

[CalcThreeF]
Measure=Calc
Formula=FLOOR(CalcThreeB)

; Styles

[TextStyleTot]
NumOfDecimals=0
AutoScale=0
Text="%1%2%3%4"

Hidden=0

; Meters

[ItemValue]
Meter=STRING
MeterStyle=TextStyleTot
MeasureName=CalcThreeF
MeasureName2=CalcThreeD
MeasureName3=CalcThreeE
MeasureName4=CalcThreeC
Now, a quick explanation is in order.
  • CalcThreeA figures out when we need to divide, and returns our exponent for our divisor.
  • CalcThreeB returns the scaled value of the parent measure.
  • CalcThreeC returns the suffix (KB, MB, etc.).
  • CalcThreeD returns our first digit after the decimal point (assuming we have one), as well as adding in the decimal point itself.
  • CalcThreeE returns the second digit after the decimal point if we have one.
  • CalcThreeF returns the primary value (0-999).
There's no easier way I can think of doing this, because of how rainmeter prints measures in the string meter. It treats them as a number, prints them, and then does the substitution after they've been printed. The thing that makes this so hard is that you can't set the decimal places dynamically and use AutoScale, because the NumOfDecimals is read when the config is loaded and never again (aside from refreshes/restarts, obviously). So, if you change it, it has no effect, and you have to approach it through this roundabout way. Also, you can't use separate NumOfDecimals for each individual measure in your meter--the setting is meter-wide. Worst part is you need this many calcs for each value you want to scale. Perhaps rainmeter can add this option as a feature in the future so we don't need to use such an ugly method? :)

Anyway, enjoy, and let me know if you think of any improvements.

Edit: There are some bugs in this, where some rounding leads to "10" for a digit. I'm working on fixing it and I'll update the post when done.
Edit2: Fixed so it will always print 3 digits, but no more rounding as a result (e.g. 10239 bytes will round to 9.99 KB instead of the ideal 10.0 KB)