Can underline, but not bold text in NSTextView - swift

I have an NSDocuments & storyboard app created with the wizard in Xcode 8. In the ViewController Scene I have added a NSTextView. Certain menu items are disabled, such as Bold and Italic.
Looking at the First Responder the actions for bold and italic are not there. Am I supposed to write these methods myself? Is this due to the responder chain not being correctly set up? Why does underline show up but not bold?
Edit: Adding an image to show how I can edit text with the Inspector Bar, but the Format menu does not show the commands I would expect.

There is a historical (?) reason of this problem.
When the main menu was created in a xib file, xib file automatically contained a NSFontManager instance and such menu items like Bold were connected to it.
However in a modern storyboard, there is no preset NSFontManager instance.
Well then, you can connect them to a FontManager manually following the following steps.
Create a normal Object instance (blue cube) in the Application scene.
Change class of the Object instance to NSFontManager.
Connect the menu items to addFontTrait(_:) action of the fontManager. Likewise, connect "Bigger" and "Smaller" items to modifyFont(_:).
You also need to set menuItems' tag, however they are actually already set. Set the correspondent tag also manually only if menuItem's tag is 0.

If you ctrl drag from menu item to first responder, in menu view, you get the same options, just ctrl click. Then you implement whatever function you just connected. If you connect File > New to newDocument and implement in your ViewController
func newDocument(_ sender: Any?){
print("func newDocument(_ sender: Any? \(String(describing: sender)))")
}
It will get called. First responder lists all the same methods as the added Object with NSFontManager as class. I don't use #IBAction in front of method because I don't connect it.

Related

Is NSMenu willClose notitfication possible?

Is it possible for an NSMenu object to notify BEFORE it'll close, not after? Its delegate has method didClose(_:) but I want to update its items before it actually closes, since the disappearing animation is too long and the eye can see the change.
I've tried to monitor NSEvents, but it's useless because NSMenu hasn't public property containing its NSWindow object.
It's theoretically possible to achieve by creating a custom NSViews for each menu items. But I don't like this because then I'll have to draw all the drawing of the items, including selection and click animation.
UPDATE:
I've tried to subclass the NSPopUpButton to track menu updates:
class CustomPopUpButton: NSPopUpButton {
var isMenuShown: Bool = false
var onClosingMenu: ((NSMenu)->())?
override var needsDisplay: Bool {
willSet {
if let menu = self.menu, isMenuShown, newValue {
onClosingMenu?(menu)
isMenuShown = false
}
}
}
override func willOpenMenu(_ menu: NSMenu, with event: NSEvent) {
isMenuShown = true
super.willOpenMenu(menu, with: event)
}
}
I'm not proud of that piece of code but it works in general. Yet the 'onClosingMenu' method is being called just after the menu closing animation is finished. Not before.
Video of what I want to achieve: https://drive.google.com/file/d/1GAceKp-fTlurxSybdB3h0epVZrtQjthm/view?usp=sharing
Finally, I've found the solution. No need to fight the system and update something before the button menu closes. I've found the another way and it's pretty simple.
I've subclassed the NSPopUpButton and created another NSMenu in the subclass, called 'attributedMenu'. Overrided all properties of the NSPopUpButton that deal with menu items (insertions and removals) and redirected that actions to the 'attributedMenu' property.
The initial menu property of NSPopUpButton I'm using only for selected items, removing non-selected items right away.
I intercept the click on the button to show 'attributedMenu', not the default menu of the class.
That solution even made possible to display 'multiple values' title if I select more than one element. Like in Apple Pages' font picker when you select text written with multiple fonts. All it takes is to add an NSMenuItem with title 'Multiple Values' and call super to select it.
That's it, now it works as perfect as in Apple Pages font picker button. As long, as I'm not touching the original 'menu' property of NSPopUpButton class.
UPDATE
Uploaded the subclass to GitHub: https://github.com/CineDev/AttributedPopUpButton

Implementation of NSURL/File QuickLook Preview & NSURL/File dragging

I have a file (let's say a PDF) I have stored to disk on my macos Cocoa application. I have the NSURL that contains the path to this file.
I am currently showing that this file exists to the user using an NSView, which contains a label displaying the filename, and an NSImageView, displaying the file's icon (using NSWorkspace.shared.icon(forFile:url.path)).
My question is, how can I allow the user to 'select' or 'highlight' this NSView and when the space bar key is tapped have the QuickLook preview pop up for that particular file.
In addition, how would I have the NSView be draggable, with the end result of being able to drag the NSView to a Finder window and have the file copied to the dragged destination.
For both the QuickLook and dragging functionalities, I have gone through the Apple documentation but haven't found anything that accurately describes what I'm after.
For "selecting" a view, you should have the view accept first responder, and draw a focus ring (or whatever highlight is appropriate for you) when the view is first responder. Override acceptsFirstResponder (return true), becomeFirstResponder and resignFirstResponder (keep a flag for whether the view is first responder, and trigger drawing with setNeedsDisplay or whatever is appropriate), and the drawing mechanism (drawRect or whatever is approproiate if you're using CALayers).
Override keyDown for handling the spacebar.
Override mouseDragged and initiate a drag session, and simply create an NSDraggingItem with the pasteboardWriter being the NSURL itself.
For displaying QuickLook: QLPreviewPanel https://developer.apple.com/documentation/quartz/qlpreviewpanel

Get specific Item of NSToolbar

I want to have a NSToolbar in my macOS-App. I have created a Toolbar in the Window of my storyboard and connected this with a swift class called MainToolbar.
The source text of this class is the following (at this moment):
import Cocoa
class MainToolbar: NSToolbar, NSToolbarDelegate {
override init(identifier: String) {
super.init(identifier: identifier)
}
}
Now, I want to change the title of the Colors-Element and add a share button as two examples.
The Colors-Element has the identifier "NSToolbarShowColorsItem" in the storyboard.
I know, that there is the possibility of getting the items with "self.items", but there is now way of adding elements because it is immutable. And I also cannot find the way of getting elements with the identifier.
In order to do this you have to go to the storyboard and click on the toolbar.
The toolbar will open up and show two sections. The top section is the available buttons and the bottom section is the default buttons for the application.
I don't think it is wise to actually change the standard buttons, i.e. change the meaning of Colors. It is better to add a new NSToolbarItem to the top section. After you added it, you can double click on the title to give it a title and you can set the image by providing an image name in the Attribute Inspector.
Next you drag the new button from the top section to the bottom section.
Actions should be set from the top section and not from the bottom section.

Hide keyboard plus return key?

I have a view with a textfield at the top, a textview under it and two buttons below the textview.
The keyboard is configured with a "Done" button. Once the user has typed in their info, they click the save button, which is below the textview. First they click Done to hide the keyboard (and reveal the save button) then click the save button.
I need to allow carriage returns in the textview but "Return" is already taken up by Done.
How is it usually handled when you need a Return key and ability to also hide the keyboard?
Drag a button into your view, delete the text, and resize it to take up the entire view. In the document outline, select the new button and drag it to the top of the list of elements. This puts it in the background so it is not hiding the elements of your view.
Add this code to your ViewController:
#IBAction func hideKeyboard(sender: AnyObject) {
self.textField.resignFirstResponder()
}
Link the button to this action and you're all set.
If you're using a UINavigationBar or have other buttons or fields, activating any of those UIControls could be detected and used to dismiss the keyboard via resignFirstResponder(). In fact Save/Cancel/Done are UIBarButtonItems and are a standard mechanism for completing things and changing state, and create a framework for accomplishing what you want. If you don't take that approach then you have to get creative with how you do it, and also make it clear to the user what needs to be done.
In Interface Builder you can change the type of your main view from UIView to UIControl and then use addTarget() to detect touch events as a 'touch outside' area and use those actions to resign first responder as well. But you might want to consider a UINavigationBar or some other button bar or tab interface to make state transitions.
Also review iOS Human Interface Guidelines document. It's a great document for understanding how iOS is designed to handle common situations like what you are dealing with, and it can get you out of design ruts. It's well written and worth re-visiting periodically.

How to create a toolbar in a TableView with a Label?

I would like to add a toolbar with a label entitled "Save your search?" on the left and a button "Save" on the right that triggers a specific action when tapped. How could I do that programmatically, especially I want this Toolbar to show up only when a particular View is loaded on a screen but not on every view.
Also, I want the toolbar to have a static image as background. "Save" button will also have a static image for background
Just to check; why do you need to add this toolbar of sorts onto a TableView? Depending on how you've set things up; and specially seeing that you need to conditionally hide/show this toolbar, might be easier to add it outside the tableView (just above it I guess).
Seeing as you need to hide/show this toolbar at will; guess you can simply use a UIView for it and add the UIButtons on top as subviews; --> declare it as a property in the .h file so that it can be freely accessed in the .m file whenever you need to hide / show it.
Did you need help on some specific issue related to this perhaps; or would this serve as a goo enough starting point?