How to use NSControl's edit(withFrame:editor:delegate:event:)?

293 Views Asked by At

I have a custom NSControl and I'm trying to get the function edit(withFrame:editor:delegate:event:) to work. Upon calling it I expect the field editor to show up in my view, but nothing happens.

I have read through the documentation for for the function, and I have created a minimal example:

class MyView: NSControl, NSControlTextEditingDelegate, NSTextDelegate {
  required init?(coder: NSCoder) {
    super.init(coder: coder)
    isEnabled = true
  }

  override func mouseDown(with event: NSEvent) {
    let editor = window!.fieldEditor(true, for: nil)!
    let rect = bounds.insetBy(dx: 10.0, dy: 10.0)
    self.edit(withFrame: rect, editor: editor, delegate: self, event: event)
  }

  func control(_ control: NSControl, textShouldBeginEditing fieldEditor: NSText) -> Bool {
    return true
  }

  func control(_ control: NSControl, textShouldEndEditing fieldEditor: NSText) -> Bool {
    self.endEditing(fieldEditor)
    return true
  }

  func textShouldBeginEditing(_ textObject: NSText) -> Bool {
    return true
  }
}

As you can see from the example, I'm not quite sure whether to conform to NSControlTextEditingDelegate or NSTextDelegate. None of the functions I implement seem to be called.

Or am I perhaps misunderstanding the purpose of the function? Should I be overriding it instead of calling it?

1

There are 1 best solutions below

0
TimTwoToes On

I'm no expert on the field editor, but browsing Apple's documentation seems to indicate, that it is designed to be implemented on the controls NSCell class and render the text yourself. If you want the field editor to appear in the above example, you must insert the field editor into the view hierarchy. It doesn't happen automatically.

class CustomTextControl: NSControl {
    override func mouseDown(with event: NSEvent) {
        // Make sure
        if currentEditor() == nil {
            if let controlWindow = window {
                if controlWindow.makeFirstResponder(controlWindow) {
                    // It is safe to claim the field editor
                    if let editor = controlWindow.fieldEditor(true, for: nil) as? NSTextView {
                        addSubview(editor)
                        editor.frame = bounds
                        edit(withFrame: bounds, editor: editor, delegate: nil, event: event)
                    }
                } else {
                    // Some other control has first responder, force first responder to resign
                    controlWindow.endEditing(for: nil)
                }
            }
        }
    }
}

I recommend that you read up on Apple's documentation on Cocoa Text Architecture Guide. Specifically Working with the Field Editor and the NSCell documentation. It is a non-trivial task.

What are you trying to achieve I wonder.