Sizing a control to fit all text

I have several blocks of text that can each be long or short or anywhere in between. I want to display them as a list, but with the ability to show each block as a small 2 or 3 line preview or expand it to show the entire text. I want the text to be selectable, but not editable.

I am currently using a DesktopLabel to display the text, and calculating the height of the label for the preview is easy and accurate, but getting the correct height for the expanded mode is proving to be frustrating. I am currently using this function:

Public Function Height(Extends val As String, wrapWidth As Double, fontName As String, fontSize As Double, isBold As Boolean = False, isItalic As Boolean = False) As Double
Dim p As New Picture(1, 1)

p.Graphics.FontName = fontName
p.Graphics.FontSize = fontSize
p.Graphics.Bold = isBold
p.Graphics.Italic = isItalic

Return p.Graphics.TextHeight(val, wrapWidth)

End Function

The calculated height is generally too short, but by how much seems to change with how many EndOfLines there are and how long the text is. I haven’t really found a pattern. I’m thinking that the label has some padding that the Graphics object doesn’t, and it could possibly wrap different than a graphics object?

Any ideas? Or another approach? A different control to display the text in, but still be able to do the expand/collapse action?

I have been playing with accounting for padding in the label and it seems to be mostly accurate now - it will sometimes be an extra line too tall but it’s not cutting off the text anymore.

I get the width of the label and subtract from that the padding, and then pass that number into the height function as the wrap width. Then I add the padding to the calculated height and set Label.Height to that. FWIW a padding value of 16 is working pretty well.

I am still open to other suggestions if there is a better way.

Maybe the FlowLayout Plugin by @Björn_Eiríksson from Einhugur can help with this?

There’s a bug already reported: https://tracker.xojo.com/xojoinc/xojo/-/work_items?sort=created_date&state=opened&search=TextHeight&first_page_size=20&show=eyJpaWQiOiI2OTY1NyIsImZ1bGxfcGF0aCI6Inhvam9pbmMveG9qbyIsImlkIjo2MTcyN30%3D

It’s in the category of those framework bugs that last for several years and are impacting basic functionalities, like DesktopTextArea.LineNumAtCharPos which has never been reliable since at least Cocoa was a target: https://tracker.xojo.com/xojoinc/xojo/-/work_items/43874
I’m really tired of them.

There is this one as well:
https://tracker.xojo.com/xojoinc/xojo/-/work_items/51461

What platforms are you targetting?

Yes, I chose to not list them all, to not overload the forum software :sweat_smile:

MacOS and Windows.

I just got Bjorn’s plugins earlier this week - I give that a try and see if it’s any better.

OK.

On macOS you should be able to do this using Declares or the MBS plugins. Here is the code we use in a v1 API Label control subclass method.

    Dim nsTextFieldObj As NSTextFieldMBS
    Dim nsTextFieldCellObj As NSTextFieldCellMBS
    Dim boundsNSRectObj As NSRectMBS
    Dim boundsCellSizeObj As NSSizeMBS
    
    'retrieve the nstextfield and nstextfieldcell for the control
    nsTextFieldObj = Self.NSTextFieldMBS
    nsTextFieldCellObj = nsTextFieldObj.cell
    
    
    'define the bounds which is the nstextfield bounds width (which may be different to the control width) and a large height
    boundsNSRectObj = New NSRectMBS
    boundsNSRectObj.Width = nsTextFieldObj.bounds.Width
    boundsNSRectObj.Height = 99999
    
    
    'retrieve the cell size that fits the text and update the height
    boundsCellSizeObj = nsTextFieldCellObj.cellSizeForBounds(boundsNSRectObj)
    
    Self.Height = Ceil(boundsCellSizeObj.Height)

On MS-Windows, things are more difficult. Xojo Graphics use Direct2D (DirectWrite) but the UI controls when not using WinUI use GDI / GDI+ which are two completely different technologies. We solved this using the Win32 API via Declares. Unfortunately, I cannot share this code but you should start by looking at the DrawTextW API call.

@kevin_g Thanks for the code and pointing me in the right direction for Windows. I appreciate it!