Show popOver when right click on TableViewCell - macos

I have a NSTableView and want to show a popOver if the User right click on a row. So i have this function:
override func rightMouseDown(theEvent: NSEvent) {
super.rightMouseDown(theEvent)
var point: NSPoint = talbeView.convertPoint(theEvent.locationInWindow, fromView: nil)
var row = tableView.rowAtPoint(point)
var rec = tableView.rectOfRow(row)
let storyboard = NSStoryboard(name: "Main", bundle: nil)
let popOverViewController = storyboard!.instantiateControllerWithIdentifier("RightMousPopOver") as! NSViewController
var cell: DocumentCellView = tableView.viewAtColumn(0, row: row, makeIfNecessary: true) as! DocumentCellView
self.presentViewController(popOverViewController, asPopoverRelativeToRect: rec, ofView: cell, preferredEdge: 2, behavior: NSPopoverBehavior.Transient)
}
But the popOver appears only if I right click on the first row. I have debug the row and its right. Also if i change the row manuelle, the popOver show on the right row, but again only if I click on the first row.
I'm little bit confused. What is wrong withe my code?

Ok i think i found the answer. tableView.rectOfRow(row) is false. cell.frame is the right way to get the NSRec

Related

Set NSTableView clickedRow

How to programmatically simulate Control-Click on a table view row to display the table context menu and the clickedRow border? Just like the Notes app does on clicking the ellipsis button.
I was able to trigger the menu by:
let point = tableView.convert(NSApp.currentEvent!.locationInWindow, from: nil)
let row = tableView.row(at: point)
tableView.menu?.popUp(positioning: tableView.menu!.item(at: 0), at: point, in: tableView)
But can't figure out a simple way of drawing the clicked row border and setting the table view's clickedRow.
Well, I was pretty close. Seems like menu(for: NSEvent) -> NSMenu? does the trick:
#IBAction func showContextMenu(_ sender: NSButton!) {
guard let event = NSApp.currentEvent,
let menu = tableView.menu(for: event) else {
return
}
NSMenu.popUpContextMenu(menu, with: event, for: tableView)
}

How to create table with highlighted-on-mouseover cells on macOS cocoa?

I'm trying to create a tray popover app with table very similar to the one Dropbox has in it's popover view.
There is a table of files and when you hover mouse over a table cell, cell will highlight and show additional controls.
I'm not sure if NSTableView is suitable for this at all?
Does anyone have any advice?
This would be an ideal use of NSTableView. Using a view-based NSTableView, you'll be easily able to create the look of those cells (views). The highlight on mouse-over should be accomplishable if you add an NSTrackingArea to the table view (scroll view might be better) with -[NSView addTrackingArea:], which gives you callbacks for -mouseMoved: events. From that method you can use the locationInWindow property on the NSEvent, and then use NSTableView's -rowAtPoint: call to query which row you should change to display the hover event.
As a possible amendment here, I had to do the following to make this work:
highlightedRow: MyCustomRow?
func viewWillAppear(){
configureTableHighlight()
}
func configureTableHighlight() {
let trackingArea = NSTrackingArea(rect: scrollView.frame, options: [.mouseMoved, .activeInKeyWindow, .inVisibleRect], owner: self, userInfo: nil)
scrollView.addTrackingArea(trackingArea)
}
override func mouseMoved(with event: NSEvent) {
let pointInTableView = tableView.convert(event.locationInWindow, to: nil)
let row = tableView.row(at: pointInTableView)
if row == -1 {
highlightedRow?.highlight = false
highlightedRow = nil
return
}
guard let view = tableView.view(atColumn: 0, row: row, makeIfNecessary: false) as? MyCustomRow else {
return
}
if(highlightedRow == view){
return
}
view.highlight = true;
highlightedRow?.highlight = false
highlightedRow = view;
}
This might depend on where you add the trackingView however.
Additional reference:
mouseover detection in NSTableView's NSCell?

NSTextField in an NSTableView truncates Dates

I have an NSTableView (View type, not Cell type) which is resulting in text with "..." at the end. When I resize the columns, the "..." doesn't go away, indicating that the size is being set somewhere else... but I'm not sure where.
Here is what the table looks like:
When I make it bigger, the text is still truncated:
If I take out the ".ByClipping", I get this:
Here is the code that makes the cell:
func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView? {
let identifier = tableColumn!.identifier
let networkName = displayedNetworks[row]
let networkVals = model.networks[networkName]!
if let val: AnyObject = networkVals[identifier] {
var obj = tableView.makeViewWithIdentifier(identifier, owner:self)
if (obj==nil) {
// No existing cell to reuse, so make a new one
obj = NSTableCellView(frame:NSMakeRect(0,0,400,400))
obj!.identifier = identifier
}
let cellView = obj as! NSTableCellView
if let d = val as? NSDate {
let formatter = NSDateFormatter()
formatter.dateStyle = NSDateFormatterStyle.ShortStyle
formatter.timeStyle = .ShortStyle
cellView.textField!.stringValue = formatter.stringFromDate(d)+"****"
cellView.textField!.lineBreakMode = .ByClipping
}
else {
cellView.textField!.stringValue = "\(val)"
}
return cellView
}
return nil
}
Something is wrong, but I can't figure it out. I thought that resizing the column resized the contained cells. Mine aren't. This is only happening with the cells that are displaying dates. What should I do?
Example you can select you Table View Cell in IB and then click that button "Resolve Auto Layuout Issues" which is just under pop over bottom left corner and the "Add Missing Constraints".

Calling popover from a menu item crash

I have a toolbar button
#IBOutlet weak var testButton: NSToolbarItem!
The button call a popover and works fine.
But if i try and call the popover from a top menu item i get a crash.
I have amended the location of the popover to appear below the testButton just as it normally would. (commented below)
#IBAction func menuPreviewAndTestAction(sender: AnyObject) {
var returnedHtmlString = checkEverythingAndCreateTheEncodedHtml(testButton)
setEncodedHtmlToPreview(returnedHtmlString)
var thebounds = self.testButton.view?.bounds // so i am givving bounds of button that narmally calls poover
testingPopover.showRelativeToRect(thebounds!, ofView: sender as NSView, preferredEdge: NSMaxYEdge) // crashes
}
Oh dear... I missed changing the ofView, all sorted with :
var thebounds = self.testButton.view?.bounds
var theview = self.testButton.view
testingPopover.showRelativeToRect(thebounds!, ofView: theview! as NSView, preferredEdge: NSMaxYEdge)

How to present a modal atop the current view in Swift

(Xcode6, iOS8, Swift, iPad)
I am trying to create a classic Web-like modal view, where the outside of the dialog box is "grayed-out." To accomplish this, I've set the alpha value of the backgroundColor of the view for the modal to 0.5, like so:
self.view.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.5)
The only problem is that when the modal becomes full-screen, the presenting view is removed. (Ref Transparent Modal View on Navigation Controller).
(A bit irritated at the concept here. Why remove the underlying view? A modal is, by definition, to appear atop other content. Once the underlying view is removed, it's not really a modal anymore. it's somewhere between a modal and a push transition. Wa wa wa... Anyway..)
To prevent this from happening, I've set the modalPresentationStyle to CurrentContext in the viewDidLoad method of the parent controller, and in Storyboard... but no luck.
self.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
self.navigationController.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
How do I prevent the presenting view from being removed when the modal becomes full screen?
tyvm.. more info below.
Also in Storyboard, like so (Presentation: Current Context)
Thx for your help... documentation below:
First, remove all explicit setting of modal presentation style in code and do the following:
In the storyboard set the ModalViewController's modalPresentation style to Over Current context
Check the checkboxes in the Root/Presenting ViewController - Provide Context and Define Context.
They seem to be working even unchecked.
You can try this code for Swift:
let popup : PopupVC = self.storyboard?.instantiateViewControllerWithIdentifier("PopupVC") as! PopupVC
let navigationController = UINavigationController(rootViewController: popup)
navigationController.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
self.presentViewController(navigationController, animated: true, completion: nil)
For swift 4 latest syntax using extension:
extension UIViewController {
func presentOnRoot(`with` viewController : UIViewController){
let navigationController = UINavigationController(rootViewController: viewController)
navigationController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
self.present(navigationController, animated: false, completion: nil)
}
}
How to use:
let popup : PopupVC = self.storyboard?.instantiateViewControllerWithIdentifier("PopupVC") as! PopupVC
self.presentOnRoot(with: popup)
The only problem I can see in your code is that you are using CurrentContext instead of OverCurrentContext.
So, replace this:
self.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
self.navigationController.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
for this:
self.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
self.navigationController.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
This worked for me in Swift 5.0. Set the Storyboard Id in the identity inspector as "destinationVC".
#IBAction func buttonTapped(_ sender: Any) {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let destVC = storyboard.instantiateViewController(withIdentifier: "destinationVC") as! MyViewController
destVC.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
destVC.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
self.present(destVC, animated: true, completion: nil)
}
The problem with setting the modalPresentationStyle from code was that you should have set it in the init() method of the presented view controller, not the parent view controller.
From UIKit docs: "Defines the transition style that will be used for this view controller when it is presented modally. Set
this property on the view controller to be presented, not the presenter. Defaults to
UIModalTransitionStyleCoverVertical."
The viewDidLoad method will only be called after you already presented the view controller.
The second problem was that you should use UIModalPresentationStyle.overCurrentContext.
The only way I able to get this to work was by doing this on the presenting view controller:
func didTapButton() {
self.definesPresentationContext = true
self.modalTransitionStyle = .crossDissolve
let yourVC = self.storyboard?.instantiateViewController(withIdentifier: "YourViewController") as! YourViewController
let navController = UINavigationController(rootViewController: yourVC)
navController.modalPresentationStyle = .overCurrentContext
navController.modalTransitionStyle = .crossDissolve
self.present(navController, animated: true, completion: nil)
}
I am updating a simple solution. First add an id to your segue which presents modal. Than in properties change it's presentation style to "Over Current Context". Than add this code in presenting view controller (The controller which is presenting modal).
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let Device = UIDevice.currentDevice()
let iosVersion = NSString(string: Device.systemVersion).doubleValue
let iOS8 = iosVersion >= 8
let iOS7 = iosVersion >= 7 && iosVersion < 8
if((segue.identifier == "chatTable")){
if (iOS8){
}
else {
self.navigationController?.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
}
}
}
Make sure you change segue.identifier to your own id ;)

Resources