Bruce McLeod
Bruce McLeod

Reputation: 1382

NSViewController in a NSPopover via segues from an NSStatusItem in swift on 10.10

I have been trying unsuccessfully for a few hours trying to get an NSPopover to load an NSViewController to show from an NSStatusItem, ideally using a segue in swift.

I have managed to get the events to fire correctly from the new NSStatusItem.button implemententaiton in DP3, but I can't work out how to programatically add a segue to the NSButton. The code I have working so far is ...

class AppDelegate: NSObject, NSApplicationDelegate {

var statusItem : NSStatusItem

init() {
    statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(CGFloat(-2))

    // When the bug is fixed, replace the line above with this line.
    //statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(CGFloat(NSSquareStatusItemLength))
}

override func awakeFromNib() {
    SetupStatusItem()
}

func SetupStatusItem() {
    statusItem.title = nil
    var icon = NSImage(named: "Moon_Full.png")
    icon.size = NSSize(width: 16, height: 16)
    icon.setTemplate(true)
    statusItem.button.image = icon
    statusItem.button.action = "StatusItemClicked"
}

func StatusItemClicked()  {

    if (statusItem.button.appearsDisabled)
    {
        statusItem.button.appearsDisabled = false
        println("Hide NSPopover here")
    }
    else
    {
        statusItem.button.appearsDisabled = true
        println("Show NSPopover here")
    }
}
}

This sets up the NSStatusItem, it has the right colours in light and dark mode and is logging the correct messages and toggling between active and inactive states.

The seceret sauce that I am missing is how to programatically add a segue to the statusItem.button so that it perfoms a load of an NSViewController that I have built in an NSPopover from the NSStatusItem when clicked.

Edit:

I have tried a number of scenarios with a vanilla NSButton on a ViewController

A) Hooking up a segue in interface builder ... works

B) Hooking up a segue and triggering it in code .. works, but you have to still make the connection in interface builder so that does not solve the problem at hand. ( This is API is new for 10.10 )

performSegueWithIdentifier("ShowPop", sender: sender)

C) Trying to pop a view controller in the same storyboard, is where the error is occurring.

    var newView = NSView(frame: sender.frame)
    var popupViewController = ViewController(nibName: "PopupViewController", bundle: NSBundle(identifier: "PopupViewController"))

    presentViewController(popupViewController,asPopoverRelativeToRect: sender.frame, ofView: newView,preferredEdge: NSRectEdge.max,behavior: NSPopoverBehavior.Transient)

2014-07-17 08:57:55.238 popover[5116:2277209] -[NSNib initWithNibNamed:bundle:] could not load the nibName: PopupVIewController in bundle (null).

( I have tried naming the NIB in IB and calling by name as well as using null.

D) The same code works if I create a separate XIB, but my preference is to use the new storyboards if possible, as I want to use the new tab view as a container ...

I have created a sample project (in Objective-C to ensure that this was not a swift problem)

Sample ObjectiveC project

Thanks in for your help in advance.

Upvotes: 3

Views: 4120

Answers (2)

Bruce McLeod
Bruce McLeod

Reputation: 1382

The answer I was given that works is ...

    popover = NSPopover()
    popover.contentViewController = NSStoryboard(name: "PopoverStoryboard", bundle: nil).instantiateControllerWithIdentifier("PopoverStoryboardVC") as NSViewController
    popover.behavior = NSPopoverBehavior.Transient

Upvotes: 5

radex
radex

Reputation: 6566

Just don't. Invoke the popover directly using NSPopover.showRelativeToRect(...). I believe if you set the popover's behavior to .Transient, it should just close itself when you click elsewhere, but you'll need to set its delegate property to catch the popoverDidClose event and unhighlight the status item.

Edit:

As far as I know, there is no way to programmatically set a segue on a button. When you set a segue relationship in a Storyboard, I believe in compiled code, you just get a target/action set for you which perform the NSStoryboardSegue. So you can't do that. In view controllers, you can use presentViewController(asPopover...) to quickly display another view controller in a popover. But when dealing with NSStatusItem and NSStatusBarButton, you don't get a view controller, so you have to do it directly.

Upvotes: 2

Related Questions