Skip to content

DesktopTextArea Without Soft Wrapping Lines on macOS

When adding a DesktopTextArea to your macOS app, just drag it from the Library into a Window (or Container) in the layout editor of the Xojo IDE. It works out of the box with native macOS behavior. But what if you want to change that native behavior, like, for example, disabling soft wrapping? Keep reading to learn how.

On macOS, DesktopTextArea uses the native macOS control. When you need to tweak its behavior, Declares can help. For example, by default text lines are soft-wrapped to the control’s width. But sometimes you may want to turn that off so each line displays in full, making the text easier to read line by line.

If you need to do just that, without resorting to other options because the use of a DesktopTextArea is what you really need to use, then put the following snippet of code into the Opening event handler for the DesktopTextArea instance:

If that’s exactly what you need to do and you want to stick with DesktopTextArea, just add the following code to the Opening event of your DesktopTextArea:

#If TargetMacOS Then
  // At this point we are getting really the handle to
  // the wrapping object: NSScrollView
  Var tAObj As Ptr = Me.Handle
  
  Declare Function Subviews Lib "AppKit" Selector "subviews" (obj As Ptr) As Ptr
  Declare Function ObjectAtIndex Lib "AppKit" Selector "objectAtIndex:" (obj As Ptr, index As Integer) As Ptr
  
  // We need to get the real NSTextView view that is set
  // inside the clip view set inside the NSScrollView
  Var subViewsFromScroll As Ptr = Subviews(tAObj)
  Var clipView As Ptr = ObjectAtIndex(subViewsFromScroll, 1)
  Var subViewsFromClipView As Ptr = Subviews(clipView)
  
  //…and here it is
  Var textAreaView As Ptr = ObjectAtIndex(subViewsFromClipView, 2)
  
  // At this point we have the real NSTextView from the wrapping NSScrollerView!
  
  Declare Function TextContainer Lib "AppKit" Selector "textContainer" (obj As Ptr) As Ptr
  Declare Sub SetWidthTracksTextView Lib "AppKit" Selector "setWidthTracksTextView:" (obj As Ptr, value As Boolean)
  Declare Sub SetContainerSize Lib "AppKit" Selector "setContainerSize:" (obj As Ptr, size As CGSize)
  Declare Sub SetMaxSize Lib "AppKit" Selector "setMaxSize:" (obj As Ptr, size As CGSize)
  
  // Retrieving the NSTextContainer
  Var tcObj As Ptr = TextContainer(textAreaView)
  SetWidthTracksTextView(tcObj, False)
  
  Var newSize As CGSize
  newSize.Width = 100000 // Arbitrary value… we only need to set it to a really high value!
  newSize.Height = 100000
  
  // And setting a new max width size to it.
  SetMaxSize(tAObj, newSize)
  
  // …and also using the same value for the size of the NSTextContainer
  SetContainerSize(tcObj, newSize)
#Endif

The code above uses the CGSize data type, a Struct added to the Window (though you’ll likely want to place it in a Module instead). It has two members:

  • Width As Integer
  • Height As Integer

We need to use this Data Type / Struct because some macOS framework methods from NSScrollView and NSTextContainer expect it.

After adding the code, enable the ‘Has Horizontal Scrollbar’ property in the Inspector for your DesktopTextArea. Run the app and you’ll see that soft wrapping is no longer applied!

What other customized behaviors have you added to macOS DesktopTextArea instances via Declares? Go ahead and share the code so other users can benefit from them.

Happy coding!

Javier Menendez is an engineer at Xojo and has been using Xojo since 1998. He lives in Castellón, Spain and hosts regular Xojo hangouts en español. Ask Javier questions on Twitter at @XojoES or on the Xojo Forum.