00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import <Foundation/CPArray.j>
00024
00025 @import "CPControl.j"
00026
00027
00028
00029
00030
00031 CPSegmentSwitchTrackingSelectOne = 0;
00032
00033
00034
00035
00036 CPSegmentSwitchTrackingSelectAny = 1;
00037
00038
00039
00040
00041 CPSegmentSwitchTrackingMomentary = 2;
00042
00047 @implementation CPSegmentedControl : CPControl
00048 {
00049 unsigned _segmentCount;
00050
00051 CPArray _segments;
00052 CPArray _selectedSegment;
00053
00054 CPSegmentSwitchTracking _trackingMode;
00055 unsigned _trackingSegment;
00056 BOOL _trackingHighlighted;
00057 }
00058
00059 - (id)initWithFrame:(CGRect)aRect
00060 {
00061 self = [super initWithFrame:aRect];
00062
00063 if (self)
00064 {
00065 _segments = [];
00066 _selectedSegment = -1;
00067
00068 _segmentCount = 0;
00069
00070 _trackingMode = CPSegmentSwitchTrackingSelectOne;
00071 }
00072
00073 return self;
00074 }
00075
00079 - (int)selectedTag
00080 {
00081 return _segments[_selectedSegment].tag;
00082 }
00083
00084
00089 - (void)setSegmentCount:(unsigned)aCount
00090 {
00091 if (_segmentCount == aCount)
00092 return;
00093
00094 var height = CGRectGetHeight([self bounds]);
00095
00096 if (_segmentCount < aCount)
00097 {
00098 var index = _segmentCount;
00099
00100 for (; index < aCount; ++index)
00101 {
00102 _segments[index] = _CPSegmentMake();
00103 _segments[index].frame.size.height = height;
00104 }
00105 }
00106 else if (aCount < _segmentCount)
00107 {
00108 var index = aCount;
00109
00110 for (; index < _segmentCount; ++index)
00111 {
00112 [_segments[index].imageView removeFromSuperview];
00113 [_segments[index].labelView removeFromSuperview];
00114
00115 _segments[index] = nil;
00116 }
00117 }
00118
00119 _segmentCount = aCount;
00120
00121 if (_selectedSegment < _segmentCount)
00122 _selectedSegment = -1;
00123
00124 [self tileWithChangedSegment:0];
00125 }
00126
00130 - (unsigned)segmentCount
00131 {
00132 return _segmentCount;
00133 }
00134
00135
00141 - (void)setSelectedSegment:(unsigned)aSegment
00142 {
00143
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 < _segmentCount; ++index)
00163 if (_segments[index].tag == aTag)
00164 {
00165 [self setSelectedSegment:index];
00166
00167 return YES;
00168 }
00169
00170 return NO;
00171 }
00172
00173
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 < _segmentCount; ++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 < _segmentCount; ++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
00225 - (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
00226 {
00227 _segments[aSegment].width = 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 var segment = _segments[aSegment];
00251
00252 if (!anImage)
00253 {
00254 [segment.imageView removeFromSuperview];
00255
00256 segment.imageView = nil;
00257 }
00258
00259 else
00260 {
00261 if (!segment.imageView)
00262 {
00263 segment.imageView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
00264
00265 [self addSubview:segment.imageView];
00266 }
00267
00268 [segment.imageView setImage:anImage];
00269 [segment.imageView setFrameSize:CGSizeMakeCopy([anImage size])];
00270 }
00271
00272 segment.image = anImage;
00273
00274 if (segment.width)
00275 [self drawSegment:aSegment highlight:NO];
00276 else
00277 [self tileWithChangedSegment:aSegment];
00278 }
00279
00285 - (CPImage)imageForSegment:(unsigned)aSegment
00286 {
00287 return _segments[aSegment].image;
00288 }
00289
00296 - (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
00297 {
00298 var segment = _segments[aSegment];
00299
00300 if (!aLabel || !aLabel.length)
00301 {
00302 [segment.labelView removeFromSuperview];
00303
00304 segment.labelView = nil;
00305 }
00306
00307 else
00308 {
00309 if (!segment.labelView)
00310 {
00311 segment.labelView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
00312
00313 [segment.labelView setFont:[self font]];
00314
00315 [self addSubview:segment.labelView];
00316 }
00317
00318 [segment.labelView setStringValue:aLabel];
00319 [segment.labelView sizeToFit];
00320 }
00321
00322 _segments[aSegment].label = aLabel;
00323
00324 if (segment.width)
00325 [self drawSegment:aSegment highlight:NO];
00326 else
00327 [self tileWithChangedSegment:aSegment];
00328 }
00329
00335 - (CPString)labelForSegment:(unsigned)aSegment
00336 {
00337 return _segments[aSegment].label;
00338 }
00339
00346 - (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
00347 {
00348 _segments[aSegment].menu = aMenu;
00349 }
00350
00356 - (CPMenu)menuForSegment:(unsigned)aSegment
00357 {
00358 return _segments[aSegment].menu;
00359 }
00360
00368 - (void)setSelected:(BOOL)isSelected forSegment:(unsigned)aSegment
00369 {
00370 var segment = _segments[aSegment];
00371
00372
00373 if (segment.selected == isSelected)
00374 return;
00375
00376 segment.selected = isSelected;
00377
00378
00379 if (isSelected)
00380 {
00381 var oldSelectedSegment = _selectedSegment;
00382
00383 _selectedSegment = aSegment;
00384
00385 if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1)
00386 {
00387 _segments[oldSelectedSegment].selected = NO;
00388
00389 [self drawSegmentBezel:oldSelectedSegment highlight:NO];
00390 }
00391 }
00392
00393 if (_trackingMode != CPSegmentSwitchTrackingMomentary)
00394 [self drawSegmentBezel:aSegment highlight:NO];
00395 }
00396
00402 - (BOOL)isSelectedForSegment:(unsigned)aSegment
00403 {
00404 return _segments[aSegment].selected;
00405 }
00406
00413 - (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
00414 {
00415 _segments[aSegment].enabled = isEnabled;
00416 }
00417
00423 - (BOOL)isEnabledForSegment:(unsigned)aSegment
00424 {
00425 return _segments[aSegment].enabled;
00426 }
00427
00433 - (void)setTag:(int)aTag forSegment:(unsigned)aSegment
00434 {
00435 _segments[aSegment].tag = aTag;
00436 }
00437
00442 - (int)tagForSegment:(unsigned)aSegment
00443 {
00444 return _segments[aSegment].tag;
00445 }
00446
00447
00453 - (void)drawSegmentBezel:(int)aSegment highlight:(BOOL)shouldHighlight
00454 {
00455 }
00456
00462 - (void)drawSegment:(int)aSegment highlight:(BOOL)shouldHighlight
00463 {
00464 var segment = _segments[aSegment],
00465
00466 imageView = segment.imageView,
00467 labelView = segment.labelView,
00468
00469 frame = segment.frame,
00470
00471 segmentX = CGRectGetMinX(frame),
00472 segmentWidth = CGRectGetWidth(frame),
00473 segmentHeight = CGRectGetHeight(frame) - 1.0;
00474
00475 if (imageView && labelView)
00476 {
00477 var imageViewSize = [imageView frame].size,
00478 labelViewSize = [labelView frame].size,
00479 totalHeight = imageViewSize.height + labelViewSize.height,
00480 labelWidth = MIN(labelViewSize.width, width),
00481 y = (segmentHeight - totalHeight) / 2.0;
00482
00483 [imageView setFrameOrigin:CGPointMake(segmentX + (segmentWidth - imageViewSize.width) / 2.0, y)];
00484
00485 if (labelWidth < labelViewSize.width)
00486 [labelView setFrameSize:CGSizeMake(labelWidth, labelViewSize.height)];
00487
00488 [labelView setFrameOrigin:CGPointMake(segmentX + (segmentWidth - labelWidth) / 2.0, y + imageViewSize.height)];
00489 }
00490 else if (imageView)
00491 {
00492 var imageViewSize = [imageView frame].size;
00493
00494 [imageView setFrameOrigin:CGPointMake(segmentX + (segmentWidth - imageViewSize.width) / 2.0, (segmentHeight - imageViewSize.height) / 2.0)];
00495 }
00496 else if (labelView)
00497 {
00498 var labelViewSize = [labelView frame].size,
00499 labelWidth = MIN(labelViewSize.width, segmentWidth);
00500
00501 if (labelWidth < labelViewSize.width)
00502 [labelView setFrameSize:CGSizeMake(labelWidth, labelViewSize.height)];
00503
00504 [labelView setFrameOrigin:CGPointMake(segmentX + (segmentWidth - labelWidth) / 2.0, (segmentHeight - labelViewSize.height) / 2.0)];
00505 }
00506 }
00507
00508 - (void)tileWithChangedSegment:(unsigned)aSegment
00509 {
00510 var segment = _segments[aSegment],
00511 segmentWidth = segment.width;
00512
00513 if (!segmentWidth)
00514 {
00515 if (segment.labelView && segment.imageView)
00516 segmentWidth = MAX(CGRectGetWidth([segment.labelView frame]) , CGRectGetWidth([segment.imageView frame]));
00517 else if (segment.labelView)
00518 segmentWidth = CGRectGetWidth([segment.labelView frame]);
00519 else if (segment.imageView)
00520 segmentWidth = CGRectGetWidth([segment.imageView frame]);
00521 }
00522
00523 var delta = segmentWidth - CGRectGetWidth(segment.frame);
00524
00525 if (!delta)
00526 return;
00527
00528
00529 var frame = [self frame];
00530
00531 [self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))];
00532
00533
00534 segment.frame.size.width = segmentWidth;
00535
00536
00537 var index = aSegment + 1;
00538
00539 for (; index < _segmentCount; ++index)
00540 {
00541 _segments[index].frame.origin.x += delta;
00542
00543 [self drawSegmentBezel:index highlight:NO];
00544 [self drawSegment:index highlight:NO];
00545 }
00546
00547 [self drawSegmentBezel:aSegment highlight:NO];
00548 [self drawSegment:aSegment highlight:NO];
00549 }
00550
00555 - (CGRect)frameForSegment:(unsigned)aSegment
00556 {
00557 return _segments[aSegment].frame;
00558 }
00559
00565 - (unsigned)testSegment:(CGPoint)aPoint
00566 {
00567 var location = [self convertPoint:aPoint fromView:nil],
00568 count = _segments.length;
00569
00570 while (count--)
00571 if (CGRectContainsPoint(_segments[count].frame, aPoint))
00572 return count;
00573
00574 return -1;
00575 }
00576
00577 - (void)mouseDown:(CPEvent)anEvent
00578 {
00579 if (![self isEnabled])
00580 return;
00581
00582 [self trackSegment:anEvent];
00583 }
00584
00585
00586 - (void)mouseUp:(CPEvent)anEvent
00587 {
00588 }
00589
00594 - (void)trackSegment:(CPEvent)anEvent
00595 {
00596 var type = [anEvent type],
00597 location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
00598
00599 if (type == CPLeftMouseUp)
00600 {
00601 if (CGRectContainsPoint(_segments[_trackingSegment].frame, location))
00602 {
00603 if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
00604 {
00605 [self setSelected:![self isSelectedForSegment:_trackingSegment] forSegment:_trackingSegment];
00606
00607
00608 _selectedSegment = _trackingSegment;
00609 }
00610 else
00611 [self setSelected:YES forSegment:_trackingSegment];
00612
00613 [self sendAction:[self action] to:[self target]];
00614
00615 if (_trackingMode == CPSegmentSwitchTrackingMomentary)
00616 {
00617 [self setSelected:NO forSegment:_trackingSegment];
00618
00619 _selectedSegment = -1;
00620 }
00621 }
00622
00623 [self drawSegmentBezel:_trackingSegment highlight:NO];
00624
00625 _trackingSegment = -1;
00626
00627 return;
00628 }
00629
00630 if (type == CPLeftMouseDown)
00631 {
00632 _trackingHighlighted = YES;
00633 _trackingSegment = [self testSegment:location];
00634
00635 [self drawSegmentBezel:_trackingSegment highlight:YES];
00636 }
00637
00638 else if (type == CPLeftMouseDragged)
00639 {
00640 var highlighted = CGRectContainsPoint(_segments[_trackingSegment].frame, location);
00641
00642 if (highlighted != _trackingHighlighted)
00643 {
00644 _trackingHighlighted = highlighted;
00645
00646 [self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
00647 }
00648 }
00649
00650 [CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
00651 }
00652
00653 - (void)setFont:(CPFont)aFont
00654 {
00655 [super setFont:aFont];
00656
00657 var count = _segmentCount;
00658
00659 if (!count)
00660 return;
00661
00662 while (count--)
00663 [_segments[count].labelView setFont:aFont];
00664
00665 [self tileWithChangedSegment:0];
00666 }
00667
00668 @end
00669
00670 var _CPSegmentMake = function()
00671 {
00672 return { width:0, image:nil, label:@"", menu:nil, selected:NO, enabled:NO, tag:0, labelView:nil, imageView:nil, frame:CGRectMakeZero() }
00673 }