B4J Question (B4X][BBcodeView] Is there a way to avoid a small inconsistency in rendering digits?

William Lancee

Well-Known Member
Licensed User
Longtime User
See attached screen shot. The txt file has the de facto text for BBCodeView.
StatsReport2.jpg
 

Attachments

  • BBCText.txt
    4.7 KB · Views: 106

Cableguy

Expert
Licensed User
Longtime User
The simpler answer to your question is: yes, just add a zero to your numbers, like 11.10
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
Thanks to both, I tried your solutions, but the decimals are still not lined up exactly, even with monospaced font. Adding another decimal place wasn't really an option, but I tried it and the problem remains. However, it is very minor.

On (very) close examination it looks like the kerning on the "1" is too small. But only if the "1" occurs at the end of the right justified span.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
It is not related to kerning. '0' is wider than '1'.

You are looking for fixed width font / monospace, however currently BCTextEngine doesn't treat such fonts in a special way and will still measure the character widths based on the actual width. I do plan to add support for monospace fonts.
 
Upvote 0

emexes

Expert
Licensed User
I've found that most proportional fonts have identical-width digits.

On my computer, this looks ok:

1234567890 iiwwwii
0987654321 iwiwiwi
1111111111 AAVVVAA
0000000000 AVAVAVA

but I agree that if there is real kerning happening, then all alignment bets are off.

1594215526515.png
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
Thanks all. @emexes , that's what I thought. I tried adding a bit of space at the end of the Span for narrower digits. Since I have multiple columns, this was not too successful. I'll try again.

B.T.W. I measured the digits, using cv.MeasureText. The widest digit is 4. The narrowest is 1. I could add invisible 1's (setting the text color to background). I'll try that next.

I could turn kerning off and rely on equal sized digits in the proportional font, but that affects all text too, reducing the quality of the report.

As I said, the problem is minuscule.
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
I added an invisible X (white color in my case) with a text size inversely proportional to the width of the last digit. See code.

adjusted.PNG


It is still a bit odd looking but better. The best solution would be monospaced font with appropriate kerning.

B4X:
Private Sub adjustWidth(s As String) As String
    Dim zz As Int = 65 / cv.MeasureText(s.charAt(s.Length - 1), xui.CreateDefaultFont(18)).Width
    Return s & $"[TextSize=${zz}][Color=white]X[/Color][/TextSize]"$
End Sub
 
Upvote 0

emexes

Expert
Licensed User
If you're ok with doing cv.MeasureText(), and if it's possible to do a [Span MinWidth=x Alignment=Right] within an outer [Span MinWidth=columnwidth Alignment=Left], perhaps you could measure the width of the text after the decimal point, and then adjust the size x of the inner [Span MinWidth=x Alignment=Right] accordingly.

Something like: x = 200 + cv.MeasureText(s.SubString(s.IndexOf(".")) so that you end up with eg:

[Span MinWidth=300 Alignment=Left][Span MinWidth=276 Alignment=Right]34.6[/Span][/Span]
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
I tried this and Spans don't seem to be embeddable (if that's a word).

I also tried using a label control inside the span. That works but is so far from the intention of TextEngine and BBCodeView, that I am reluctant to do it.

I tried the Plain tag to disable kerning temporarily, but that doesn't work.

I tried splitting the number into two parts and right justifying the first and left justifying the second in a separate span. Works, but no improvement over my current solution, and it is more complicated.

I could create a separate grid as a view and just put it in the BBCodeview, but that is also very inelegant.

To improve on what I have, I could add two invisible Xs surrounding the fraction, to pad the narrower digits on both sides.

Perhaps a temporary suspension of kerning would do the job, or optionally turning off kerning for digits. Maybe in the future.
 
Upvote 0

emexes

Expert
Licensed User
I tried splitting the number into two parts and right justifying the first and left justifying the second in a separate span. Works, but no improvement over my current solution, and it is more complicated.
I tried this (before I spotted that you already had āœŒ ) and it looked ok to me. Seemed less complicated than measuring width of text and inserting invisible padding characters, which sounds like a recipe for off-by-one-pixel misalignments.

1594257668765.png
 
Last edited:
Upvote 0

emexes

Expert
Licensed User
1594259746239.png

B4X:
Sub BBNumberFormat(N As String, IntWidth As Int, FracWidth As Int) As String
 
    Dim P As Int = N.IndexOf(".")
    If P < 0 Then    'no decimal point
        Dim LeftBit As String = N
        Dim RightBit As String = Chr(160)    'unicode non-breaking space, to stop empty span being purged
    Else
        Dim LeftBit As String = N.SubString2(0, P)    'integer bit
        Dim RightBit As String = N.SubString(P)    'decimal point and fraction bit
    End If
 
    Dim LeftSpan As String = "[span minwidth=" & IntWidth & " alignment=right]" & LeftBit & "[/span]"
    Dim RightSpan As String = "[span minwidth=" & FracWidth & " alignment=left]" & RightBit & "[/span]"
 
    Return LeftSpan & RightSpan
 
End Sub
 
Last edited:
Upvote 0
Top