3

I have a NSPopover window which I would like to add touchbar support to. I've managed to implement touchbar support for a standard NSWindow, but following the same procedure for my popover doesn't result in any touchbar items appearing in the xCode touchbar simulator.

I am implementing makeTouchbar and the NSTouchBarDelegate in a NSViewController which is presented as a NSPopover. makeTouchBar and the delegate functions are being called, but nothing shows in the touchbar (in the below code blocks both Touchbar and hint are logging).

I'm worried that NSPopover windows do not trigger the touchbar as the active app, even though it has keyboard focus. How can I show touchbar items for a NSPopover window?

//MARK: Touch bar
@available(OSX 10.12.1, *)
override func makeTouchBar() -> NSTouchBar? {
    Swift.print("Touchbar.")

    let touchBar                        = NSTouchBar()
    touchBar.delegate                   = self
    touchBar.customizationIdentifier    = .touchBar
    touchBar.defaultItemIdentifiers     = [.tbHint, .colourC] 

    return touchBar

}

@available(OSX 10.12.1, *)
extension RememberViewController: NSTouchBarDelegate {

    func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItemIdentifier) -> NSTouchBarItem? {

        switch identifier{
        case NSTouchBarItemIdentifier .tbHint:
            Swift.print("hint")
            let buttonView  = NSCustomTouchBarItem(identifier: identifier)
            let button      = NSButton(title: "Hint", target: self, action: #selector(showHint))
            buttonView.view = button
            return buttonView

        case NSTouchBarItemIdentifier .colourC:
            let colorPicker: NSColorPickerTouchBarItem
            colorPicker = NSColorPickerTouchBarItem.colorPicker(withIdentifier: identifier)

            colorPicker.customizationLabel = "Color Picker"
            colorPicker.target = self
            colorPicker.action = #selector(showHint)

            return colorPicker

        default:
            return nil
        }


    }
}
glenstorey
  • 5,134
  • 5
  • 39
  • 71

2 Answers2

3

Check out the NSTouchBar Catalog Sample from Apple. The latest revision has an example for exactly your use case. It's called the Background Window (you have to show it via the Window Menu in the built app).

enter image description here

They are loading a BackgroundImagesViewController with a NSPopover segue in the storyboard and creating the NSTouchBar like this:

@available(OSX 10.12.2, *)
class BackgroundImagesViewController: NSViewController {
  override func makeTouchBar() -> NSTouchBar? {
    let touchBar = NSTouchBar()
    touchBar.delegate = self
    touchBar.customizationIdentifier = .scrubberBar
    touchBar.defaultItemIdentifiers = [.imageScrubber]
    touchBar.customizationAllowedItemIdentifiers = [.imageScrubber]
    touchBar.principalItemIdentifier = .imageScrubber

    return touchBar
  }
}

The best thing is to check out the example file from Apple.

alexkaessner
  • 1,966
  • 1
  • 14
  • 39
  • consider adding the relevant info to your answer. Links can get broken/removed by the website owners – pedrorijo91 Jan 15 '17 at 12:12
  • Sorry, I can't give too much helpful technical details here. I just wanted to share the link to the Sample. – alexkaessner Jan 15 '17 at 12:39
  • I don't think you are talking about the same thing. A Popover in Touch Bar parlance is a type of control, but the base question is about showing a custom touch bar for an NSPopover and I also have been unable to get that working. – RealCasually May 18 '17 at 05:02
  • 1
    No that's what I mean. Take a look inside the Sample from Apple. They're showing exactly what the question asks. You can find it in the _Background Window_ (shown via the _Window_ Menu). See my updated answer. – alexkaessner May 18 '17 at 07:04
0

I try some test. I overrode the method makeTouchBar of NSPopover and NSViewController, when it popup, it will not call that method. But when I add a TextField on it, it get the focus of keyboard, and magically the makeTouchBar method was called. And the touch bar shows nothing but an icon of keyboard. Thus, I think I can override the makeTouchBar method of NSTextField, but I failed. I Googled, they recommend NSTextView, and I override it, it works!

But actually it seems like cheating the system.

Controllers

The calling code:

@IBAction func addAction(_ sender: Any) {
    let addingController = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil).instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("controller_adding")) as! AddViewController
    let popover = NSPopover()
    popover.contentViewController = addingController
    popover.behavior = .semitransient

    popover.show(relativeTo: addButton.frame, of: addButton, preferredEdge: NSRectEdge.maxY)
}

Here is the popover's ViewController

import Cocoa

class AddViewController: NSViewController {


    @IBAction func OKAction(_ sender: Any) {
        print("OK")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do view setup here.
        let touch = MyTextView()
        touch.setController(self)
        view.addSubview(touch)  
    }
}

And here is the overrode NSTextView.

class MyTextView : NSTextView
{

    var controller : AddViewController?

    func setController(_ controller : AddViewController)
    {
        self.controller = controller
    }

    @objc func action()
    {
        controller?.OKAction(self)
    }

    override func makeTouchBar() -> NSTouchBar? {

        let touchbar = NSTouchBar()
        let item_add = NSTouchBarItem.Identifier("item_add")
        touchbar.customizationIdentifier = NSTouchBar.CustomizationIdentifier("add")

        touchbar.customizationAllowedItemIdentifiers = [item_add]
        touchbar.defaultItemIdentifiers = [item_add]

        touchbar.delegate = self

        return touchbar
    }

    override func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {
        let item = NSCustomTouchBarItem(identifier: identifier)
        let item_add = NSTouchBarItem.Identifier("item_add")
        var itemDescription = ""
        switch identifier {
        case item_add:
            itemDescription = "Add Button"
            item.view = NSButton(image: NSImage(named: NSImage.Name("NSTrashEmpty"))!, target: self, action: #selector(action))
        default:
            print("???")
        }

        item.customizationLabel = itemDescription
        return item
    }
}

I'm not familiar with macOS developing, and I don't know how to get the focus on popover, so I used this kind of method to achieve the function.

李jack
  • 1
  • 1