![]() |
API 0.9.5
|
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