7

I would like to implement a NSTokenField that will show Tokens that - when hovering over the token - show a removal icon. Subsequently when I click on the icon I want the token to be removed.

After a lot of searching it seems that this is not possible with the standard NSTokenField. If someone knows how please let me know.

I have taken a look at https://github.com/octiplex/OEXTokenField and based on that code I have made a CustomTokenField implementation in Swift. So far so good I have a working CustomTokenField and when I hover over the token it shows a removal icon.

The next phase turns out to be a problem that I cannot figure out myself. How can I get a click on the token trigger a callback.?

The token class is derived from the NSTextAttachmentCell and the CustomTokenField is derived from the NStokenField:

class CustomTokenAttachmentCell: NSTextAttachmentCell {
    . . .
}

class CustomTokenField: NSTokenField {
    . . .
}

I have tried to approach this using two different angles:

Through the CustomTokenAttachmentCell

The NSTextAttachmentCell implements the NSTextAttachmentCellProtocol.

public protocol NSTextAttachmentCellProtocol : NSObjectProtocol {
    . . .
    public func wantsToTrackMouse() -> Bool
    public func highlight(flag: Bool, withFrame cellFrame: NSRect, inView controlView: NSView?)
    public func trackMouse(theEvent: NSEvent, inRect cellFrame: NSRect, ofView controlView: NSView?, untilMouseUp flag: Bool) -> Bool
    . . .
}

This is hopeful. So I implemented these methods in CustomTokenAttachmentCell and wantsToTrackMouse() is actually being called. I have implemented that to return ‘true’.

override func trackMouse(theEvent: NSEvent, inRect cellFrame: NSRect, ofView controlView: NSView?, untilMouseUp flag: Bool) -> Bool {
    Swift.print(“trackMouse”)
    return true
}

override func highlight(flag: Bool, withFrame cellFrame: NSRect, inView controlView: NSView?) {
    Swift.print("highlight")
}

override func wantsToTrackMouse() -> Bool {
    Swift.print(“trackMouse”)
    return true
}

The other two methods are never called. Is there something else that needs to be done to make that they are being called?

Through the CustomTokenField

I also tried to approach this from the CustomTokenField. It is possible to get mouse events using MouseDown(), however I could not find a way to actually access the Tokens from the cells.

I have seen many posts here on StackOverflow and I have seen tips but none of them seems to point in the right direction.

Somehow I have come to the conclusion that you can only get mouse events in the case there is a NSControl in the hierarchy. For tokens that is not the case. An NSControl is part of the hierarchy for views hence my attempt to achieve this through the CustomTokenField but I run in a dead-end there as well. E.g. this question Clicking token in NSTokenField is exactly the same but setting the action or target will generate a fatal error because the setAction and setTarget are stubs for the base class.

I am a beginning programmer on Coacoa, so hopefully this is just a matter of lack of knowledge.

Any advise would be appreciated.

Community
  • 1
  • 1
Fred Appelman
  • 716
  • 5
  • 13
  • Did you try implementing the other TrackMouse methods of the `NSTextAttachmentCell` protocol? – Willeke Aug 27 '16 at 00:52
  • Yes I did. I also implemented hitTestForEvent(event: NSEvent, inRect cellFrame: NSRect, ofView controlView: NSView) and wantsToTrackMouseForEvent(theEvent: NSEvent, inRect cellFrame: NSRect, ofView controlView: NSView?, atCharacterIndex charIndex: Int). No change. – Fred Appelman Aug 27 '16 at 07:27
  • `OEXTokenField` implements `NSTextViewDelegate` method `textView:clickedOnCell:inRect:atIndex:`. – Willeke Aug 27 '16 at 09:38
  • I am aware and the problem is that doesn't get called. That is also a part I didn't understand from that code. I implemented it to be complete but it was never called. Also it is the token that should receive the mouse events and not the TokenField. I can get the mouse position in the TokenField but I don't know how to map this on the Token. – Fred Appelman Aug 27 '16 at 10:41
  • `clickedOnCell` is called in `OEXTokenField` because the tokenfield is the delegate of the field editor. – Willeke Aug 27 '16 at 20:37
  • Can't you add a transparant area to the removal icon to catch mousedowns? – Willeke Aug 27 '16 at 21:40
  • I will try both suggestions. Thank you. – Fred Appelman Aug 29 '16 at 04:41
  • @Willeke: Can you be a bit more specific? The delegate of the `CustomTokenField` is of the type `NSTokenFieldDelegate` and it inherits from `NSTextFieldDelegate` and not `NSTextViewDelegate`. The `NSTextFieldDelegate` doesn't have the mouse methods because it isn't a view. Am I missing what you suggested? – Fred Appelman Aug 30 '16 at 08:56
  • Do you know what [the field editor](https://developer.apple.com/library/prerelease/content/documentation/TextFonts/Conceptual/CocoaTextArchitecture/TextFieldsAndViews/TextFieldsAndViews.html#//apple_ref/doc/uid/TP40009459-CH8-50168) is? – Willeke Aug 30 '16 at 10:50
  • Apparently not. Please explain. – Fred Appelman Aug 30 '16 at 13:04
  • The field editor is a single NSTextView object that is shared among all the controls, including text fields, in a window. The focused text field uses this text view for editing. The focused text field is the delegate of the text view. and can implement `NSTextViewDelegate` methods. – Willeke Aug 30 '16 at 13:33
  • Is the token field focused or should click also work when another control has focus? – Willeke Aug 30 '16 at 13:34
  • The token field has focus. Let me look into this and see if this leads to a solution. Thank you for your support. – Fred Appelman Aug 31 '16 at 19:39
  • @Willeke: Again thank you for your patience. I am still running in a dead end. I have read everything I could about the *Field Editor* and it seems that the *Field Editor* only gets enabled when the content is being **edited**. In my case there is no editing, just clicking. I have tried to access the *Field Editor* through the Window and setup the delegate before hand but that doesn't seem to work. Am I wrong in concluding it only works if I'm editing? Currently the behavior of the TokenField is set to 'None'. – Fred Appelman Sep 02 '16 at 18:54
  • Apparently behavior None is not going to work. Is behavior Selectable an option? – Willeke Sep 03 '16 at 01:55

1 Answers1

0

Have you tried adding an NSButton on top of all of the whole CustomTokenAttachmentCell view? Then add an @IBOutlet action to the button for the click and pass that via delegation to the TokenField where you can control the tokens that are displayed.

I am also trying to implement this in my app, so if you are able to share any of the code it would be greatly appreciated. Thanks!

Gligor
  • 2,862
  • 2
  • 33
  • 40