How to get characters from emoji picker [ctrl-command-space] - objective-c

on OS X the 'Emoji & Symbols' picker can be started from the menu or [ctrl-command-space] how do I get the characters from this in my view? (just an NSView with text handling in core text).
i.e. I double click on the emoji in the picker and how do I receive it in my view - I'd guess there's a delegate I have to set somewhere - but can't seem to find the docs - I'm probably not calling it the right thing when I google
I've made a basic app
and added the lines below to the view controller
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.window?.makeFirstResponder(self.view)
self.view.becomeFirstResponder()
and made a view MyNSView with and set the view in the storyboard to MyNSView
override public func keyDown(with event: NSEvent) {
interpretKeyEvents([event])
}
When I use the emoji picker, the keydown doesn't fire (I put a breakpoint on it). Maybe the emoji comes from another method?
Seems I have to implement NSTextInputClient - see https://developer.apple.com/library/content/samplecode/TextInputView/Introduction/Intro.html

Seems I have to implement NSTextInputClient - see https://developer.apple.com/library/content/samplecode/TextInputView/Introduction/Intro.html

Related

How to change value of the NSTextField instantly as we type?

There are two outlets connected to my ViewController.swift file.
#IBOutlet var myOutlet: NSTextField!
#IBOutlet var yourOutlet: NSTextField!
There is an action connected too.
#IBAction func myAction(sender: NSTextField) {
self.yourOutlet.doubleValue = myOutlet.doubleValue - 10
When i run the app, it works.
I enter 15 to text field that myOutlet connected, then hit the enter. And field that yourOutlet connected, takes the value of 5.
If there is no enter button needed, it would be better. So how to make the value change instantly, as we type?
Thanks for the answers.
I did not get a chance to do swift and OSX development, but I can lead you to the solution.
Take a look at textDidChange(_:)
Posts a notification that the text has changed and forwards this
message to the receiver’s cell if it responds.
Declaration
func textDidChange(_ aNotification: NSNotification)
Parameters aNotification The NSControlTextDidChangeNotification
notification that is posted to the default notification center.
Discussion This method causes the receiver’s delegate to receive a
controlTextDidChange: message. See the NSControl class specification
for more information on the text delegate method.
So to achieve your goal, you would implement this delegate, it will get called each time you edit the text inside of the NSTextField.Then inside of that delegate block you will provide the logic needed.

NSStepper in NSTableCellView has no effect

I’m using a regular (not subclassed) NSTableCellView in a view-based table view. It has the initial image and text field views. I added an NSStepper to the view.
The text field is bound to tableCellView.objectValue.quantity.
The stepper’s value is bound to tableCellView.objectValue.quantity too.
The problem is that when running the app, when I click the stepper it doesn’t seem to get the mouse event, neither arrow gets highlighted, the value is not incremented or decremented.
If I set the double action of the table view it gets triggered if I double-click the stepper as if it was transparent.
What am I missing?
Thanks!
You should look at the documentation but easiest is that you need to subclass NSTableView and override this method to validate the proposed first responder. As the document states NSTableViews disallow some controls to be used unless the row is first selected. Even then it still may discard some.
- (BOOL)validateProposedFirstResponder:(NSResponder *)responder forEvent:(NSEvent *)event {
return YES;
}
Further to the correct answer from Robert Payne, with Swift you could add an extension to NSTableView and not subclass it.
extension NSTableView {
override public func validateProposedFirstResponder(responder: NSResponder, forEvent event: NSEvent?) -> Bool {
return true
}
}
And I'd like to emphasis that it's the NSTableView not the NSTableViewCell.

How do I deselect all table rows in NSOutlineView when clicking in the empty space of the view?

For example when I click on the red dot below:
I want the following deselection to occur:
I set up the view-based NSOutlineView using bindings for both the data source and the selection indexes. So far i've tried to override the TableCellView becomeFirstResponder and also override NSOutlineView's becomeFirstResponder however it seems NSOutlineView never actually gives up first responder status?
Some advice would be very much appreciated!
I found this post on the topic. The solution appears to be in creating a subclass of NSOutlineView and overriding mouseDown: so that you can determine whether the click was on a row or not. When the click is on a row you just dispatch to super. If it's not you send deselectAll: to your NSOutlineView.
I haven't tried it myself but there are various posts around which come up with comparable code.
Use setAction: method of NSOutlineView.
[mOutlineView setAction:#selector(doClick:)];
[mOutlineView setTarget:self];
-(IBAction) doClick:(id)sender;
{
if ([mOutlineView clickedRow] == -1) {
[mOutlineView deselectAll:nil];
}
}
Swift 5. in NSOutlineViewDelegate
func outlineViewSelectionDidChange(_ notification: Notification) {
//1
guard let outlineView = notification.object as? NSOutlineView else {
return
}
outlineView.deselectAll(nil)
}

NSCollectionViewItem double-click action?

How do I set an action for when a user double clicks an NSCollectionViewItem. NSTableView, for example, has the setDoubleAction method. Is there something similar for NSCollectionView?
Thanks
I know this question is ancient, but it comes up as the third result on Google right now, and I've found a different and very straightforward method that I haven't seen documented elsewhere. (I don't just need to manipulate the represented item, but have more complex work to do in my app.)
NSCollectionView inherits from NSView, so you can simply create a custom subclass and override mouseDown. This is not completely without pitfalls - you need to check the click count, and convert the point from the main window to your collection view's coordinate, before using NSCollectionView's indexPathForItem method:
override func mouseDown(with theEvent: NSEvent) {
if theEvent.clickCount == 2 {
let locationInWindow = theEvent.locationInWindow
let locationInView = convert(locationInWindow, from: NSApplication.shared.mainWindow?.contentView)
if let doubleClickedItem = indexPathForItem(at: locationInView){
// handle double click - I've created a DoubleClickDelegate
// (my collectionView's delegate, but you could use notifications as well)
...
This feels as if I've finally found the method Apple intended to be used - otherwise, there's no reason for indexPathForItem(at:) to exist.
You'd probably want to handle this in your NSCollectionViewItem, rather than the NSCollectionView itself (to work off your NSTableView analogy).

Can you set a navbar's edit button in Interface Builder?

It's easy enough to set up a table view to allow editing. Just add one line to your UITableViewController:
self.navigationItem.rightBarButtonItem = self.editButtonItem;
This line adds an edit button on the nav bar that will change the table to editing mode and change its button text to "Done" while editing.
Is it possible to set this up in Interface Builder? I see that you can add a UIBarButtonItem and can set its "Identifier" to "Edit", but I don't see the expected behavior.
BTW, what does the "Identifier" in the Attributes panel do?
Yes, you can add UIBarButtonItems in Interface Builder, and they should work.
The identifier lets you use a preset button (like Edit or Reload), or you can choose Custom and make your own button.
EDIT: I may be able to help further if you could explain how UIBarButtonItems added through IB don't work.
UPDATE: UIViewController.editButtonItem is a special method that returns a UIBarButtonItem that invokes the view's setEditing method. You can achieve the same effect by creating a method that does the same thing and connecting the selector to your UIBarButtonItem in IB.
In your header file:
- IBAction edit:(id)sender;
and in your implementation file:
- (IBAction) edit:(id)sender {
[self setEditing:YES animated:YES];
}
then connect the selector to the UIBarButtonItem.
However, you might not be able to create this connection in the default Navigation-Based Application template since the Table View is in a separate file.
Have a look here: http://blog.tmro.net/2009/05/uitabbarbuttonitem-did-not-change-its.html
If you want your button to be able to change its label dynamically make sure you use a custom identifier otherwise its title will be immutable.
We still can't seem to do this specifically in Interface Builder as of Xcode 9.4.1. It's very easy to do in code, though.
You don't need to set up the button in IB at all. Simply add this code in your viewDidLoad method:
navigationItem.leftBarButtonItem = editButtonItem
That automatically sets up the Edit button, which turns to Done so the user can end editing.
To do anything custom associated with the editing process, override the view controller's setEditing(_ editing: Bool, animated: Bool) method.
For example, if you have a table view whose editing needs to be turned on and off, you can do this:
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
tableView.setEditing(editing, animated: animated)
}
Make sure to call super.setEditing here.
Note: if you're using a UITableViewController, setEditing is already set up in the super class to handle the table view. You don't need to override it, unless you have other custom code you want to include when editing is enabled/disabled.