Open infinite window of Preferences Pane in Cocoa app when using segue - macos

I want to open a preference pane in my Cocoa app when an user taps the Preferences... menu or typing ⌘+,. So I connected from the preferences menu item to the window controller in storyboard as a show segue.
However, while this opens the preference pane when an user taps Preferences..., if the user taps the menu item again before closing the pane, another pane is going to be launched and displayed on the screen.
I want to have only one preference pane in my screen but how can I do that? I want to set it up only on storyboard and avoid coding that makes the nest of nest of boring menu items...

In order to prevent the windows from being launched multiple times, you select Single from the Window Controller's Attribute Inspector on Storyboard.
The default value is Multiple, causing the infinite windows to be launched.
Alternatively, if you want to use the code, here is something I will do in AppDelegate.swift.
extension AppDelegate: NSSeguePerforming {
func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
if identifier == OpenPreferencesIdentifier {
let windows = NSApp.windows
for window in windows {
if window.windowController?.className == MyPreferencesWindowController.className() {
return false
}
}
}
return true
}
}
Also do NOT forget to set the appropriate segue identifier on Storyboard.

Related

NSColorPanel not showing up after the first time

I have a statusBarItem that I want to use to show the NSColorPanel.
The following code is called when the button is tapped, which activates the ColorPanel.
#IBAction func showColour( button:NSButton ){
DispatchQueue.main.async {
NSApplication.shared.orderFrontColorPanel(self)
print( "panel frame:\(NSColorPanel.shared.frame), is visible:\(NSColorPanel.shared.isVisible )" )
}
}
If the user presses the close button to close the colour panel, tapping the button to show the panel works as expected and displays the panel again. However, if the user clicks in an empty space, the colorPanel disappears, and tapping the button to reopen the panel does not work any more. However, based on the logs, it appears that the panel has a valid rect and is visible.
Any Suggestions?ThanksReza
As it was pointed out by a user on Reddit, when tapping in an empty space the app will go to the background, and is no longer the foreground application, so a utility-style window like the color panel will not be displayed. Hence as the app is not active, subsequent taps to show the colour panel, will not bring the utility window to the front.
So the solution is to make sure the app is active prior to trying to open the colour panel by calling:
NSApplication.shared.activate(ignoringOtherApps: true )
in the showColour function

SwiftUI context menu trigger by left click on macOS

I have a gear button on my view, when user click it I want to show a menu of buttons. It seems the https://developer.apple.com/documentation/swiftui/view/contextmenu(menuitems:) is designed for this task but only right click can trigger the context menu.
How can I trigger the contextMenu by left-click on macOS? Thanks!
You can use a specific menu style for that type of UI. If you want to hide the indicator, just put in false.
Menu("Label") {
Button("Buttons") { }
}
.menuStyle(BorderlessButtonMenuStyle())
.menuIndicator(.hidden)
.fixedSize() // Otherwise will be the width of your menu options.

macOS: NSToolbar with translucency effect in Big Sur

I am working with a new Xcode project for Big Sur, with a "Split View with Sidebar" scene in the main storyboard. I want to make the window title and toolbar have the translucency effect that you see in the toolbars in Safari or Finder. In my storyboard, I specify "Full Size Content View" and "Hide Title Text", and in the storyboard it looks like what I want:
But when I build and run it, the window's toolbar is plain white:
Now if I disable the "Hide Title Bar" checkbox, it looks fine in the storyboard with the title and the toolbar items on the same line:
Now when I build and run it, the toolbar has the translucency effect I want, but the title is on a 2nd level above the toolbar items:
I'm not sure what else I can do to control this. Ideally, I would hide the title bar and keep the translucency, but it doesn't seem to be working. Is there anything else I can try to control this?
If not, I would prefer the title to be on the same level as the toolbar items, like it does in the storyboard. But even that isn't working as desired.
Any ideas on what I can try? I've tried changing the toolbar styles, but they all have similar results.
EDIT:
I've tried using Apple's own code for "Navigating Hierarchical Data Using Outline and Split Views" and after tweaking the storyboard with enabling both "Full Size Content View" and "Hide Title Bar" checkboxes, I'm seeing the same issue: i.e. the toolbar turns white. So it's likely an Apple framework bug? I'm not sure, so I have filed a bug to find out.
I created an app that build fine on High Sierra and Catalina, it may build on OX11. It removes the titlebar, but I don't use a toolbar. Try this, it may do similar to what you want - you may have to comment-out some settings, etc.
Create a file "MainWindow" that is a subclass of NSWindowController. Fill the file with:
class MainWindow: NSWindowController {
var controller: ViewController?
override func windowDidLoad() {
super.windowDidLoad()
controller = self.contentViewController as? ViewController
self.smartWindow()
self.activateWindowDrag()
}
}
// you may prefer the below as a separate file
extension NSWindowController {
func smartWindow() {
self.window?.styleMask.insert(NSWindow.StyleMask.unifiedTitleAndToolbar)
self.window?.styleMask.insert(NSWindow.StyleMask.fullSizeContentView)
self.window?.styleMask.insert(NSWindow.StyleMask.titled)
self.window?.toolbar?.isVisible = false
self.window?.titleVisibility = .hidden
self.window?.titlebarAppearsTransparent = true
}
func activateWindowDrag() {
self.window?.isMovableByWindowBackground = true
}
}

Enabling "Use keyboard navigation" messes with NSTableView

I have an NSTableView where I use the
tableView(tableView:shouldTypeSelectFor:withCurrentSearch:) -> Bool
delegate method to select certain lines with the SPACE key like this
func tableView(_ tableView: NSTableView,
shouldTypeSelectFor event: NSEvent,
withCurrentSearch searchString: String?) -> Bool {
if event.charactersIgnoringModifiers == " " {
// Perform action on currently selected row(s)
}
return false
}
That works fine, but when the setting in
Preferences > Keyboard > Shortcuts > "Use keyboard navigation to move focus between controls"
Is turned on, the table view loses focus entirely after hitting the SPACE key.
If I check my responder chain afterwards, I can se that the focus moved back to the window.
Another sideeffect of turning this setting on is that if I have a check box (NSButton) in the selected table view cell, its action will be automatically called when hitting SPACE.
The setting explicitly states it only moves focus on TAB and SHIFT+TAB, not change how controls work.
Why does this happen?
Can I disable this behavior at least partially for the table view of the app?
After almost losing my last hair here is what resolves it
Make sure all your cell subviews have refusesFirstResponder set to false
Now the table views first responder status is not lost.

how to make a macOS app have two main menu

I know some mac application has two main menu.
main menu means top left menu in macOS screen.
When a windowA show, the main menuA show.
As I click some window (name it windowB) in the application
and another menuB is replaced menuA.
And as I click windowA, the main menuA reappear.
Does someone know how to implement this behavior?
You have to associate a menu to each window. For this, you can copy the MainMenu of the Application and paste it into the appropriate Window Controller Scene. Then select the connections of the window in the scene and link the item "menu" to the new menu of the scene. Repeat this for all your window controllers/windows.
Then you need to add some code. Create a new Window class:
class Window : NSWindow {
override func becomeKey() {
NSLog("become2")
NSApplication.shared().mainMenu = self.menu
super.becomeKey()
}
}
and then set the class property of each window to this Window class.
You can then edit menus accordingly to your needs. Be aware that you need to reconnect each menu item to the appropriate first responder action...
I'm not sure it is the best solution, but it works well for me. In fact I don't really understand why I need to subclass NSWindow this way...

Resources