IBAction method with colorwell - objective-c

I have a colorwell that when clicked fires to an IBAction method. There I check to see if the new color selected is different then the default color for an event and if it is, I show a sheet dialog to the user alerting them to this.
The problem I am having is that the color picker calls the action method every time a control such as the slider is moved. This causes the action method to be called n times instead of just once, and I have to respond to the dialog n times.
In IB there is a checkbox for continuous state. If I leave it unchecked it does't call the action method at all. Most slider controls allow you to choose between continuous state or a single state, but I am not seeing this option for a color well.
Any advise appreciated;
Simple Code:
-(IBAction)colorwellManager{
if([self shouldAlertUser] == YES){
[self dialog:#"Your are about to change the default color" #"Confirm Button"];
}
}
If a slider is moved on the color picker, this code executes many times.

I found I good explanation for whats happening here:
NSColorPanel blocking mouse up events (second answer)
The underlying class (NSColorPanel) needs to have it's setContinuous set to NO programmatically in addition to unchecking the colorwell's continuous state checkbox in IB. This allows the color well to call the action method only once per action.

Related

Keeping an NSStatusBarButton highlighted while popover is displayed

Practically all of NSStatusItem has been deprecated for 10.10 and the behavior of the underlying NSStatusBarButton seems to be confusing.
Currently I am working on a menu bar application. When the user clicks the menu bar icon for the app, a method in my application delegate is called via target-action which displays an NSPopover (or closes it if it's already visible) with some information.
Normally, if you've associated, say, an NSMenu with an NSStatusItem when the user clicks on the menu bar icon that icon remains highlighted blue until the menu is closed. Similarly clicking the system volume icon pops down a slider and highlights its icon blue until the view containing the slider disappears.
However, since I'm the one opening the NSPopover, the system instead highlights the icon blue on mouse down, then returns it to normal on mouse up after my method has been called. Meaning there's nothing I can seem to do on that loop to maintain the highlight. I want the icon to continue being highlighted on mouse up and only return to normal when I tell it to (ie. when I close my popover.)
I have no idea how to do this. I've tried using
[self.statusItem.button setHighlighted: YES];
//or [self.statusItem.button highlight: YES];
when I receive the mouse up event in my app delegate and open the popover. The problem is the system still has it, apparently, highlighted this frame/loop from the earlier mouse down and immediately after I set it to highlighted, it sets it to unhighlighted due to the mouse up. I can get around this by encapsulating this in a method and running the method using a timer or delayed selector a split second later. This allows me to keep the icon highlighted but introduces a flicker; the icon is highlighted automatically as the mouse goes down, as the mouse goes up it unhighlights it for a frame, then my method re-highlights it.
I also figured perhaps I could use the deprecated setHighlightMode: and set it to NO to prevent the icon from being highlighted automatically on click, then using setHighlighted: / highlighted: to set it manually but that doesn't work either. Similarly, I thought maybe this would work as well:
NSButtonCell* cell = (NSButtonCell*)self.statusItem.button.cell;
cell.highlightsBy = NSNoCellMask;
But regardless clicking it automatically highlights the icon and dehighlights it on mouse up right after my method is called.
Basically:
The undesirable automatic highlighting behavior of NSStatusBarButton interferes with manually setting the highlight state, unless I delay manually setting it which introduces a short flicker.
The only thing that seems to successfully disable this automatic behavior is the deprecated setHighlightMode:, but this seems to prevent all highlighting, manual or not.
The only work around seems to be to add a subview to the NSButtonCell, add an event listener for mouse up and then set the highlight state of the superview as per here:
NSStatusBarButton keep highlighted
but I would think there'd be a simpler way to just... disable the automatic highlighting altogether.
tl;dr: Is there a way for me to easily obtain full control over when and when not my menu bar icon is highlighted, so that I can have it highlight naturally while my NSPopover is displayed?
I ended up solving this by not setting the NSStatusItem's action selector property. Instead I used NSEvent's addLocalMonitorForEventsMatchingMask:handler:. In the handler block I check if the event.locationInWindow is within my status item's .bounds. If so I send the message the .action would have manually and then return nil to prevent the event from being passed on. If it's not within the status icon's bounds I return event so it gets passed on normally. In my click handling method I use [self.statusItem.button highlight: YES/NO] when my popover is displayed/closed.
TL;DR:
In applicationDidFinishLaunching:
__block AppDelegate* appDelegate = self;
[NSEvent addLocalMonitorForEventsMatchingMask: NSEventMaskFromType(NSLeftMouseDown) handler:^NSEvent* (NSEvent* event){
if (NSPointInRect(event.locationInWindow, appDelegate.statusItem.button.bounds)){
[appDelegate clickedMenuBarIcon: event];
return nil;
}
return event;
}];
In clickedMenuBarIcon: I can then set the highlight state. Since I returned nil in my handler block it prevented the event from getting passed on so the automatic highlighting never occurs and I can do it manually.
If there's any bugs associated with this I'd appreciate any advice.

is single radio button available in cocoa?

I am trying to drag-drop a single radio button from object library in cocoa. But there is "radio group" object is available to drag-drop. In radio group has two radio button.
Is there any way to create a single radio button in cocoa application or hide the one radio button from radio group?
Thanks
You can make it one by going to attribute inspector and set the cell count to 1. but you have to handle the behaviour by your self logically.
Single radio button is not available in object library in cocoa. You can just use a normal UIButton and give its normal and selected images in Interface Builder.
Alternatively, you can just use a custom library for radio button like this one : https://github.com/onegray/RadioButton-ios
You should use a simple UIButton.
You can set different texts/images depending on a button status, like Devanshi suggested. The if/else approach is a bad idea though, because cocoa already provides these and are much more simple and small.
There are two ways, either storyboard (if you use it) or programatically, wherever you create your button (most likely viewDidLoad).
If you are using Storyboard
Storyboard is pretty straightforward, select your button, and under the "State" you can chose different settings. Each settings will actually load different parameters for the next settings. Like the title and image for example.
Just go on state "default" and set an unchecked box as image.
(You can)go on state "Highlighted" and set a temporary highlighted box as image; this is not mandatory.
Then go on state "Selected" and set a checked box as image.
And you're done.
If you are using only code
The programatic way to do this is fairly simple.
I assume we have a button called btSend,
UIControlStateNormal, UIControlStateSelected, UIControlStateDisabled, UIControlStateHighligted, are the states you can use. I used disabled and normal (enabled) here.
[self.btSend setImage:[UIImage imageNamed:#"SendIcon.png"] forState:UIControlStateNormal];
[self.btSend setImage:[UIImage imageNamed:#"SendIconGrayed.png"] forState:UIControlStateDisabled];
With this, you'll be up and running too.
After setting that up
Now that your buttons know what to show depending on their state, you need to add a selector method for your action (an IBAction), in which you will need to invert the state of your current button. You probably already have that, just add a boolean.
checkBoxSelected is a boolean that I created as an instance variable (on top of .m file). You can set it to "NO" in viewDidLoad if your radio is not selected by default, and to YES if it is selected by default.
#implementation TermViewController{
BOOL checkBoxSelected;
}
here is the method that is called when I press the button
- (IBAction)tapRadioButton:(id)sender {
checkBoxSelected = !checkBoxSelected;
[_btCheckbox setSelected:checkBoxSelected];
}
You probably have "something" that checks if your checkbox is selected, to know that, you can either get the state of your button by using self.yourButton.state. This will return a UIControlState, just check if it's Normal or Selected or Disabled or HIghlighted.
Or you can check the Boolean "checkboxselected" if it's YES or NO :)
If you have many radio buttons, you can save all those boolean values in a dictionary. the key would be your button number for example, and the object would be YES or NO. if you press the button, (like shown before), change the button state and also change it in the dictionary. At the end you have all your states in the dictionary.
I didn't explain all that in my first writing because that wasn't really a part of your question :) I hope this helps.
For radio button can use simple UIButton and maintain state of it and replace the image of on click event.
1) Declare globally in view
BOOL isChecked;
2) On button click event
if (isChecked)
{
[_btnRadioBox setImage:[UIImage imageNamed:#"chk_uncheck.png"] forState:UIControlStateNormal];
}
else
{
[_btnRadioBox setImage:[UIImage imageNamed:#"chk_check.png"] forState:UIControlStateNormal];
}
isChecked=!isChecked;
3) And get the status of it.
if (isChecked)
{
// Here write code of radio button when selected
}
else
{
// Here write code of radio button when unselected
}
You can use MVRadioButton to add animated radio button in iOS. This is very simple Drop in and easy to integrate Custom Control.
Its using CoreAnimation and Layers to Give it look and feel exactly like a Traditional Radio button that we have seen on Web.

Buttons as Outlets vs IBActions [Objective C + Xcode]

What is the point of ever setting a button as an outlet? I am following a tutorial and the teacher didn't really mention why he set a button as an outlet. A button is suppose to do an action/call a method and so we set it as an IBAction.
He sets the button as an outlet and then proceeds to change the text of the button through Xcode in viewDidLoad, but why not just keep it as an IBAction and change the text by using setTitle: forState:UIControlStateNormal ?
Isn't a button suppose to cause an action by definition?
in some logic cases you would need to change the behaviour of the button , e.g. upon invoking an action (triggered by other event )you will need to disable it or change its backgroundColor or text.
you don't have to set at all times , but in many cases it is really useful

How to force an NSWindow to be always active/focused?

I have a transparent NSWindow that follows the user's screen everywhere he goes (the NSWindowstays in front of every app, no matter what, even fullscreen apps).
In that NSWindow i have a mouseDown event that shows a popup. Let's say i'm on safari in fullscreen mode and i have my Window in front of it, i click on safari and i click again on my Window: nothing happens, the mouseDown doesn't occur. I have to click again so the mouseDown event is triggered.
How can i force my NSWindow to be always active so i don't have to click it 2x to trigger the mouseDown when i click on a background app and click in my window again?
Thank you!
I'm not sure if this is exactly what you want (it's not quite a window wide setting), but, from the documentation:
By default, a mouse-down event in a window that isn’t the key window
simply brings the window forward and makes it key; the event isn’t
sent to the NSView object over which the mouse click occurs. The
NSView can claim an initial mouse-down event, however, by overriding
acceptsFirstMouse: to return YES.
The argument of this method is the
mouse-down event that occurred in the non-key window, which the view
object can examine to determine whether it wants to receive the mouse
event and potentially become first responder. You want the default
behavior of this method in, for example, a control that affects the
selected object in a window.
However, in certain cases it’s
appropriate to override this behavior, such as for controls that
should receive mouseDown: messages even when the window is inactive.
Examples of controls that support this click-through behavior are the
title-bar buttons of a window.
Or you could try fiddling with
- (void)sendEvent:(NSEvent *)theEvent
and see if you can handle events in a custom way.
If you add a borderless NSButton instance to your window's view and set your image as the button's image (and as its alternate image, to make it more beautiful), it will work out of the box: Just connect the button's action method to your app delegate (or the object where you want to process the click action). A click on the image (i.e. the button) will then trigger the button's action method, no matter which window is active.
This worked for me, hope that will be helpful, This will keep your window always on Top of all applications
[self.window makeKeyAndOrderFront:nil];
[self.window setLevel:NSStatusWindowLevel];
I think what you really should do is use an NSPanel (a floating palette -- a special kind of NSWindow) that will do exactly what you want in a way that's consistent with the OS rather than trying to fight intended behavior.
Here's the NSPanel documentation:
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nspanel_Class/Reference/Reference.html
And here's some helpful and pithy information:
http://cocoadev.com/wiki/NSPanel
By default, an NSPanel will disappear when the application is inactive, but you can turn this off.
I apologize for not laying it out more fully ... pressed for time.
Edit:
Note that you can probably get your window to behave as desired simply:
"The NSView can claim an initial mouse-down event, however, by overriding acceptsFirstMouse: to return YES."
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/EventOverview/HandlingMouseEvents/HandlingMouseEvents.html
You'll need to do this with any NSView subclass to skip the "activation click".

How can I get the value of an NSSlider continuously?

It seems like NSSlider in Cocoa does not provide a delegate to receive an event like Value Changed for a UISlider.
How can I get the value of an NSSlider continuously and display it in an NSTextField, for example?
You need to research Cocoa's Target/Action mechanism. This is a basic Cocoa concept you'll need to understand. The slider (and any other control) can be given a target (some controller object) and an action (the method to call against that controller object).
The action is fired when the user stops dragging by default. Check the slider's Continuous property in Interface Builder to cause it to trigger the action as you're sliding it.
One advantage of using the timer approach is that it works for the case of using the keyboard rather than the mouse to adjust the slider. If the user has "Full Keyboard Access" turned on in System Preferences, they can use the Tab key to give the slider focus. They can then hold down an arrow key so that autorepeat kicks in, whereupon you have a similar situation to dragging with the mouse: the target/action is firing repeatedly, and you want to wait for a moment of calm before saving to the database.
You do need to be careful not to delete your NSTimer prematurely. For example, if the user quits the app during those couple of seconds you probably want to "flush" the slider value to the database before terminating the process.
Programmatical solution based on the answer of Joshua Nozzi:
Swift
slider.isContinuous = true
Objective-C
slider.continuous = YES;