Big `Graphics.TextWidth` bug?

My never ending battle with the code editor I’m writing continues.

It seems that Graphics.TextWidth (and Graphics.StringWidth although deprecated) return the wrong value if the passed String (or Text) contain a horizontal tab character (&u0009).

// We'll try to get the length of `a	b`

// Get a graphics context.
Var p As TrueWindow.BitmapForCaching(800, 600)
Var g As Graphics = p.Graphics

Var a As String = "a"
Var tab As String = &u0009
Var b As String = "b"
Var aTabb As String = a + tab + b // a	b

Var aWidth As Double = g.TextWidth(a) // 6.62
Var tabWidth As Double = g.TextWidth(tab) // 28
Var bWidth As Double = g.TextWidth(b) // 7.37
Var aTabWidth As Double = g.TextWidth(aTabb) // 35.37

As you can see, the correct length should be 6.62 + 28 + 7.37 (41.99) but it’s reported as 35.37.

This happens with longer phrases:

Var hello As String = "hello"
Var world As String = "world"
Var helloTabWorld As String = "hello" + &u0009 + "world" // hello	world
Var helloWidth As Double = g.TextWidth(hello) // 27.076
Var worldWidth As Double = g.TextWidth(world) // 31.125
Var helloTabWorldWidth As Double = g.TextWidth(helloTabWorld) // 59.125

In this case, the length should be 27.076 + 28 + 31.125 (86.201) but it’s reported as 59.125. This is the width of the tab (28) plus the characters after the tab (31.125).

It seems that Graphics.TextWidth and Graphics.StringWidth are ignoring the characters before the tab character and only reporting the length of the tab and the characters afterwards.

Can someone confirm that this is a bug (I only have macOS available at present to test).

I should mention that I actually need to use Text not String (see this thread) but the bug affects both data types.

What happens, if you explicit set the font before?

g.FontName = "System"
g.FontSize = 0

No difference.

Is the width of the tab wrong? The b is 7, the tab is has a width of 28 which is 4 times the width of the b but it’s barely wider than the b. Other than that I don’t see a problem with the calculation.

What about the second example (hello world)?

If "hello" is 27.076 pixels wide, the tab character is 28 pixels wide and "world" is 31.125 pixels wide, why is "hello world" (with a tab inbetween) only 59.125? That’s the tab width plus the "world" width added together.

Does it increase by 28 if you have 2 tabs in a row instead of 1? What if you use 4 spaces instead?

1 Like
Var aTABb As String = a + tab + b
Var aTABTABb As String = a + tab + tab + b

Var aTABbWidth As Double = g.TextWidth(aTABb) // 35.9091796875
Var aTABTABbWidth As Double = g.TextWidth(aTABTABb) // 63.9091796875

If you add another tab you get an increase of 28 which is the exact width of a tab. It’s definitely truncating characters before the first tab,

Try a monospace font and you’ll get the expected results …

Nope. I get the same using Source Code Pro (monospace):

Tab is also to build a column where the data start exact at the same place.
its more a variable width so you can not just add single values together as one width.
Ashampoo_Snap_Donnerstag, 29. Juli 2021_15h56m38s_001_Neues Textdokument.txt - Editor

4 Likes

That’s not the expected behaviour with a monospaced font however (which is all my code editor uses).

What is that you expect in MarkusR example? The b in different places to the right depending on the number of a?

i know that some editors can replace the tab as spaces.
if me change the font to source code pro the screenshot from notepad would look same.

Ok confirmed, then it sure looks like a bug…:wink:

A quick test on my Mac seems to indicate that the tabs up to a certain width are aligned to a set of tab stops. After that the width seems to increase consistently.

This is the test code I used (edited):

NOTE. If you change s2 to be a single character then you should see this more clearly.

Dim p As New Picture(1, 1)
Dim s As String
Dim s2 As String
Dim s3 As String
Dim i As Int32

p.Graphics.TextFont = "SmallSystem"
p.Graphics.TextSize = 0

s = "Hello"
System.DebugLog s + " = " + Str(p.Graphics.StringWidth(s))

s2 = "Me"
System.DebugLog s2 + " = " + Str(p.Graphics.StringWidth(s2))

s3 = Chr(9) + s
For i = 1 To 100
  System.DebugLog Str(i) + " = " + Str(p.Graphics.StringWidth(s3))
  
  s3 = s2 + s3
Next

With a monospaced font in Word on Windows 10 I see the same results as Markus

OK guys. It looks like @MarkusR is correct. The tab width is variable. I guess code editors handle things differently than I had engineered in this regards.

No worries. I shall endeavour to work around it. The easiest fix is to replace tabs with spaces but some languages (such as Python) don’t always play nice with that.

Thanks to everyone who has chimed in. I’ve learned something new!

1 Like

python only gets mad if you mix tabs and spaces, so using all spaces will be fine. I set all my text editors to tab=4 spaces and have never had an issue.