Connecting Multiple NSMenuItems with Actions and State Variables - objective-c

I'm not sure how to describe what I need but I'll give it a try, via an example :
Let's say we have a window and a sidebar, and want to toggle it (I mean the sidebar : on/off).
Now, let's also say that :
The user may toggle the sidebar via an item at the Main menu (e.g. Show Sidebar / Hide Sidebar)
The user may also toggle the sidebar via a button
And there is also another item, in some other menu, to do the very same thing (Show/Hide Sidebar)
What would be the most practical Cocoa-friendly approach to achieve that?
Of course, that means that, e.g. :
When somebody clicks the button, apart from the sidebar (showing or hiding), the menu items must now be showing the current status of the sidebar (e.g. "Show sidebar" must now turn to "Hide Sidebar" in all possible instances within menus, etc)
I hope you get the idea; it's definitely not something difficult; but I'm definitely confused on how I could use all of Cocoa's tricks to do it fast.
Thanks!

I'm assuming you have some controller object which implements an action -toggleSidebar:, and that both menus target the same controller. Also, in the controller, you keep an instance variable BOOL isSidebarShown.
Make your controller implement the NSUserInterfaceValidations protocol. Something like this:
- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem
{
if (anItem.action == #selector(toggleSidebar:) && [anItem isKindOfClass:[NSMenuItem class]])
{
NSString* title = isSidebarShown ? #"Hide Sidebar" : #"Show Sidebar";
[(NSMenuItem*)anItem setTitle:title];
}
return YES; // either way, the menu item is enabled
}

Related

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 click on action bar menu items in test app that having only apk using robotium

I am testing APK file. I dont have source code. I need to click on the action bar menu item
I have tried solo.clickonActionbaritems option and it did not work. Please help me. Many thanks!
I guess you want to click on Android Menu button:
Find your keycode here
solo.sendKey(KeyEvent.KEYCODE_MENU);
Also I highly recommend to use Hierarchy viewer in DDMS to find id of required button.
View requiredButton = getViewById(id.reqired_button_id);
solo.clickOnView(requiredButton);
// Method returns view
protected View getViewById(int id) {
View view = solo.getView(id);
assertNotNull("View is null", view);
assertTrue("View is not shown", view.isShown());
return view;
}
Also you can use clickOnText.

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();
}

Dynamic popup menu for all views

I need to provide a dynamic popup menu for all views. I can create a dynamic popup menu contributibution, but I must set the URI and register it for certain view. Now I'm trying to register the menu dynamically, when the user selects another view:
public class GlobalSelectionListener implements ISelectionListener {
HashSet<IWorkbenchPart> extended = new HashSet<IWorkbenchPart>();
#Override
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
if (!extended.contains(part)) {
IWorkbenchPartSite wps = part.getSite();
if (wps == null)
return;
//creates popup menu for this part
MenuManager mgr = new MenuManager();
mgr.add(new DynamicMenu()); //DynamicMenu extends ContributionItem
wps.registerContextMenu("identifier." + mgr.hashCode(), mgr, wps.getSelectionProvider());
extended.add(part);
System.out.println(part + " menu extended");
}
}
}
But this does not work. No one menu item appears in popup menu. I don't know, whether is it ever possible to do it this way. Is there any method to add popup menu for arbitrary view dynamically? It seems, that the registerContextMenu() method does something else.
The problem was not solved, nevertheless there is a workaround. It is possible to register the pop-up menu in plugin.xml file for all views and editors needed. Usualy the number of plugin usecases is limited. If you're writting a plugin, you know what you need the plugin for. Use the Spy plug-in (ALT+SHIFT+F1) to see the active menu contribution identifiers and register your contribution to the pop-up menu of all views and editors you need.

Something like .NET's "tag" property for Interface Builder

I'm currently struggling to use UI elements in Interface Builder. I keep trying to do things "in the .NET way."
I have several buttons that all map down their TOUCH event to the SAME FUNCTION:
-(IBAction) onTouch:(id) sender
{
// do something with touch, DEPENDING ON WHAT BUTTON WAS PUSHED
// I want to do something like
if( sender.tag == "something" )
{
//...doesn't work on apple, of course..
}
}
I want to uniquely identify each BUTTON USING SOMETHING like the TAG property in .NET. I tried using the INTERFACE BUILDER "NAME" field that is on the "Identity" panel of interface builder, but I don't know how to access that field programmatically.
-(IBAction) onTouch:(id) sender
{
// do something with touch, DEPENDING ON WHAT BUTTON WAS PUSHED
// I want to do something like
if( sender.InterfaceBuilderName == "something" )
{
//...doesn't work..
}
}
So, WHAT / IS THERE a way to uniquely identify a UI element (such as a button) OTHER THAN doing something like
-(IBAction) onTouch:(id) sender
{
// look at
[sender currentTitle]
}
The reason that's bad is because if the text on the button changes for some cosmetic reason you break the whole app, right
The last solution I can think of is write seperate functions for each button's touch event but I really want to know if it is possible to uniquely identify a button by something similar to .Net's TAG property.
In the iPhone SDK all UIView objects have a property also called tag which is an integer value and can basically be used to do what you are intending.
I usually define a constant for the tag values I'm going to use for a specific purpose.
You can access the tag on the button object:
myButton.tag = MYBUTTON_TAG_CONSTANT
// button tag constant
#define MYBUTTON_TAG_CONSTANT 1
For buttons, there is a Tag entry in the View section (click on your button, select Attributes Inspector from the Tools menu). You can then use this integer value in your code.
Here is a link that may help as well:
http://www.iphonedevsdk.com/forum/iphone-sdk-development/25582-using-tags-interface-builder.html
UIView's tag property is accessible from Interface Builder. Unlike .NET, it's an integer rather than a string.