NSTextField alignment when selected in NSTableView

157 views Asked by At

I have a programmatically created NSTableView with n rows and 1 column. The embedded text field is selectable, and not editable. I am able to observe the mouseDown event in the text field, but as you can see in the image, the selected row is repositioned and word wrapped. I suspect this may be related to the field editor, but my MacOS odyssey has proven me wrong innumerable times.

My question: What do I need to do to maintain the layout of the selected row to be consistent with the other rows in the table?

Update: adding a textfield.cell.wraps = false to the tableview delegate eliminated the word wrap, but still have the issue with the selected text field indented.

enter image description here

Code snippets:
From the table delegate:

    func tableView (_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?
    {
        let text = dataArray [row]
        var v = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier.init(rawValue: "TableColumn"), owner: self) as? MyTextFieldExt
        if v == nil
        {
            v = MyTextFieldExt ()
            v?.identifier = NSUserInterfaceItemIdentifier(rawValue: "TableColumn")
            v?.maximumNumberOfLines = 1
            v?.autoresizingMask = [.width]
            v?.setContentHuggingPriority(NSLayoutConstraint.Priority(rawValue: 251), for: .horizontal)
            v?.translatesAutoresizingMaskIntoConstraints = false
            
            v?.isEditable = false
            v?.isSelectable = true
            
            v?.cell?.wraps = false
        }
        
        v!.stringValue = text
        v!.font = NSFont.monospacedSystemFont(ofSize: 10, weight: .regular)
        v!.frame = CGRect(x: 0, y: 0, width: 3000, height: 0)

        return v!
    }

From the text field (custom) that traps the mouseDown:

    override func mouseDown(with event: NSEvent)
    {
        super.mouseDown(with: event)

        let cEditor = self.currentEditor() as? NSTextView
        let localPos = convert (event.locationInWindow, to: nil)

        let location = cEditor?.selectedRange().location

        if let r = cEditor?.selectedRange()
        {
            self.select(withFrame: self.frame, editor: cEditor!, delegate: self, start: r.location, length: r.length+10)
        }

    }

From the view controller that creates the scrollview, table view, and column:

    func setupTableView ()
    {
        let tableView = MyTableViewExt ()
        tableView.selectionHighlightStyle = .none
        
        tableView.headerView = nil
        tableView.columnAutoresizingStyle = .lastColumnOnlyAutoresizingStyle
        tableView.autoresizesSubviews = true
        tableView.autoresizingMask = [.width, .height]
        
        let column = NSTableColumn ()
        column.identifier = NSUserInterfaceItemIdentifier(rawValue: "TableColumn")
        column.width = 426
        column.minWidth = 40
        column.maxWidth = 1000
        column.resizingMask = [.autoresizingMask, .userResizingMask] // verify in debugger
        
        tableView.addTableColumn(column)

        tableView.delegate = self
        tableView.dataSource = self
        
        let scrollView = NSScrollView (frame: self.view.bounds)
        scrollView.autoresizesSubviews = true
        scrollView.autoresizingMask = [.height, .width]
        scrollView.translatesAutoresizingMaskIntoConstraints = false        
        scrollView.hasHorizontalScroller = true
        scrollView.hasVerticalScroller = true
        
        self.view.addSubview(scrollView)
        
        self.view.addConstraint(NSLayoutConstraint (item: self.view, attribute: .trailing, relatedBy: .equal, toItem: scrollView, attribute: .trailing, multiplier: 1.0, constant: 20))
        self.view.addConstraint(NSLayoutConstraint (item: scrollView, attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leading, multiplier: 1.0, constant: 20))
        self.view.addConstraint(NSLayoutConstraint (item: self.view, attribute: .bottom, relatedBy: .equal, toItem: scrollView, attribute: .bottom, multiplier: 1.0, constant: 20))
        self.view.addConstraint(NSLayoutConstraint (item: scrollView, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1.0, constant: 20))
        
        scrollView.documentView = tableView
    }
1

There are 1 answers

0
Hayseed On

So my problem was resolved by modifying the code in the text field mouseDown logic. The corrected code looks like this, with a change in setting the selected range:

    override func mouseDown(with event: NSEvent)
    {
        super.mouseDown(with: event)

        let cEditor = self.currentEditor() as? NSTextView
        let localPos = convert (event.locationInWindow, to: nil)
        let insertionPoint = cEditor?.characterIndexForInsertion(at: localPos)
        let location = cEditor?.selectedRange().location

        if let r = cEditor?.selectedRange()
        {            
//          self.select(withFrame: self.frame, editor: cEditor!, delegate: self, start: r.location, length: r.length+10) <-- Source of problem
            cEditor?.setSelectedRange(NSMakeRange(r.location, r.length+10)) <-- Solution to problem
        }
    }

And just to be clear, the statement of not requiring the textfield.cell?.wraps = false I made in a comment is incorrect. That line is needed in my table view delegate to avoid the word wrap.