Hi all,

I'm trying to work out the correct way to handle a mixed-state checkbox 
(NSButton checkbox with allowsMixedState=YES), bound to a property on my 
controller. I am intending it to serve as an "applies to all" type control at 
the head of a column of checkboxes - so if other checkboxes in the column are 
toggled, it will display a state of on (if all in column are on), off (if all 
are off), or mixed if there is a mixture of states in the column. 

My property has no backing variable, but a manually-implemented getter and 
setter. I am happy with how the getter is working - it scans the column and 
returns the appropriate state. What I am not sure about is how to handle the 
setter.

It seems that allowsMixedState makes it possible to *present* the mixed state, 
but also means that the user can click through the three states in order. What 
I believe the normal interface would be in my situation is for a user click on 
a box in on (or off) state to switch it to off (or on), and a click on mixed 
state puts it to either on or off (not sure which). What I would not expect is 
for a click when in off state to put it into MIXED state. In this interface (if 
I have described it clearly!) it makes no sense for the user to actively put 
the checkbox into mixed state.

So... my question is how to implement the correct behaviour? 

1. It would be great if there was a flag I could set that says "behave like I 
want", but I can't see one!

2. Failing that, I believe what I need to do is to spot the setter being called 
with a value of -1 (mixed), and overrule that. However, I haven't found a way 
of doing that that "feels right" - all successful approaches feel like a hack 
rather than the right way of doing it. My setter code currently looks like this:

-(void)setGlobalChannelEnableState:(NSInteger)state
{
        if (state == -1)
        {
#if 0
                // Checkbox remains in '-' state if I use this code
                [self willChangeValueForKey:@"globalChannelEnableState"];
                state = 1;
                [self didChangeValueForKey:@"globalChannelEnableState"];
#elif 1
                // Works. Schedule another call in a moment, to update the 
value to 'on'
                dispatch_async(dispatch_get_main_queue(), ^{ 
self.globalChannelEnableState = 1; });
                return;
#else
                // Also works. Change the input state and fall through to the 
code that does the actual updating (below)
                state = 1;
                dispatch_async(dispatch_get_main_queue(),
                                           ^{
                                                   [self 
willChangeValueForKey:@"globalChannelEnableState"];
                                                   [self 
didChangeValueForKey:@"globalChannelEnableState"];
                                           });
#endif
        }
        
        // Update state for all individual channels [code not shown here]
}


Can anybody comment, and maybe suggest a more elegant way of handling this? For 
brevity, I have not shown the getter code, but remember that there is no 
backing variable and the getter just examines the current program state to 
determine what the correct value is.

Thanks for any comments
Jonny.
_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to