00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import "CPButton.j"
00024 @import "CPGeometry.j"
00025 @import "CPMenu.j"
00026 @import "CPMenuItem.j"
00027
00028
00029 var VISIBLE_MARGIN = 7.0;
00030
00031 var CPPopUpButtonArrowsImage = nil;
00032
00037 @implementation CPPopUpButton : CPButton
00038 {
00039 BOOL _pullsDown;
00040 int _selectedIndex;
00041 CPRectEdge _preferredEdge;
00042
00043 CPImageView _arrowsView;
00044
00045 CPMenu _menu;
00046 }
00047
00054 - (id)initWithFrame:(CGRect)aFrame pullsDown:(BOOL)shouldPullDown
00055 {
00056 self = [super initWithFrame:aFrame];
00057
00058 if (self)
00059 {
00060 _pullsDown = shouldPullDown;
00061 _selectedIndex = CPNotFound;
00062 _preferredEdge = CPMaxYEdge;
00063
00064 [self setBezelStyle:CPTexturedRoundedBezelStyle];
00065
00066 [self setImagePosition:CPImageLeft];
00067 [self setAlignment:CPLeftTextAlignment];
00068
00069 [self setMenu:[[CPMenu alloc] initWithTitle:@""]];
00070 }
00071
00072 return self;
00073 }
00074
00075 - (id)initWithFrame:(CGRect)aFrame
00076 {
00077 return [self initWithFrame:aFrame pullsDown:NO];
00078 }
00079
00080 - (void)setBordered:(BOOL)shouldBeBordered
00081 {
00082 if (shouldBeBordered)
00083 {
00084 var bounds = [self bounds];
00085
00086 _arrowsView = [[CPImageView alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds) - 10.0, (CGRectGetHeight(bounds) - 8.0) / 2.0, 5.0, 8.0)];
00087
00088 if (!CPPopUpButtonArrowsImage)
00089 CPPopUpButtonArrowsImage = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPPopUpButton class]] pathForResource:@"CPPopUpButton/CPPopUpButtonArrows.png"] size:CGSizeMake(5.0, 8.0)];
00090
00091 [_arrowsView setImage:CPPopUpButtonArrowsImage];
00092 [_arrowsView setAutoresizingMask:CPViewMaxXMargin | CPViewMinYMargin | CPViewMaxYMargin];
00093
00094
00095 [self addSubview:_arrowsView];
00096 }
00097 else
00098 {
00099 [_arrowsView removeFromSuperview];
00100
00101 _arrowsView = nil;
00102 }
00103
00104 [super setBordered:shouldBeBordered];
00105 }
00106
00107
00108
00114 - (void)setPullsDown:(BOOL)shouldPullDown
00115 {
00116 if (_pullsDown == shouldPullDown)
00117 return;
00118
00119 _pullsDown = shouldPullDown;
00120
00121 var items = [_menu itemArray];
00122
00123 if (items.length <= 0)
00124 return;
00125
00126 [items[0] setHidden:_pullsDown];
00127
00128 [self synchronizeTitleAndSelectedItem];
00129 }
00130
00134 - (BOOL)pullsDown
00135 {
00136 return _pullsDown;
00137 }
00138
00139
00144 - (void)addItemWithTitle:(CPString)aTitle
00145 {
00146 [_menu addItemWithTitle:aTitle action:NULL keyEquivalent:NULL];
00147 }
00148
00153 - (void)addItemsWithTitles:(CPArray)titles
00154 {
00155 var index = 0,
00156 count = [titles count];
00157
00158 for (; index < count; ++index)
00159 [self addItemWithTitle:titles[index]];
00160 }
00161
00167 - (void)insertItemWithTitle:(CPString)aTitle atIndex:(int)anIndex
00168 {
00169 var items = [self itemArray],
00170 count = [items count];
00171
00172 while (count--)
00173 if ([items[count] title] == aTitle)
00174 [self removeItemAtIndex:count];
00175
00176 [_menu insertItemWithTitle:aTitle action:NULL keyEquivalent:NULL atIndex:anIndex];
00177 }
00178
00182 - (void)removeAllItems
00183 {
00184 var count = [_menu numberOfItems];
00185
00186 while (count--)
00187 [_menu removeItemAtIndex:0];
00188 }
00189
00194 - (void)removeItemWithTitle:(CPString)aTitle
00195 {
00196 [self removeItemAtIndex:[self indexOfItemWithTitle:aTitle]];
00197 [self synchronizeTitleAndSelectedItem];
00198 }
00199
00204 - (void)removeItemAtIndex:(int)anIndex
00205 {
00206 [_menu removeItemAtIndex:anIndex];
00207 [self synchronizeTitleAndSelectedItem];
00208 }
00209
00210
00214 - (CPMenuItem)selectedItem
00215 {
00216 if (_selectedIndex < 0)
00217 return nil;
00218
00219 return [_menu itemAtIndex:_selectedIndex];
00220 }
00221
00225 - (CPString)titleOfSelectedItem
00226 {
00227 return [[self selectedItem] title];
00228 }
00229
00233 - (int)indexOfSelectedItem
00234 {
00235 return _selectedIndex;
00236 }
00237
00238
00242 - (id)objectValue
00243 {
00244 return _selectedIndex;
00245 }
00246
00247
00252 - (void)selectItem:(CPMenuItem)aMenuItem
00253 {
00254 [self selectItemAtIndex:[self indexOfItem:aMenuItem]];
00255 }
00256
00261 - (void)selectItemAtIndex:(int)anIndex
00262 {
00263 if (_selectedIndex == anIndex)
00264 return;
00265
00266 if (_selectedIndex >= 0 && !_pullsDown)
00267 [[self selectedItem] setState:CPOffState];
00268
00269 _selectedIndex = anIndex;
00270
00271 if (_selectedIndex >= 0 && !_pullsDown)
00272 [[self selectedItem] setState:CPOnState];
00273
00274 [self synchronizeTitleAndSelectedItem];
00275 }
00276
00281 - (void)selectItemWithTag:(int)aTag
00282 {
00283 [self selectItemAtIndex:[self indexOfItemWithTag:aTag]];
00284 }
00285
00290 - (void)selectItemWithTitle:(CPString)aTitle
00291 {
00292 [self selectItemAtIndex:[self indexOfItemWithTitle:aTitle]];
00293 }
00294
00299 - (void)setObjectValue:(id)aValue
00300 {
00301 [self selectItemAtIndex:[aValue intValue]];
00302 }
00303
00304
00308 - (CPMenu)menu
00309 {
00310 return _menu;
00311 }
00312
00316 - (void)setMenu:(CPMenu)aMenu
00317 {
00318 if (_menu == aMenu)
00319 return;
00320
00321 var defaultCenter = [CPNotificationCenter defaultCenter];
00322
00323 if (_menu)
00324 {
00325 [defaultCenter
00326 removeObserver:self
00327 name:CPMenuDidAddItemNotification
00328 object:_menu];
00329
00330 [defaultCenter
00331 removeObserver:self
00332 name:CPMenuDidChangeItemNotification
00333 object:_menu];
00334
00335 [defaultCenter
00336 removeObserver:self
00337 name:CPMenuDidRemoveItemNotification
00338 object:_menu];
00339 }
00340
00341 _menu = aMenu;
00342
00343 if (_menu)
00344 {
00345 [defaultCenter
00346 addObserver:self
00347 selector:@selector(menuDidAddItem:)
00348 name:CPMenuDidAddItemNotification
00349 object:_menu];
00350
00351 [defaultCenter
00352 addObserver:self
00353 selector:@selector(menuDidChangeItem:)
00354 name:CPMenuDidChangeItemNotification
00355 object:_menu];
00356
00357 [defaultCenter
00358 addObserver:self
00359 selector:@selector(menuDidRemoveItem:)
00360 name:CPMenuDidRemoveItemNotification
00361 object:_menu];
00362 }
00363
00364 [self synchronizeTitleAndSelectedItem];
00365 }
00366
00370 - (int)numberOfItems
00371 {
00372 return [_menu numberOfItems];
00373 }
00374
00378 - (CPArray)itemArray
00379 {
00380 return [_menu itemArray];
00381 }
00382
00387 - (CPMenuItem)itemAtIndex:(unsigned)anIndex
00388 {
00389 return [_menu itemAtIndex:anIndex];
00390 }
00391
00396 - (CPString)itemTitleAtIndex:(unsigned)anIndex
00397 {
00398 return [[_menu itemAtIndex:anIndex] title];
00399 }
00400
00404 - (CPArray)itemTitles
00405 {
00406 var titles = [],
00407 items = [self itemArray],
00408
00409 index = 0,
00410 count = [items count];
00411
00412 for (; index < count; ++index)
00413 items.push([items[index] title]);
00414 }
00415
00420 - (CPMenuItem)itemWithTitle:(CPString)aTitle
00421 {
00422 return [_menu itemAtIndex:[_menu indexOfItemWithTitle:aTitle]];
00423 }
00424
00428 - (CPMenuItem)lastItem
00429 {
00430 return [[_menu itemArray] lastObject];
00431 }
00432
00433
00438 - (int)indexOfItem:(CPMenuItem)aMenuItem
00439 {
00440 return [_menu indexOfItem:aMenuItem];
00441 }
00442
00447 - (int)indexOfItemWithTag:(int)aTag
00448 {
00449 return [_menu indexOfItemWithTag:aMenuItem];
00450 }
00451
00456 - (int)indexOfItemWithTitle:(CPString)aTitle
00457 {
00458 return [_menu indexOfItemWithTitle:aTitle];
00459 }
00460
00467 - (int)indexOfItemWithRepresentedObject:(id)anObject
00468 {
00469 return [_menu indexOfItemWithRepresentedObejct:anObject];
00470 }
00471
00479 - (int)indexOfItemWithTarget:(id)aTarget action:(SEL)anAction
00480 {
00481 return [_menu indexOfItemWithTarget:aTarget action:anAction];
00482 }
00483
00484
00490 - (CPRectEdge)preferredEdge
00491 {
00492 return _preferredEdge;
00493 }
00494
00500 - (void)setPreferredEdge:(CPRectEdge)aRectEdge
00501 {
00502 _preferredEdge = aRectEdge;
00503 }
00504
00505
00510 - (void)setTitle:(CPString)aTitle
00511 {
00512 if ([self title] == aTitle)
00513 return;
00514
00515 if (_pullsDown)
00516 {
00517 [_items[0] setTitle:aTitle];
00518 [self synchronizeTitleAndSelectedItem];
00519 }
00520 else
00521 {
00522 var index = [self indexOfItemWithTitle:aTitle];
00523
00524 if (index < 0)
00525 {
00526 [self addItemWithTitle:aTitle];
00527
00528 index = [self numberOfItems] - 1;
00529 }
00530
00531 [self selectItemAtIndex:index];
00532 }
00533 }
00534
00535
00541 - (void)setImage:(CPImage)anImage
00542 {
00543
00544 }
00545
00546
00551 - (void)synchronizeTitleAndSelectedItem
00552 {
00553 var item = nil;
00554
00555 if (_pullsDown)
00556 {
00557 var items = [_menu itemArray];
00558
00559 if (items.length > 0)
00560 item = items[0];
00561 }
00562 else
00563 item = [self selectedItem];
00564
00565 [super setImage:[item image]];
00566 [super setTitle:[item title]];
00567 }
00568
00569
00574 - (void)menuDidAddItem:(CPNotification)aNotification
00575 {
00576 var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"];
00577
00578 if (_selectedIndex < 0)
00579 [self selectItemAtIndex:0];
00580
00581 else if (index == _selectedIndex)
00582 [self synchronizeTitleAndSelectedItem];
00583
00584 else if (index < _selectedIndex)
00585 ++_selectedIndex;
00586
00587 if (index == 0 && _pullsDown)
00588 {
00589 var items = [_menu itemArray];
00590
00591 [items[0] setHidden:YES];
00592
00593 if (items.length > 0)
00594 [items[1] setHidden:NO];
00595 }
00596 }
00597
00602 - (void)menuDidChangeItem:(CPNotification)aNotification
00603 {
00604 var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"];
00605
00606 if (_pullsDown && index != 0)
00607 return;
00608
00609 if (!_pullsDown && index != _selectedIndex)
00610 return;
00611
00612 [self synchronizeTitleAndSelectedItem];
00613 }
00614
00619 - (void)menuDidRemoveItem:(CPNotification)aNotification
00620 {
00621 var numberOfItems = [self numberOfItems];
00622
00623 if (numberOfItems <= _selectedIndex)
00624 [self selectItemAtIndex:numberOfItems - 1];
00625 }
00626
00627 - (void)mouseDown:(CPEvent)anEvent
00628 {
00629 if (![self isEnabled])
00630 return;
00631
00632 [self highlight:YES];
00633
00634 var theWindow = [self window],
00635 menuWindow = [_CPMenuWindow menuWindowWithMenu:[self menu] font:[self font]];
00636
00637 [menuWindow setDelegate:self];
00638 [menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
00639
00640 var menuOrigin = [theWindow convertBaseToBridge:[self convertPoint:CGPointMakeZero() toView:nil]];
00641
00642
00643 if (_pullsDown)
00644 menuOrigin.y += CGRectGetHeight([self frame]);
00645
00646
00647 else
00648 {
00649 var contentRect = [menuWindow rectForItemAtIndex:_selectedIndex];
00650
00651 menuOrigin.x -= CGRectGetMinX(contentRect) + [_CPMenuItemView leftMargin];
00652 menuOrigin.y -= CGRectGetMinY(contentRect);
00653 }
00654
00655 [menuWindow setFrameOrigin:menuOrigin];
00656
00657 var menuMaxX = CGRectGetMaxX([menuWindow frame]),
00658 buttonMaxX = CGRectGetMaxX([self convertRect:[self bounds] toView:nil]);
00659
00660 if (menuMaxX < buttonMaxX)
00661 [menuWindow setMinWidth:CGRectGetWidth([menuWindow frame]) + buttonMaxX - menuMaxX - VISIBLE_MARGIN];
00662
00663 [menuWindow orderFront:self];
00664 [menuWindow beginTrackingWithEvent:anEvent sessionDelegate:self didEndSelector:@selector(menuWindowDidFinishTracking:highlightedItem:)];
00665 }
00666
00667
00668
00669
00670 - (void)menuWindowDidFinishTracking:(_CPMenuWindow)aMenuWindow highlightedItem:(CPMenuItem)aMenuItem
00671 {
00672 [_CPMenuWindow poolMenuWindow:aMenuWindow];
00673
00674 [self highlight:NO];
00675
00676 var index = [_menu indexOfItem:aMenuItem];
00677
00678 if (index == CPNotFound)
00679 return;
00680
00681 [self selectItemAtIndex:index];
00682
00683 var selectedItem = [self selectedItem],
00684 target = nil,
00685 action = [selectedItem action];
00686
00687 if (!action)
00688 {
00689 target = [self target];
00690 action = [self action];
00691 }
00692
00693
00694 else
00695 target = [selectedItem target];
00696
00697 [self sendAction:action to:target];
00698 }
00699
00700 @end
00701
00702 var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
00703 CPPopUpButtonSelectedIndexKey = @"CPPopUpButtonSelectedIndexKey",
00704 CPPopUpButtonPullsDownKey = @"CPPopUpButtonPullsDownKey";
00705
00706 @implementation CPPopUpButton (CPCoding)
00714 - (id)initWithCoder:(CPCoder)aCoder
00715 {
00716 self = [super initWithCoder:aCoder];
00717
00718 if (self)
00719 {
00720 [self setMenu:[aCoder decodeObjectForKey:CPPopUpButtonMenuKey]];
00721 [self selectItemAtIndex:[aCoder decodeObjectForKey:CPPopUpButtonSelectedIndexKey]];
00722 [self setPullsDown:[aCoder decodeBoolForKey:CPPopUpButtonPullsDownKey]];
00723 }
00724
00725 return self;
00726 }
00727
00733 - (void)encodeWithCoder:(CPCoder)aCoder
00734 {
00735 [super encodeWithCoder:aCoder];
00736
00737 [aCoder encodeObject:_menu forKey:CPPopUpButtonMenuKey];
00738 [aCoder encodeInt:_selectedIndex forKey:CPPopUpButtonSelectedIndexKey];
00739 [aCoder encodeBool:_pullsDown forKey:CPPopUpButtonPullsDownKey];
00740 }
00741
00742 @end