Dynamic Text Field Height (Omnis Studio)

This method has been used successfully from Omnis Studio 5.32 through 11.2 --- in other words, properly battle-tested.

It provides a robust way to dynamically size a text field and its containing window based on: - Window resizing - Text content - Carriage returns - Style commands - Embedded bitmap elements


๐Ÿง  Philosophy

The approach follows a simple principle:

Let Omnis handle layout wherever possible.

Instead of forcing sizes: - Use kPagedPane auto-resizing - Use edgefloat - Use style sheets - Calculate only what Omnis cannot


๐Ÿงฑ Window Structure

Window
โ””โ”€โ”€ kPagedPane (messagePane)
    โ””โ”€โ”€ Background object (iMessage)
        โ””โ”€โ”€ Calculation: [iMessage]
            โ””โ”€โ”€ Instance variable: iMessage

Key Setup Notes

This allows: - Automatic resizing when window changes - Additional UI elements alongside message


โœ๏ธ Setting the Message

Calculate iMessage as con(
  'I am a message with CRs in it ',
  kcr,kcr,
  ' and ',
  style(kesccolor,kblue),
  ' style commands'
)

No special handling required --- styles and CRs are handled by the sizing routine.


โš™๏ธ Window Resize Logic

Run this: - On window open - Whenever iMessage changes

Set reference MessageRef to $cinst.$objs.MessagePane.$bobjs.iMessage

Calculate HeightRemainder as $cinst.$height-MessageRef.$height

Calculate NewHeight as tStringFields.$getWindowFieldHeightForAvailWidth(
  MessageRef.$fieldstyle,
  iMessage,
  MessageRef.$width
)

If $root.$height<NewHeight
  Breakpoint Uh oh! Message larger than screen
End If

Calculate NewHeight as NewHeight+HeightRemainder

If NewHeight<$cinst.$height
  Calculate NewHeight as $cinst.$height
End If

What This Does


๐Ÿ”ง Core Routine

$getWindowFieldHeightForAvailWidth

This is the real workhorse.

It: - Handles CRs - Handles wrapping - Strips style codes correctly - Accounts for bitmap width


Local Variables

Variable Default


bitmapWidth 18 bmpCount 0 height 0 linesToAdd 0 StyleSubString "" Token "" TokenString "" TokenWidth 0


Implementation

Calculate Height as $cinst.$getWindowFieldHeight(pFieldStyle)

Calculate LinesToAdd as 0
Calculate bitmapWidth as 18 

Calculate TokenString as pText

While pos(chr(27),TokenString)>0
  Calculate styleSubString as mid(TokenString,pos(chr(27),TokenString))
  Calculate styleSubString as mid(styleSubString,1,pos(chr(35),styleSubString))

  If asc(styleSubString,2)=kEscBmp
    Calculate bmpCount as bmpCount+$cinst.$replace(TokenString,styleSubString,'',TokenString)
  Else
    Calculate TokenString as replaceall(TokenString,styleSubString,'')
  End If
End While

Calculate Token as strtok(nam(TokenString),kCr)

While len(TokenString)>0|len(Token)>0

  If len(Token)=0
    Calculate LinesToAdd as LinesToAdd+1

  Else
    Calculate TokenWidth as $cinst.$getWindowFieldWidth(pFieldStyle,Token)+bmpCount*bitmapWidth
    Calculate LinesToAdd as LinesToAdd+int(TokenWidth/pAvailWidth)+1
  End If

  Calculate Token as strtok(nam(TokenString),kCr)
End While

Quit method Height*LinesToAdd

๐Ÿงพ Behaviour Notes


โš ๏ธ Limitations


๐Ÿ†š Alternative Approach (FontOps)

Simpler but less accurate:

Calculate pixWidth as FontOps.$wintextwidth(cMessage,'Chicago',12)
Calculate pixHeight as FontOps.$wintextheight('Chicago',12)
Calculate wrapWidth as msgFld.$width-20

Do msgFld.$height.$assign(
  ((pixHeight+4)*(int(pixWidth/wrapWidth)+2+crCount))
  +((pixHeight/2)*(crCount=0))
)

Downsides


โœ… Summary

This method:

In short:

Set it up once, and let Omnis behave properly.