NSAttributedStringKey.font not working - cocoa

I want to add temporary attributes to the text in an NSTextView. It is working for NSAttributedStringKey.foregroundColor but not for NSAttributedStringKey.font. It's also unfortunate that I can't get to the definitive headers to see where NSAttributedStringKey is defined. (I tried cmd-clicking but it's a dead end without the actual definitions).
The code below should work but the font doesn't change
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
#IBOutlet weak var textView: NSTextView!
func applicationDidFinishLaunching(_ aNotification: Notification) {
textView.layoutManager?.delegate = self
}
}
extension AppDelegate: NSLayoutManagerDelegate {
func layoutManager(_ layoutManager: NSLayoutManager,
shouldUseTemporaryAttributes attrs: [NSAttributedStringKey : Any] = [:],
forDrawingToScreen toScreen: Bool,
atCharacterIndex charIndex: Int,
effectiveRange effectiveCharRange: NSRangePointer?) -> [NSAttributedStringKey : Any]?
{
var attributes = attrs
if let font = NSFont(name: "Comic Sans MS", size: 14) {
attributes[NSAttributedStringKey.font] = font
}
return attributes
}
}

Related

webView didFinish Navigation never gets called

I am trying to get the splash view ( back_button ) to remove itself once the webpage fully loads, I had done quite a bit of researching and they always point to the same code as an answer. However, mine will not get called. Can somebody advise what I am doing wrong?
import UIKit
import WebKit
class ViewController: UIViewController {
#IBOutlet weak var LoadingView: UIImageView!
var webView: WKWebView?
var bgImage: UIImageView?
var imageViewObject :UIImageView?
override func viewDidLoad() {
super.viewDidLoad()
//var imageViewObject :UIImageView
let screenSize: CGRect = UIScreen.main.bounds
imageViewObject = UIImageView(frame:CGRect(x:0,y: 0, width: screenSize.width, height: screenSize.height))
imageViewObject?.image = UIImage(named:"back_image")
webView?.navigationDelegate = self as? WKNavigationDelegate
self.view.addSubview(imageViewObject!)
let myURL = URL(string: "https://www.google.com")
let myRequest = URLRequest(url: myURL!)
_ = webView?.load(myRequest)
}
override func loadView() {
super.loadView()
//self.view.sendSubview(toBack: imageViewObject)
//self.view = self.LoadingView
self.webView = WKWebView()
self.view = self.webView
}
#IBAction func BackButton(_ sender: Any) {
if(webView?.canGoBack)!
{
webView?.goBack();
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("TEST")
imageViewObject?.removeFromSuperview()
}
func webViewDidFinishLoad(webView: WKWebView) {
imageViewObject?.removeFromSuperview()
self.view = self.webView
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
you have to conform to it's protocol delegate by putting this line of code in viewDidLoad
webView?.uiDelegate = self
after doing that , now if you want to use delegation method's you have to put your viewController as a subclass of UIWebViewDelegate
class ViewController: UIViewController ,UIWebViewDelegate{
I fixed this by making
webView?.navigationDelegate = self
and adding this to the Class
class ViewController: UIViewController, WKNavigationDelegate

Passing a value from inputField to NSTextField

I'd like to pass string value from one NSTextField to another NSTextField pressing a button. I used for this for-in loop. I need to pass a value from inputField to visibleText1, then to visibleText2 and then to visibleText3. But it doesn't work.
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
#IBOutlet weak var inputField: NSTextField!
#IBOutlet weak var visibleText1: NSTextField!
#IBOutlet weak var visibleText2: NSTextField!
#IBOutlet weak var visibleText3: NSTextField!
func applicationDidFinishLaunching(aNotification: NSNotification) { }
func applicationWillTerminate(aNotification: NSNotification) { }
#IBAction func applyButton(sender: AnyObject) {
for u in (visibleText1.stringValue...visibleText3.stringValue) {
visibleText.stringValue[u] = inputField.stringValue
inputField.stringValue = ""
}
}
}
Xcode gives me an error:
// Type 'ClosedInterval<String>' does not conform to protocol 'SequenceType'
How how to do it right?
No you can't do that because you can't create a range of string values of different text fields.
You could make an array of the three fields and enumerate that:
#IBAction func applyButton(sender: AnyObject) {
for field in [visibleText1, visibleText2, visibleText3] {
field.stringValue = inputField.stringValue
}
inputField.stringValue = ""
}
or with the forEach function
#IBAction func applyButton(sender: AnyObject) {
[visibleText1, visibleText2, visibleText3].forEach {
$0.stringValue = inputField.stringValue
}
inputField.stringValue = ""
}
Resetting the inputField in the repeat loop would always apply an empty string after the first iteration.
There are several things wrong with this, but I will start with what will work:
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
#IBOutlet weak var inputField: NSTextField!
#IBOutlet weak var visibleText1: NSTextField!
#IBOutlet weak var visibleText2: NSTextField!
#IBOutlet weak var visibleText3: NSTextField!
func applicationDidFinishLaunching(aNotification: NSNotification) { }
func applicationWillTerminate(aNotification: NSNotification) { }
#IBAction func applyButton(sender: AnyObject) {
for u in [visibleText1, visibleText2, visibleText3] {
u.stringValue = inputField.stringValue
}
}
}
So what's wrong with the original?
1) Your (visibleText1.stringValue...visibleText3.stringValue) is of type String ... String, which is not what you intended. You need to have an array of NSTextFields.
2) visibleText.stringValue[u] is not even a thing. There is no variable visibleString, and even if it was an NSTextField - which I think is what you want it to be, it's .stringValue is a String, and not an array.
3) What are you doing setting inputField.stringValue = "" inside the for loop? If your construct worked, only the first field would be set.
4) Not an error, but why are you doing all of this inside NSApplicationDelegate, rather than a viewController?

Populate NSComboBox from Data Source

This code compiles OK, but the ComboBox (cbxColors) is empty - not populated from the Data Source (array: COLORS_OF). Uses Data Source is checked in IB.
func numberOfItemsInComboBox() returns the correct result: 5.
func comboBox() is not doing its job.
What am I missing?
EDITED: Now working.
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, NSComboBoxDelegate, NSComboBoxDataSource {
#IBOutlet weak var window: NSWindow!
func applicationDidFinishLaunching(aNotification: NSNotification) {
cbxColors.dataSource = self
numberOfItemsInComboBoxCell(cbxColors)
comboBoxCell(cbxColors, objectValueForItemAtIndex: 0)
}
func applicationWillTerminate(aNotification: NSNotification) {
}
#IBOutlet weak var cbxColors: NSComboBox!
#IBOutlet weak var txtResult: NSTextField!
#IBAction func actColors(sender: NSComboBox) {
// display User selected item in 'txtResult'
}
func numberOfItemsInComboBoxCell(aComboBox: NSComboBox) -> Int {
return(COLORS_OF.count)
}
func comboBoxCell(aComboBox: NSComboBox, objectValueForItemAtIndex index: Int) -> AnyObject {
return(COLORS_OF[index])
}
let COLORS_OF = [ "Blue", "Green", "Purple", "Red", "Yellow" ]
}
You probably forgot to check Uses Data Source or you have to delete datasource connection and reconnect it again (weird bug of Xcode).
Other then that if your outlets are correctly hooked your code works.

How to set NSButton's keyEquivalent to NSDownArrowFunctionKey in Swift

How do I set an NSButton's keyEquivalent (which is a String type) to the down arrow key in Swift? NSDownArrowFunctionKey is an Int.
This page in Apple's documentation addresses this exact issue. The example they provide is written in Objective-C, the Swift equivalent is as follows:
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
#IBOutlet weak var button: NSButton!
func applicationDidFinishLaunching(aNotification: NSNotification) {
var array = [unichar(NSDownArrowFunctionKey)]
button.keyEquivalent = NSString(characters: array, length: 1)
}
}

CustomView Does not show up in StatusBar

I am trying to make a SystemStatusBar popover for Mac. (Roughly, translating this Cocoa app to a Swift app). However, the view that I am using never shows up and the popup appears in the bottom left of the screen replicating the StatusBarItem.
This is what I expect (and that happens in the example from case of example from the link):
and this is what actually shows up (in my, Swift version of the application) instead of the NSPopover being shown in the StatusBar [Showing or Hiding the popup is controlled by the two buttons as shown in the previous figure. In this screenshot I have not added that window as it remains the same.]:
This is the AppDelegate:
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
var statusView : StatusView!
var popController: PopViewController!
#IBAction func showPop(sender: NSButton)
{
statusView.showPopup()
}
#IBAction func hidePop(sender: NSButton)
{
statusView.hidePopup()
}
func applicationDidFinishLaunching(aNotification: NSNotification)
{
var height = NSStatusBar.systemStatusBar().thickness
statusView = StatusView(frame: NSMakeRect(0, 0, CGFloat(height), CGFloat(height)))
}
}
The CustomView:
class StatusView : NSView, NSMenuDelegate
{
var imageView: NSImageView!
var statusItem: NSStatusItem!
var popover: NSPopover!
var popController: PopViewController!
required init? (coder: NSCoder)
{
super.init(coder: coder)
}
override init(frame frameRect: NSRect)
{
var height = NSStatusBar.systemStatusBar().thickness
imageView = NSImageView(frame: NSMakeRect(0, 0, CGFloat(height), CGFloat(height)))
statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(CGFloat(height))
super.init(frame: frameRect)
imageView.image = NSImage(named: "mf-image-black.png")
self.addSubview(imageView)
statusItem.view = self
popover = NSPopover()
popController = PopViewController(nibName: "PopViewController", bundle: nil)
popController.view = self
popover.contentViewController = popController
}
func showPopup()
{
if(!popover.shown)
{
popover.showRelativeToRect(self.frame, ofView: self, preferredEdge: NSMinYEdge)
}
}
func hidePopup()
{
if(popover.shown)
{
popover.close()
}
}
}
and the ViewController:
class PopViewController: NSViewController
{
#IBOutlet var statusView: StatusView!
override init?(nibName: String?, bundle: NSBundle?) {
super.init(nibName: nibName, bundle: bundle)
}
required init?(coder: NSCoder)
{
super.init(coder: coder)
}
}
I am not exactly sure what is that I am missing here. The StatusItem never seems to make use of the PopViewController nib.

Resources