Support closing of a NSWindow presented as sheet via escape key - objective-c

How do I setup an NSWindows (on OS X) to be closed when the user presses the escape key?
The window is presented as a sheet via
presentingWindow.beginSheet(mySheetWindow, completionHandler:nil)
It has a close button (via IB) that has a key equivalent set to 'escape'. This close button is already working
Pressing escape leads to the system audio error output ('Funk' - Sound), but no logging and no closing of the window.

You have to add a regular button and position it at the top left corner of your window. Set your button width and alpha to 0.
Click at the key equivalent field and press ESC. It will show the escape key icon
Then create your IBAction for the hidden button as follow:
#IBAction func closeWindowAction(sender: AnyObject) {
window.close()
}
Make sure you have your window outlet connected to the proper window:
#IBOutlet weak var window: NSWindow!

Related

Java FX Dialog "appears" with no size

I'm using JFX 11 on Fedora 33 (GNU/Linux) with the Xorg GUI server (v 1.20.11), creating a dialog thus (kotlin):
fun YNdialog (txt : String) : Boolean {
val dlog = Dialog<ButtonType>()
dlog.dialogPane.apply {
contentText = txt
buttonTypes.apply {
add(ButtonType.OK)
add(ButtonType.CANCEL)
}
minWidth = 200.0
minHeight = 100.0
}
dlog.initOwner(theStage.scene.window)
val r = dlog.showAndWait()
return r.isPresent && r.get() == ButtonType.OK
}
This is called from an EventHandler<ActionEvent> associated with a Button:
if (YNdialog("hello world")) ...
There does seem to be a window created. If I remove the initOwner() call, an icon for it appears in the desktop taskbar (KDE), allowing me to do things like move it, but "maximize" and "resize" are greyed out, and the mouse cursor appears to be dragging nothing, ie., it has no width or height.
With the initOwner() it does much the same thing, except it gets no taskbar icon. Also, there is a visible vertical line one or two pixels thick where it should be (centered over the main window). What's more interesting is a second close button appears in the titlebar of the main window:
This is not part of the javafx interface, but I've never seen the window manager (?) do this before.
Occasionally (maybe one in five or ten times) the dialog does appear, and curiously,
the close button there is offset with space for a second one:
When this happens and I can dismiss the dialog window, the second close button on the main window disappears.
Using Alert
Replacing that function, etc. with:
Alert(Alert.AlertType.CONFIRMATION, "hello world").showAndWait()
.filter { res -> res == ButtonType.OK }
.ifPresent { _ -> log.msg("ok!") }
The result is identical to the YNdialog with initOwner().
Am I missing something here? I got all of this pretty much straight from the docs. I have done custom popup windows (instantiated via FXMLLoader) and have not had any problem with that. Does this experience imply the dialog hierarchy is glitchy in this context and I should roll my own?

How to make "Browse/save file as" dialog show over NSMainMenuWindowLevel

I had the need to create a window so it covers the menubar at top and the dock at bottom. So I had to [NSWindow setLevel:NSMainMenuWindowLevel+1] (if i did just NSMainMenuWindowLevel some of the corner items in the top right of the menubar would still show over my window so I had to go +1).
So now the issue is, a user right clicks in my window (which is a canvas drawing of an image) and then they select "save as", at this point I pop open the "Save as" dialog, but it is showing behind my window. Is there anyway to like find that just opened dialog window with objc and set its level to be above NSMainMenuWindowLevel+1?
Like is there anyway to make this panel open higher then this level:
var NSSavePanel = objc_getClass('NSSavePanel');
var savePanel = sel_registerName('savePanel');
var aSavePanel = objc_msgSend(NSSavePanel, savePanel);
var runModal = sel_registerName('runModal')
Thanks
You have to defer the setting of the save panel's level until after the window is showing, which is tricky. You can do something like this (in Objective-C) before the call to -runModal:
dispatch_async(dispatch_get_main_queue(), ^{
[[NSApp modalWindow] setLevel:NSMainMenuWindowLevel+1];
});
If you can't use GCD, you can use -performSelector:withObject:afterDelay: with a 0 delay. You'll have to use the selector of a method of your own. (You can't use #selector(setLevel:) because that takes a scalar, not an object, as its parameter.)

How to hide a button on an app with multiple windows? - Objective C OSX

I have an application which has a button on the first window, once pressed this button should hide and perform an action, to hide the button i'm using this code:
[self.myButton setHidden:TRUE];
This works fine until I have multiple windows - new instances of this window do not have this button it's hidden by default. However when I create a new window and press the myButton on the first window it doesn't hide the button.
Furthermore if I create a new window and then close that window and press the myButton on the first and now only window it crashes.
It's clear it always seems to target the last window created, how can I make it always target the first window created, or the window the action is actually being sent from?
New windows are simply being created by calling a newDocument from the document controller like so:
[dc newDocument:self];
Most button actions look like this:
- (void)someAction:(NSButton* sender) {}
or
func someAction(sender : NSButton) {}
As you can see, a sender is passed with the action. Now this sender is actually the button you pressed. So you can simply hide this particular button by calling sender.hidden = true;
The sender is automatically added when you use Storyboards or Xibs to add the actions.
If you add the action programmatically, add a colon after the selector (ObjC) or string (Swift). The button instance should be passed to you then.
... action:#selector(someAction:)...
or
... action:"someAction:" ...

Custom context menu XAML for WP8

I try to implement a custom ContextMenu in a LongListSelector.
I'm not using the ContextMenu from Microsoft.Phone.Controls.Toolkit, it's basically the same as in the Rowi App:
(source: hiddenpineapple.com)
Approach 1
My list item toggles a VisualState on hold and an overlay is shown with controls in it.
The problem
I can't find a way to go back to the default state when the user clicks outside of the list item (as in the default ContextMenu).
Approach 2
I've implemented a custom template for the toolkit ContextMenu which looks exactly the same. I had to move its margin top to -itemHeight, as by default it is below the item.
The problem
The problem with this solution is, that it automatically closes itself when opening and I couldn't figure out how to avoid this.
Another problem was that it didn't work well with TiltEffect.IsTiltEnabled from the Toolkit (visual problems).
I need your help
Any suggestions on how to get this working?
Answer
Thanks to Cheese, now I know how to properly close the menu when the user clicks outside.
His suggestion was to get the coordinates of a Tap event on the current page, and check if it's inside the menu. When not, close the menu.
So I added a Tap listener to the page when the menu opens, and removed it when the menu closes. From the page listener I got the event coordinates and could check if it's inside the control which holds the menu (same size and position). I received the position of the control with Point leftUpperPoint = control.TransformToVisual(page).Transform(new Point(0, 0)) and the rightLowerPoint by adding the ActualWidth and ActualHeight.
But then I realized:
Why should I even calculate if the tap is inside the menu? I always want to close the menu when the user taps anywhere on the screen. If it's outside, yes. If it's on a menu button, yes.
Another modification I made was to listen for MouseLeftButtonDown instead of Tap as it also triggers when the user swipes.
So I removed this code and came up with the following:
private void ToggleMenu(object sender, System.Windows.Input.GestureEventArgs e)
{
PhoneApplicationFrame frame = ((PhoneApplicationFrame)Application.Current.RootVisual);
VisualState state = this.States.CurrentState;
if (state == null || state.Name == "DefaultState")
{
frame.MouseLeftButtonDown += MouseDownDelegate;
this.State = "MenuState";
}
else
{
frame.MouseLeftButtonDown -= MouseDownDelegate;
this.State = "DefaultState";
}
}
private void MouseDownDelegate(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
ToggleMenu(sender, null);
}
This works perfectly!
Thanks to Cheese for the hint.
Something like this by #denniscode http://dotnet.dzone.com/articles/rowi-show-tap-menu
Approach 1 problem
The best solution would be:
Get the menus coordinates, when user makes a tap - you check are tap coordinates on menu or not, if not - dissmiss - simple.
Approach 2 problem
I guess you had some button in a corner and when you tapped on it - nothing happened? And when you dissmissed the Tilt all worked. It seems that tilt works faster than a click, so, tilt changes the button coordinates, and device thiks you have missed/or dragged off
You can use what #ScottIsAFool suggested and maybe create another Dependency Property on your TapMenu control of type UIElement named CloseWhenTappedElement and automatically listen for Tap events inside your control once set. For example
<Grid x:Name="TapArea"/>
<TapMenu CloseWhenTappedElement="{Binding ElementName=TapArea"}/>

How to show a Safari Extension popover programmatically

I'm trying to write a Safari extension that consists of a button on the main toolbar with a popover tied to it, and a contextual menu item. The basic feel is modeled after the feel of the 1Password extension.
One of the jobs of the popover is to allow a person to log in. I'm also conditionally changing the action of the contextual menu item, and if a who person isn't logged in clicks the menu item I would like to show the popover allowing them to log in, but I can't find a way to do this in the developer guides.
How do I "show" a popover?
If you only have one toolbar item and one popover (and never plan to add more), then it's just one line. Assuming you've already assigned the popover to the toolbar item in Extension Builder, you can just use:
safari.extension.toolbarItems[0].showPopover();
But if you have more than one popover and (potentially) more than one toolbar item, here's a generalized function to open a popover, specified by its identifier, under the specified toolbar item in the active browser window:
function showPopover(popoverId, toolbarItemId) {
var toolbarItem = safari.extension.toolbarItems.filter(function (tbi) {
return tbi.identifier == toolbarItemId && tbi.browserWindow == safari.application.activeBrowserWindow;
})[0];
var popover = safari.extension.popovers.filter(function (po) {
return po.identifier == popoverId;
})[0];
toolbarItem.popover = popover;
toolbarItem.showPopover();
}