API 0.9.5
AppKit/CPSegmentedControl.j
Go to the documentation of this file.
00001 /*
00002  * CPSegmentedControl.j
00003  * AppKit
00004  *
00005  * Created by Francisco Tolmasky.
00006  * Copyright 2008, 280 North, Inc.
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00021  */
00022 
00023 
00024 
00025 
00026 CPSegmentSwitchTrackingSelectOne = 0;
00027 CPSegmentSwitchTrackingSelectAny = 1;
00028 CPSegmentSwitchTrackingMomentary = 2;
00029 
00036 @implementation CPSegmentedControl : CPControl
00037 {
00038     CPArray                 _segments;
00039     CPArray                 _themeStates;
00040 
00041     int                     _selectedSegment;
00042     int                     _segmentStyle;
00043     CPSegmentSwitchTracking _trackingMode;
00044 
00045     unsigned                _trackingSegment;
00046     BOOL                    _trackingHighlighted;
00047 }
00048 
00049 + (CPString)defaultThemeClass
00050 {
00051     return "segmented-control";
00052 }
00053 
00054 + (id)themeAttributes
00055 {
00056     return [CPDictionary dictionaryWithObjects:[CPCenterTextAlignment, CPCenterVerticalTextAlignment, CPImageLeft, CPScaleNone, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], [CPNull null], 1.0, 24.0]
00057                                        forKeys:[@"alignment", @"vertical-alignment", @"image-position", @"image-scaling", @"bezel-inset", @"content-inset", @"left-segment-bezel-color", @"right-segment-bezel-color", @"center-segment-bezel-color", @"divider-bezel-color", @"divider-thickness", @"default-height"]];
00058 }
00059 
00060 - (id)initWithFrame:(CGRect)aRect
00061 {
00062     _segments = [];
00063     _themeStates = [];
00064 
00065     self = [super initWithFrame:aRect];
00066 
00067     if (self)
00068     {
00069         _selectedSegment = -1;
00070 
00071         _trackingMode = CPSegmentSwitchTrackingSelectOne;
00072     }
00073 
00074     return self;
00075 }
00076 
00080 - (int)selectedTag
00081 {
00082     return [_segments[_selectedSegment] tag];
00083 }
00084 
00085 // Specifying the number of segments
00090 - (void)setSegmentCount:(unsigned)aCount
00091 {
00092     if (_segments.length == aCount)
00093         return;
00094 
00095     var height = CGRectGetHeight([self bounds]),
00096         dividersBefore = MAX(0, _segments.length - 1),
00097         dividersAfter = MAX(0, aCount - 1);
00098 
00099     if (_segments.length < aCount)
00100     {
00101         for (var index = _segments.length; index < aCount; ++index)
00102         {
00103             _segments[index] = [[_CPSegmentItem alloc] init];
00104             _themeStates[index] = CPThemeStateNormal;
00105         }
00106     }
00107     else if (aCount < _segments.length)
00108     {
00109         _segments.length = aCount;
00110         _themeStates.length = aCount;
00111     }
00112 
00113     if (_selectedSegment >= _segments.length)
00114         _selectedSegment = -1;
00115 
00116     // Make space for/remove space used by dividers.
00117     var thickness = [self currentValueForThemeAttribute:@"divider-thickness"],
00118         delta = thickness * (dividersAfter - dividersBefore),
00119         frame = [self frame];
00120 
00121     if (delta)
00122         [self setFrameSize:CGSizeMake(frame.size.width + delta, frame.size.height)];
00123 
00124     [self tileWithChangedSegment:0];
00125 }
00126 
00130 - (unsigned)segmentCount
00131 {
00132     return _segments.length;
00133 }
00134 
00135 // Specifying Selected Segment
00141 - (void)setSelectedSegment:(unsigned)aSegment
00142 {
00143     // setSelected:forSegment throws the exception for us (if necessary)
00144     [self setSelected:YES forSegment:aSegment];
00145 }
00146 
00150 - (unsigned)selectedSegment
00151 {
00152     return _selectedSegment;
00153 }
00154 
00158 - (BOOL)selectSegmentWithTag:(int)aTag
00159 {
00160     var index = 0;
00161 
00162     for (; index < _segments.length; ++index)
00163         if (_segments[index].tag == aTag)
00164         {
00165             [self setSelectedSegment:index];
00166 
00167             return YES;
00168         }
00169 
00170     return NO;
00171 }
00172 
00173 // Specifying Tracking Mode
00174 
00175 - (BOOL)isTracking
00176 {
00177 
00178 }
00179 
00180 - (void)setTrackingMode:(CPSegmentSwitchTracking)aTrackingMode
00181 {
00182     if (_trackingMode == aTrackingMode)
00183         return;
00184 
00185     _trackingMode = aTrackingMode;
00186 
00187     if (_trackingMode == CPSegmentSwitchTrackingSelectOne)
00188     {
00189         var index = 0,
00190             selected = NO;
00191 
00192         for (; index < _segments.length; ++index)
00193             if ([_segments[index] selected])
00194                 if (selected)
00195                     [self setSelected:NO forSegment:index];
00196                 else
00197                     selected = YES;
00198     }
00199 
00200     else if (_trackingMode == CPSegmentSwitchTrackingMomentary)
00201     {
00202         var index = 0;
00203 
00204         for (; index < _segments.length; ++index)
00205             if ([_segments[index] selected])
00206                 [self setSelected:NO forSegment:index];
00207     }
00208 }
00209 
00213 - (CPSegmentSwitchTracking)trackingMode
00214 {
00215     return _trackingMode;
00216 }
00217 
00218 // Working with Individual Segments
00225 - (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
00226 {
00227     [_segments[aSegment] setWidth:aWidth];
00228 
00229     [self tileWithChangedSegment:aSegment];
00230 }
00231 
00237 - (float)widthForSegment:(unsigned)aSegment
00238 {
00239     return [_segments[aSegment] width];
00240 }
00241 
00248 - (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
00249 {
00250     [_segments[aSegment] setImage:anImage];
00251 
00252     [self tileWithChangedSegment:aSegment];
00253 }
00254 
00260 - (CPImage)imageForSegment:(unsigned)aSegment
00261 {
00262     return [_segments[aSegment] image];
00263 }
00264 
00271 - (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
00272 {
00273     [_segments[aSegment] setLabel:aLabel];
00274 
00275     [self tileWithChangedSegment:aSegment];
00276 }
00277 
00283 - (CPString)labelForSegment:(unsigned)aSegment
00284 {
00285     return [_segments[aSegment] label];
00286 }
00287 
00294 - (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
00295 {
00296     [_segments[aSegment] setMenu:aMenu];
00297 }
00298 
00304 - (CPMenu)menuForSegment:(unsigned)aSegment
00305 {
00306     return [_segments[aSegment] menu];
00307 }
00308 
00316 - (void)setSelected:(BOOL)isSelected forSegment:(unsigned)aSegment
00317 {
00318     var segment = _segments[aSegment];
00319 
00320     // If we're already in this state, bail.
00321     if ([segment selected] == isSelected)
00322         return;
00323 
00324     [segment setSelected:isSelected];
00325 
00326     _themeStates[aSegment] = isSelected ? CPThemeStateSelected : CPThemeStateNormal;
00327 
00328     // We need to do some cleanup if we only allow one selection.
00329     if (isSelected)
00330     {
00331         var oldSelectedSegment = _selectedSegment;
00332 
00333         _selectedSegment = aSegment;
00334 
00335         if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1)
00336         {
00337             [_segments[oldSelectedSegment] setSelected:NO];
00338             _themeStates[oldSelectedSegment] = CPThemeStateNormal;
00339 
00340             [self drawSegmentBezel:oldSelectedSegment highlight:NO];
00341         }
00342     }
00343 
00344     if (_trackingMode != CPSegmentSwitchTrackingMomentary)
00345         [self drawSegmentBezel:aSegment highlight:NO];
00346 
00347     [self setNeedsLayout];
00348     [self setNeedsDisplay:YES];
00349 }
00350 
00356 - (BOOL)isSelectedForSegment:(unsigned)aSegment
00357 {
00358     return [_segments[aSegment] selected];
00359 }
00360 
00367 - (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
00368 {
00369     [_segments[aSegment] setEnabled:isEnabled];
00370 
00371     if (isEnabled)
00372         _themeStates[aSegment] &= ~CPThemeStateDisabled;
00373     else
00374         _themeStates[aSegment] |= CPThemeStateDisabled;
00375 
00376     [self setNeedsLayout];
00377     [self setNeedsDisplay:YES];
00378 }
00379 
00385 - (BOOL)isEnabledForSegment:(unsigned)aSegment
00386 {
00387     return [_segments[aSegment] enabled];
00388 }
00389 
00395 - (void)setTag:(int)aTag forSegment:(unsigned)aSegment
00396 {
00397     [_segments[aSegment] setTag:aTag];
00398 }
00399 
00404 - (int)tagForSegment:(unsigned)aSegment
00405 {
00406     return [_segments[aSegment] tag];
00407 }
00408 
00409 // Drawings
00415 - (void)drawSegmentBezel:(int)aSegment highlight:(BOOL)shouldHighlight
00416 {
00417     if (shouldHighlight)
00418         _themeStates[aSegment] |= CPThemeStateHighlighted;
00419     else
00420         _themeStates[aSegment] &= ~CPThemeStateHighlighted;
00421 
00422     [self setNeedsLayout];
00423     [self setNeedsDisplay:YES];
00424 }
00425 
00426 - (float)_leftOffsetForSegment:(unsigned)segment
00427 {
00428     var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
00429 
00430     if (segment == 0)
00431         return bezelInset.left;
00432 
00433     var thickness = [self currentValueForThemeAttribute:@"divider-thickness"];
00434 
00435     return [self _leftOffsetForSegment:segment - 1] + [self widthForSegment:segment - 1] + thickness;
00436 }
00437 
00438 - (unsigned)_indexOfLastSegment
00439 {
00440     var lastSegmentIndex = [_segments count] - 1;
00441 
00442     if (lastSegmentIndex < 0)
00443         lastSegmentIndex = 0;
00444 
00445     return lastSegmentIndex;
00446 }
00447 
00448 - (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
00449 {
00450     var height = [self currentValueForThemeAttribute:@"default-height"],
00451         contentInset = [self currentValueForThemeAttribute:@"content-inset"],
00452         bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"],
00453         bounds = [self bounds];
00454 
00455     if (aName === "left-segment-bezel")
00456     {
00457         return CGRectMake(bezelInset.left, bezelInset.top, contentInset.left, height);
00458     }
00459     else if (aName === "right-segment-bezel")
00460     {
00461         return CPRectMake(CGRectGetWidth([self bounds]) - contentInset.right,
00462                             bezelInset.top,
00463                             contentInset.right,
00464                             height);
00465     }
00466     else if (aName.indexOf("segment-bezel") === 0)
00467     {
00468         var segment = parseInt(aName.substring("segment-bezel-".length), 10),
00469             frame = CGRectCreateCopy([_segments[segment] frame]);
00470 
00471         if (segment === 0)
00472         {
00473             frame.origin.x += contentInset.left;
00474             frame.size.width -= contentInset.left;
00475         }
00476 
00477         if (segment === _segments.length - 1)
00478             frame.size.width = CGRectGetWidth([self bounds]) - contentInset.right - frame.origin.x;
00479 
00480         return frame;
00481     }
00482     else if (aName.indexOf("divider-bezel") === 0)
00483     {
00484         var segment = parseInt(aName.substring("divider-bezel-".length), 10),
00485             width = [self widthForSegment:segment],
00486             left = [self _leftOffsetForSegment:segment],
00487             thickness = [self currentValueForThemeAttribute:@"divider-thickness"];
00488 
00489         return CGRectMake(left + width, bezelInset.top, thickness, height);
00490     }
00491     else if (aName.indexOf("segment-content") === 0)
00492     {
00493         var segment = parseInt(aName.substring("segment-content-".length), 10);
00494 
00495         return [self contentFrameForSegment:segment];
00496     }
00497 
00498     return [super rectForEphemeralSubviewNamed:aName];
00499 }
00500 
00501 - (CPView)createEphemeralSubviewNamed:(CPString)aName
00502 {
00503     if ([aName hasPrefix:@"segment-content"])
00504         return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
00505 
00506     return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
00507 }
00508 
00509 - (void)layoutSubviews
00510 {
00511     if (_segments.length <= 0)
00512         return;
00513 
00514     var themeState = _themeStates[0];
00515 
00516     themeState |= _themeState & CPThemeStateDisabled;
00517 
00518     var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
00519                                             inState:themeState],
00520 
00521         leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
00522                                                positioned:CPWindowBelow
00523                           relativeToEphemeralSubviewNamed:nil];
00524 
00525     [leftBezelView setBackgroundColor:leftCapColor];
00526 
00527     var themeState = _themeStates[_themeStates.length - 1];
00528 
00529     themeState |= _themeState & CPThemeStateDisabled;
00530 
00531     var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
00532                                              inState:themeState],
00533 
00534         rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
00535                                                positioned:CPWindowBelow
00536                           relativeToEphemeralSubviewNamed:nil];
00537 
00538     [rightBezelView setBackgroundColor:rightCapColor];
00539 
00540     for (var i = 0, count = _themeStates.length; i < count; i++)
00541     {
00542         var themeState = _themeStates[i];
00543 
00544         themeState |= _themeState & CPThemeStateDisabled;
00545 
00546         var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color"
00547                                               inState:themeState],
00548 
00549             bezelView = [self layoutEphemeralSubviewNamed:"segment-bezel-" + i
00550                                                positioned:CPWindowBelow
00551                           relativeToEphemeralSubviewNamed:nil];
00552 
00553         [bezelView setBackgroundColor:bezelColor];
00554 
00555 
00556         // layout image/title views
00557         var segment = _segments[i],
00558             contentView = [self layoutEphemeralSubviewNamed:@"segment-content-" + i
00559                                                  positioned:CPWindowAbove
00560                             relativeToEphemeralSubviewNamed:@"segment-bezel-" + i];
00561 
00562         [contentView setText:[segment label]];
00563         [contentView setImage:[segment image]];
00564 
00565         [contentView setFont:[self valueForThemeAttribute:@"font" inState:themeState]];
00566         [contentView setTextColor:[self valueForThemeAttribute:@"text-color" inState:themeState]];
00567         [contentView setAlignment:[self valueForThemeAttribute:@"alignment" inState:themeState]];
00568         [contentView setVerticalAlignment:[self valueForThemeAttribute:@"vertical-alignment" inState:themeState]];
00569         [contentView setLineBreakMode:[self valueForThemeAttribute:@"line-break-mode" inState:themeState]];
00570         [contentView setTextShadowColor:[self valueForThemeAttribute:@"text-shadow-color" inState:themeState]];
00571         [contentView setTextShadowOffset:[self valueForThemeAttribute:@"text-shadow-offset" inState:themeState]];
00572         [contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" inState:themeState]];
00573 
00574         if ([segment image] && [segment label])
00575             [contentView setImagePosition:[self valueForThemeAttribute:@"image-position" inState:themeState]];
00576         else if ([segment image])
00577             [contentView setImagePosition:CPImageOnly];
00578 
00579         if (i == count - 1)
00580             continue;
00581 
00582         var borderState = _themeStates[i] | _themeStates[i + 1];
00583 
00584         borderState = (borderState & CPThemeStateSelected & ~CPThemeStateHighlighted) ? CPThemeStateSelected : CPThemeStateNormal;
00585 
00586         borderState |= _themeState & CPThemeStateDisabled;
00587 
00588         var borderColor = [self valueForThemeAttribute:@"divider-bezel-color"
00589                                                inState:borderState],
00590 
00591             borderView = [self layoutEphemeralSubviewNamed:"divider-bezel-" + i
00592                                                 positioned:CPWindowBelow
00593                            relativeToEphemeralSubviewNamed:nil];
00594 
00595         [borderView setBackgroundColor:borderColor];
00596     }
00597 }
00598 
00599 
00605 - (void)drawSegment:(int)aSegment highlight:(BOOL)shouldHighlight
00606 {
00607 }
00608 
00609 - (void)tileWithChangedSegment:(unsigned)aSegment
00610 {
00611     if (aSegment >= _segments.length)
00612         return;
00613 
00614     var segment = _segments[aSegment],
00615         segmentWidth = [segment width],
00616         themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled),
00617         contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState],
00618         font = [self font];
00619 
00620     if (!segmentWidth)
00621     {
00622         if ([segment image] && [segment label])
00623             segmentWidth = [[segment label] sizeWithFont:font].width + [[segment image] size].width + contentInset.left + contentInset.right;
00624         else if (segment.image)
00625             segmentWidth = [[segment image] size].width + contentInset.left + contentInset.right;
00626         else if (segment.label)
00627             segmentWidth = [[segment label] sizeWithFont:font].width + contentInset.left + contentInset.right;
00628         else
00629             segmentWidth = 0.0;
00630     }
00631 
00632     var delta = segmentWidth - CGRectGetWidth([segment frame]);
00633 
00634     if (!delta)
00635     {
00636         [self setNeedsLayout];
00637         [self setNeedsDisplay:YES];
00638 
00639         return;
00640     }
00641 
00642     // Update control size
00643     var frame = [self frame];
00644 
00645     [self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))];
00646 
00647     // Update segment width
00648     [segment setWidth:segmentWidth];
00649     [segment setFrame:[self frameForSegment:aSegment]];
00650 
00651     // Update following segments widths
00652     var index = aSegment + 1;
00653 
00654     for (; index < _segments.length; ++index)
00655     {
00656         [_segments[index] frame].origin.x += delta;
00657 
00658         [self drawSegmentBezel:index highlight:NO];
00659         [self drawSegment:index highlight:NO];
00660     }
00661 
00662     [self drawSegmentBezel:aSegment highlight:NO];
00663     [self drawSegment:aSegment highlight:NO];
00664 
00665     [self setNeedsLayout];
00666     [self setNeedsDisplay:YES];
00667 }
00668 
00673 - (CGRect)frameForSegment:(unsigned)aSegment
00674 {
00675     return [self bezelFrameForSegment:aSegment];
00676 }
00677 
00678 - (CGRect)bezelFrameForSegment:(unsigned)aSegment
00679 {
00680     var height = [self currentValueForThemeAttribute:@"default-height"],
00681         bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"],
00682         width = [self widthForSegment:aSegment],
00683         left = [self _leftOffsetForSegment:aSegment];
00684 
00685     return CGRectMake(left, bezelInset.top, width, height);
00686 }
00687 
00688 - (CGRect)contentFrameForSegment:(unsigned)aSegment
00689 {
00690     var height = [self currentValueForThemeAttribute:@"default-height"],
00691         contentInset = [self currentValueForThemeAttribute:@"content-inset"],
00692         width = [self widthForSegment:aSegment],
00693         left = [self _leftOffsetForSegment:aSegment];
00694 
00695     return CGRectMake(left + contentInset.left, contentInset.top, width - contentInset.left - contentInset.right, height - contentInset.top - contentInset.bottom);
00696 }
00697 
00703 - (unsigned)testSegment:(CGPoint)aPoint
00704 {
00705     var location = [self convertPoint:aPoint fromView:nil],
00706         count = _segments.length;
00707 
00708     while (count--)
00709         if (CGRectContainsPoint([_segments[count] frame], aPoint))
00710             return count;
00711 
00712     if (_segments.length)
00713     {
00714         var adjustedLastFrame = CGRectCreateCopy([_segments[_segments.length - 1] frame]);
00715         adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x;
00716 
00717         if (CGRectContainsPoint(adjustedLastFrame, aPoint))
00718             return _segments.length - 1;
00719     }
00720 
00721     return -1;
00722 }
00723 
00724 - (void)mouseDown:(CPEvent)anEvent
00725 {
00726     if (![self isEnabled])
00727         return;
00728 
00729     [self trackSegment:anEvent];
00730 }
00731 
00732 // FIXME: this should be fixed way up in cpbutton/cpcontrol.
00733 - (void)mouseUp:(CPEvent)anEvent
00734 {
00735 }
00736 
00741 - (void)trackSegment:(CPEvent)anEvent
00742 {
00743     var type = [anEvent type],
00744         location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
00745 
00746     if (type == CPLeftMouseUp)
00747     {
00748         if (_trackingSegment == -1)
00749             return;
00750 
00751         if (_trackingSegment === [self testSegment:location])
00752         {
00753             if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
00754             {
00755                 [self setSelected:![self isSelectedForSegment:_trackingSegment] forSegment:_trackingSegment];
00756 
00757                 // With ANY, _selectedSegment means last pressed.
00758                 _selectedSegment = _trackingSegment;
00759             }
00760             else
00761                 [self setSelected:YES forSegment:_trackingSegment];
00762 
00763             [self sendAction:[self action] to:[self target]];
00764 
00765             if (_trackingMode == CPSegmentSwitchTrackingMomentary)
00766             {
00767                 [self setSelected:NO forSegment:_trackingSegment];
00768 
00769                 _selectedSegment = -1;
00770             }
00771         }
00772 
00773         [self drawSegmentBezel:_trackingSegment highlight:NO];
00774 
00775         _trackingSegment = -1;
00776 
00777         return;
00778     }
00779 
00780     if (type == CPLeftMouseDown)
00781     {
00782         var trackingSegment = [self testSegment:location];
00783         if (trackingSegment > -1 && [self isEnabledForSegment:trackingSegment])
00784         {
00785             _trackingHighlighted = YES;
00786             _trackingSegment = trackingSegment;
00787             [self drawSegmentBezel:_trackingSegment highlight:YES];
00788         }
00789     }
00790 
00791     else if (type == CPLeftMouseDragged)
00792     {
00793         if (_trackingSegment == -1)
00794             return;
00795 
00796         var highlighted = [self testSegment:location] === _trackingSegment;
00797         if (highlighted != _trackingHighlighted)
00798         {
00799             _trackingHighlighted = highlighted;
00800 
00801             [self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
00802         }
00803     }
00804 
00805     [CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
00806 }
00807 
00808 - (void)setFont:(CPFont)aFont
00809 {
00810     [super setFont:aFont];
00811 
00812     [self tileWithChangedSegment:0];
00813 }
00814 
00815 @end
00816 
00817 var CPSegmentedControlSegmentsKey       = "CPSegmentedControlSegmentsKey",
00818     CPSegmentedControlSelectedKey       = "CPSegmentedControlSelectedKey",
00819     CPSegmentedControlSegmentStyleKey   = "CPSegmentedControlSegmentStyleKey",
00820     CPSegmentedControlTrackingModeKey   = "CPSegmentedControlTrackingModeKey";
00821 
00822 @implementation CPSegmentedControl (CPCoding)
00823 
00824 - (id)initWithCoder:(CPCoder)aCoder
00825 {
00826     self = [super initWithCoder:aCoder];
00827 
00828     if (self)
00829     {
00830         var frame = [self frame],
00831             originalWidth = frame.size.width;
00832 
00833         frame.size.width = 0;
00834 
00835         [self setFrame:frame];
00836 
00837         _segments       = [aCoder decodeObjectForKey:CPSegmentedControlSegmentsKey];
00838         _segmentStyle   = [aCoder decodeIntForKey:CPSegmentedControlSegmentStyleKey];
00839         _themeStates  = [];
00840 
00841         if ([aCoder containsValueForKey:CPSegmentedControlSelectedKey])
00842             _selectedSegment = [aCoder decodeIntForKey:CPSegmentedControlSelectedKey];
00843         else
00844             _selectedSegment = -1;
00845 
00846         if ([aCoder containsValueForKey:CPSegmentedControlTrackingModeKey])
00847             _trackingMode = [aCoder decodeIntForKey:CPSegmentedControlTrackingModeKey];
00848         else
00849             _trackingMode = CPSegmentSwitchTrackingSelectOne;
00850 
00851         // HACK
00852 
00853         for (var i = 0; i < _segments.length; i++)
00854         {
00855             _themeStates[i] = [_segments[i] selected] ? CPThemeStateSelected : CPThemeStateNormal;
00856             [self tileWithChangedSegment:i];
00857         }
00858 
00859         var difference = MAX(originalWidth - [self frame].size.width, 0.0),
00860             remainingWidth = FLOOR(difference / _segments.length);
00861 
00862         for (var i = 0; i < _segments.length; i++)
00863             [self setWidth:[_segments[i] width] + remainingWidth forSegment:i];
00864 
00865         [self tileWithChangedSegment:0];
00866     }
00867 
00868     return self;
00869 }
00870 
00871 - (void)encodeWithCoder:(CPCoder)aCoder
00872 {
00873     [super encodeWithCoder:aCoder];
00874 
00875     [aCoder encodeObject:_segments forKey:CPSegmentedControlSegmentsKey];
00876     [aCoder encodeInt:_selectedSegment forKey:CPSegmentedControlSelectedKey];
00877     [aCoder encodeInt:_segmentStyle forKey:CPSegmentedControlSegmentStyleKey];
00878     [aCoder encodeInt:_trackingMode forKey:CPSegmentedControlTrackingModeKey];
00879 }
00880 
00881 @end
00882 
00883 
00884 @implementation _CPSegmentItem : CPObject
00885 {
00886     CPImage     image;
00887     CPString    label;
00888     CPMenu      menu;
00889     BOOL        selected;
00890     BOOL        enabled;
00891     int         tag;
00892     int         width;
00893 
00894     CGRect      frame;
00895 }
00896 
00897 - (id)init
00898 {
00899     if (self = [super init])
00900     {
00901         image        = nil;
00902         label        = @"";
00903         menu         = nil;
00904         selected     = NO;
00905         enabled      = YES;
00906         tag          = -1;
00907         width        = 0;
00908 
00909         frame        = CGRectMakeZero();
00910     }
00911     return self;
00912 }
00913 
00914 @end
00915 
00916 var CPSegmentItemImageKey       = "CPSegmentItemImageKey",
00917     CPSegmentItemLabelKey       = "CPSegmentItemLabelKey",
00918     CPSegmentItemMenuKey        = "CPSegmentItemMenuKey",
00919     CPSegmentItemSelectedKey    = "CPSegmentItemSelectedKey",
00920     CPSegmentItemEnabledKey     = "CPSegmentItemEnabledKey",
00921     CPSegmentItemTagKey         = "CPSegmentItemTagKey",
00922     CPSegmentItemWidthKey       = "CPSegmentItemWidthKey";
00923 
00924 @implementation _CPSegmentItem (CPCoding)
00925 
00926 - (id)initWithCoder:(CPCoder)aCoder
00927 {
00928     self = [super init];
00929 
00930     if (self)
00931     {
00932         image        = [aCoder decodeObjectForKey:CPSegmentItemImageKey];
00933         label        = [aCoder decodeObjectForKey:CPSegmentItemLabelKey];
00934         menu         = [aCoder decodeObjectForKey:CPSegmentItemMenuKey];
00935         selected     = [aCoder decodeBoolForKey:CPSegmentItemSelectedKey];
00936         enabled      = [aCoder decodeBoolForKey:CPSegmentItemEnabledKey];
00937         tag          = [aCoder decodeIntForKey:CPSegmentItemTagKey];
00938         width        = [aCoder decodeFloatForKey:CPSegmentItemWidthKey];
00939 
00940         frame        = CGRectMakeZero();
00941     }
00942 
00943     return self;
00944 }
00945 
00946 - (void)encodeWithCoder:(CPCoder)aCoder
00947 {
00948     [aCoder encodeObject:image  forKey:CPSegmentItemImageKey];
00949     [aCoder encodeObject:label  forKey:CPSegmentItemLabelKey];
00950     [aCoder encodeObject:menu   forKey:CPSegmentItemMenuKey];
00951     [aCoder encodeBool:selected forKey:CPSegmentItemSelectedKey];
00952     [aCoder encodeBool:enabled  forKey:CPSegmentItemEnabledKey];
00953     [aCoder encodeInt:tag       forKey:CPSegmentItemTagKey];
00954     [aCoder encodeFloat:width   forKey:CPSegmentItemWidthKey];
00955 }
00956 
00957 @end
 All Classes Files Functions Variables Defines