summaryrefslogtreecommitdiff
path: root/frontends/cocoa/PSMTabBarControl/PSMTabBarCell.m
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/cocoa/PSMTabBarControl/PSMTabBarCell.m')
-rw-r--r--frontends/cocoa/PSMTabBarControl/PSMTabBarCell.m489
1 files changed, 489 insertions, 0 deletions
diff --git a/frontends/cocoa/PSMTabBarControl/PSMTabBarCell.m b/frontends/cocoa/PSMTabBarControl/PSMTabBarCell.m
new file mode 100644
index 000000000..f7a04f202
--- /dev/null
+++ b/frontends/cocoa/PSMTabBarControl/PSMTabBarCell.m
@@ -0,0 +1,489 @@
+//
+// PSMTabBarCell.m
+// PSMTabBarControl
+//
+// Created by John Pannell on 10/13/05.
+// Copyright 2005 Positive Spin Media. All rights reserved.
+//
+
+#import "PSMTabBarCell.h"
+#import "PSMTabBarControl.h"
+#import "PSMTabStyle.h"
+#import "PSMProgressIndicator.h"
+#import "PSMTabDragAssistant.h"
+
+@interface PSMTabBarControl (Private)
+- (void)update;
+@end
+
+@implementation PSMTabBarCell
+
+#pragma mark -
+#pragma mark Creation/Destruction
+- (id)initWithControlView:(PSMTabBarControl *)controlView {
+ if((self = [super init])) {
+ _controlView = controlView;
+ _closeButtonTrackingTag = 0;
+ _cellTrackingTag = 0;
+ _closeButtonOver = NO;
+ _closeButtonPressed = NO;
+ _indicator = [[PSMProgressIndicator alloc] initWithFrame:NSMakeRect(0.0, 0.0, kPSMTabBarIndicatorWidth, kPSMTabBarIndicatorWidth)];
+ [_indicator setStyle:NSProgressIndicatorSpinningStyle];
+ [_indicator setAutoresizingMask:NSViewMinYMargin];
+ _hasCloseButton = YES;
+ _isCloseButtonSuppressed = NO;
+ _count = 0;
+ _countColor = nil;
+ _isEdited = NO;
+ _isPlaceholder = NO;
+ }
+ return self;
+}
+
+- (id)initPlaceholderWithFrame:(NSRect)frame expanded:(BOOL)value inControlView:(PSMTabBarControl *)controlView {
+ if((self = [super init])) {
+ _controlView = controlView;
+ _isPlaceholder = YES;
+ if(!value) {
+ if([controlView orientation] == PSMTabBarHorizontalOrientation) {
+ frame.size.width = 0.0;
+ } else {
+ frame.size.height = 0.0;
+ }
+ }
+ [self setFrame:frame];
+ _closeButtonTrackingTag = 0;
+ _cellTrackingTag = 0;
+ _closeButtonOver = NO;
+ _closeButtonPressed = NO;
+ _indicator = nil;
+ _hasCloseButton = YES;
+ _isCloseButtonSuppressed = NO;
+ _count = 0;
+ _countColor = nil;
+ _isEdited = NO;
+
+ if(value) {
+ [self setCurrentStep:(kPSMTabDragAnimationSteps - 1)];
+ } else {
+ [self setCurrentStep:0];
+ }
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [_countColor release];
+
+ [_indicator removeFromSuperviewWithoutNeedingDisplay];
+
+ [_indicator release];
+ [super dealloc];
+}
+
+#pragma mark -
+#pragma mark Accessors
+
+- (id)controlView {
+ return _controlView;
+}
+
+- (void)setControlView:(id)view {
+ // no retain release pattern, as this simply switches a tab to another view.
+ _controlView = view;
+}
+
+- (NSTrackingRectTag)closeButtonTrackingTag {
+ return _closeButtonTrackingTag;
+}
+
+- (void)setCloseButtonTrackingTag:(NSTrackingRectTag)tag {
+ _closeButtonTrackingTag = tag;
+}
+
+- (NSTrackingRectTag)cellTrackingTag {
+ return _cellTrackingTag;
+}
+
+- (void)setCellTrackingTag:(NSTrackingRectTag)tag {
+ _cellTrackingTag = tag;
+}
+
+- (CGFloat)width {
+ return _frame.size.width;
+}
+
+- (NSRect)frame {
+ return _frame;
+}
+
+- (void)setFrame:(NSRect)rect {
+ _frame = rect;
+
+ //move the status indicator along with the rest of the cell
+ if(![[self indicator] isHidden] && ![_controlView isTabBarHidden]) {
+ [[self indicator] setFrame:[self indicatorRectForFrame:rect]];
+ }
+}
+
+- (void)setStringValue:(NSString *)aString {
+ [super setStringValue:aString];
+ _stringSize = [[self attributedStringValue] size];
+ // need to redisplay now - binding observation was too quick.
+ [_controlView update];
+}
+
+- (NSSize)stringSize {
+ return _stringSize;
+}
+
+- (NSAttributedString *)attributedStringValue {
+ return [(id < PSMTabStyle >)[_controlView style] attributedStringValueForTabCell:self];
+}
+
+- (NSInteger)tabState {
+ return _tabState;
+}
+
+- (void)setTabState:(NSInteger)state {
+ _tabState = state;
+}
+
+- (NSProgressIndicator *)indicator {
+ return _indicator;
+}
+
+- (BOOL)isInOverflowMenu {
+ return _isInOverflowMenu;
+}
+
+- (void)setIsInOverflowMenu:(BOOL)value {
+ if(_isInOverflowMenu != value) {
+ _isInOverflowMenu = value;
+ if([[[self controlView] delegate] respondsToSelector:@selector(tabView:tabViewItem:isInOverflowMenu:)]) {
+ [[[self controlView] delegate] tabView:[self controlView] tabViewItem:[self representedObject] isInOverflowMenu:_isInOverflowMenu];
+ }
+ }
+}
+
+- (BOOL)closeButtonPressed {
+ return _closeButtonPressed;
+}
+
+- (void)setCloseButtonPressed:(BOOL)value {
+ _closeButtonPressed = value;
+}
+
+- (BOOL)closeButtonOver {
+ return(_closeButtonOver && ([_controlView allowsBackgroundTabClosing] || ([self tabState] & PSMTab_SelectedMask) || [[NSApp currentEvent] modifierFlags] & NSCommandKeyMask));
+}
+
+- (void)setCloseButtonOver:(BOOL)value {
+ _closeButtonOver = value;
+}
+
+- (BOOL)hasCloseButton {
+ return _hasCloseButton;
+}
+
+- (void)setHasCloseButton:(BOOL)set;
+{
+ _hasCloseButton = set;
+}
+
+- (void)setCloseButtonSuppressed:(BOOL)suppress;
+{
+ _isCloseButtonSuppressed = suppress;
+}
+
+- (BOOL)isCloseButtonSuppressed;
+{
+ return _isCloseButtonSuppressed;
+}
+
+- (BOOL)hasIcon {
+ return _hasIcon;
+}
+
+- (void)setHasIcon:(BOOL)value {
+ _hasIcon = value;
+ //[_controlView update:[[self controlView] automaticallyAnimates]]; // binding notice is too fast
+}
+
+- (BOOL)hasLargeImage {
+ return _hasLargeImage;
+}
+
+- (void)setHasLargeImage:(BOOL)value {
+ _hasLargeImage = value;
+}
+
+
+- (NSInteger)count {
+ return _count;
+}
+
+- (void)setCount:(NSInteger)value {
+ _count = value;
+ //[_controlView update:[[self controlView] automaticallyAnimates]]; // binding notice is too fast
+}
+
+- (NSColor *)countColor {
+ return _countColor;
+}
+
+- (void)setCountColor:(NSColor *)color {
+ [_countColor release];
+ _countColor = [color retain];
+}
+
+- (BOOL)isPlaceholder {
+ return _isPlaceholder;
+}
+
+- (void)setIsPlaceholder:(BOOL)value;
+{
+ _isPlaceholder = value;
+}
+
+- (NSInteger)currentStep {
+ return _currentStep;
+}
+
+- (void)setCurrentStep:(NSInteger)value {
+ if(value < 0) {
+ value = 0;
+ }
+
+ if(value > (kPSMTabDragAnimationSteps - 1)) {
+ value = (kPSMTabDragAnimationSteps - 1);
+ }
+
+ _currentStep = value;
+}
+
+- (BOOL)isEdited {
+ return _isEdited;
+}
+
+- (void)setIsEdited:(BOOL)value {
+ _isEdited = value;
+ //[_controlView update:[[self controlView] automaticallyAnimates]]; // binding notice is too fast
+}
+
+#pragma mark -
+#pragma mark Bindings
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
+ // the progress indicator, label, icon, or count has changed - redraw the control view
+ //[_controlView update];
+ //I seem to have run into some odd issue with update not being called at the right time. This seems to avoid the problem.
+ [_controlView performSelector:@selector(update) withObject:nil afterDelay:0.0];
+}
+
+#pragma mark -
+#pragma mark Component Attributes
+
+- (NSRect)indicatorRectForFrame:(NSRect)cellFrame {
+ return [(id < PSMTabStyle >)[_controlView style] indicatorRectForTabCell:self];
+}
+
+- (NSRect)closeButtonRectForFrame:(NSRect)cellFrame {
+ return [(id < PSMTabStyle >)[_controlView style] closeButtonRectForTabCell:self withFrame:cellFrame];
+}
+
+- (CGFloat)minimumWidthOfCell {
+ return [(id < PSMTabStyle >)[_controlView style] minimumWidthOfTabCell:self];
+}
+
+- (CGFloat)desiredWidthOfCell {
+ return [(id < PSMTabStyle >)[_controlView style] desiredWidthOfTabCell:self];
+}
+
+#pragma mark -
+#pragma mark Drawing
+
+- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
+ if(_isPlaceholder) {
+ [[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set];
+ NSRectFillUsingOperation(cellFrame, NSCompositeSourceAtop);
+ return;
+ }
+
+ [(id < PSMTabStyle >)[_controlView style] drawTabCell:self];
+}
+
+#pragma mark -
+#pragma mark Tracking
+
+- (void)mouseEntered:(NSEvent *)theEvent {
+ // check for which tag
+ if([theEvent trackingNumber] == _closeButtonTrackingTag) {
+ _closeButtonOver = YES;
+ }
+ if([theEvent trackingNumber] == _cellTrackingTag) {
+ [self setHighlighted:YES];
+ [_controlView setNeedsDisplay:NO];
+ }
+
+ // scrubtastic
+ if([_controlView allowsScrubbing] && ([theEvent modifierFlags] & NSAlternateKeyMask)) {
+ [_controlView performSelector:@selector(tabClick:) withObject:self];
+ }
+
+ // tell the control we only need to redraw the affected tab
+ [_controlView setNeedsDisplayInRect:NSInsetRect([self frame], -2, -2)];
+}
+
+- (void)mouseExited:(NSEvent *)theEvent {
+ // check for which tag
+ if([theEvent trackingNumber] == _closeButtonTrackingTag) {
+ _closeButtonOver = NO;
+ }
+
+ if([theEvent trackingNumber] == _cellTrackingTag) {
+ [self setHighlighted:NO];
+ [_controlView setNeedsDisplay:NO];
+ }
+
+ //tell the control we only need to redraw the affected tab
+ [_controlView setNeedsDisplayInRect:NSInsetRect([self frame], -2, -2)];
+}
+
+#pragma mark -
+#pragma mark Drag Support
+
+- (NSImage *)dragImage {
+ NSRect cellFrame = [(id < PSMTabStyle >)[(PSMTabBarControl *)_controlView style] dragRectForTabCell:self orientation:(PSMTabBarOrientation)[(PSMTabBarControl *)_controlView orientation]];
+ //NSRect cellFrame = [self frame];
+
+ [_controlView lockFocus];
+ NSBitmapImageRep *rep = [[[NSBitmapImageRep alloc] initWithFocusedViewRect:cellFrame] autorelease];
+ [_controlView unlockFocus];
+ NSImage *image = [[[NSImage alloc] initWithSize:[rep size]] autorelease];
+ [image addRepresentation:rep];
+ NSImage *returnImage = [[[NSImage alloc] initWithSize:[rep size]] autorelease];
+ [returnImage lockFocus];
+ [image compositeToPoint:NSMakePoint(0.0, 0.0) operation:NSCompositeSourceOver fraction:1.0];
+ [returnImage unlockFocus];
+ if(![[self indicator] isHidden]) {
+ NSImage *pi = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"pi"]];
+ [returnImage lockFocus];
+ NSPoint indicatorPoint = NSMakePoint([self frame].size.width - MARGIN_X - kPSMTabBarIndicatorWidth, MARGIN_Y);
+ [pi compositeToPoint:indicatorPoint operation:NSCompositeSourceOver fraction:1.0];
+ [returnImage unlockFocus];
+ [pi release];
+ }
+ return returnImage;
+}
+
+#pragma mark -
+#pragma mark Archiving
+
+- (void)encodeWithCoder:(NSCoder *)aCoder {
+ [super encodeWithCoder:aCoder];
+ if([aCoder allowsKeyedCoding]) {
+ [aCoder encodeRect:_frame forKey:@"frame"];
+ [aCoder encodeSize:_stringSize forKey:@"stringSize"];
+ [aCoder encodeInteger:_currentStep forKey:@"currentStep"];
+ [aCoder encodeBool:_isPlaceholder forKey:@"isPlaceholder"];
+ [aCoder encodeInteger:_tabState forKey:@"tabState"];
+ [aCoder encodeInteger:_closeButtonTrackingTag forKey:@"closeButtonTrackingTag"];
+ [aCoder encodeInteger:_cellTrackingTag forKey:@"cellTrackingTag"];
+ [aCoder encodeBool:_closeButtonOver forKey:@"closeButtonOver"];
+ [aCoder encodeBool:_closeButtonPressed forKey:@"closeButtonPressed"];
+ [aCoder encodeObject:_indicator forKey:@"indicator"];
+ [aCoder encodeBool:_isInOverflowMenu forKey:@"isInOverflowMenu"];
+ [aCoder encodeBool:_hasCloseButton forKey:@"hasCloseButton"];
+ [aCoder encodeBool:_isCloseButtonSuppressed forKey:@"isCloseButtonSuppressed"];
+ [aCoder encodeBool:_hasIcon forKey:@"hasIcon"];
+ [aCoder encodeBool:_hasLargeImage forKey:@"hasLargeImage"];
+ [aCoder encodeInteger:_count forKey:@"count"];
+ [aCoder encodeBool:_isEdited forKey:@"isEdited"];
+ }
+}
+
+- (id)initWithCoder:(NSCoder *)aDecoder {
+ self = [super initWithCoder:aDecoder];
+ if(self) {
+ if([aDecoder allowsKeyedCoding]) {
+ _frame = [aDecoder decodeRectForKey:@"frame"];
+ _stringSize = [aDecoder decodeSizeForKey:@"stringSize"];
+ _currentStep = [aDecoder decodeIntegerForKey:@"currentStep"];
+ _isPlaceholder = [aDecoder decodeBoolForKey:@"isPlaceholder"];
+ _tabState = [aDecoder decodeIntegerForKey:@"tabState"];
+ _closeButtonTrackingTag = [aDecoder decodeIntegerForKey:@"closeButtonTrackingTag"];
+ _cellTrackingTag = [aDecoder decodeIntegerForKey:@"cellTrackingTag"];
+ _closeButtonOver = [aDecoder decodeBoolForKey:@"closeButtonOver"];
+ _closeButtonPressed = [aDecoder decodeBoolForKey:@"closeButtonPressed"];
+ _indicator = [[aDecoder decodeObjectForKey:@"indicator"] retain];
+ _isInOverflowMenu = [aDecoder decodeBoolForKey:@"isInOverflowMenu"];
+ _hasCloseButton = [aDecoder decodeBoolForKey:@"hasCloseButton"];
+ _isCloseButtonSuppressed = [aDecoder decodeBoolForKey:@"isCloseButtonSuppressed"];
+ _hasIcon = [aDecoder decodeBoolForKey:@"hasIcon"];
+ _hasLargeImage = [aDecoder decodeBoolForKey:@"hasLargeImage"];
+ _count = [aDecoder decodeIntegerForKey:@"count"];
+ _isEdited = [aDecoder decodeBoolForKey:@"isEdited"];
+ }
+ }
+ return self;
+}
+
+#pragma mark -
+#pragma mark Accessibility
+
+-(BOOL)accessibilityIsIgnored {
+ return NO;
+}
+
+- (id)accessibilityAttributeValue:(NSString *)attribute {
+ id attributeValue = nil;
+
+ if([attribute isEqualToString: NSAccessibilityRoleAttribute]) {
+ attributeValue = NSAccessibilityButtonRole;
+ } else if([attribute isEqualToString: NSAccessibilityHelpAttribute]) {
+ if([[[self controlView] delegate] respondsToSelector:@selector(accessibilityStringForTabView:objectCount:)]) {
+ attributeValue = [NSString stringWithFormat:@"%@, %lu %@", [self stringValue],
+ (unsigned long)[self count],
+ [[[self controlView] delegate] accessibilityStringForTabView:[[self controlView] tabView] objectCount:[self count]]];
+ } else {
+ attributeValue = [self stringValue];
+ }
+ } else if([attribute isEqualToString: NSAccessibilityFocusedAttribute]) {
+ attributeValue = [NSNumber numberWithBool:([self tabState] == 2)];
+ } else {
+ attributeValue = [super accessibilityAttributeValue:attribute];
+ }
+
+ return attributeValue;
+}
+
+- (NSArray *)accessibilityActionNames {
+ static NSArray *actions;
+
+ if(!actions) {
+ actions = [[NSArray alloc] initWithObjects:NSAccessibilityPressAction, nil];
+ }
+ return actions;
+}
+
+- (NSString *)accessibilityActionDescription:(NSString *)action {
+ return NSAccessibilityActionDescription(action);
+}
+
+- (void)accessibilityPerformAction:(NSString *)action {
+ if([action isEqualToString:NSAccessibilityPressAction]) {
+ // this tab was selected
+ [_controlView performSelector:@selector(tabClick:) withObject:self];
+ }
+}
+
+- (id)accessibilityHitTest:(NSPoint)point {
+ return NSAccessibilityUnignoredAncestor(self);
+}
+
+- (id)accessibilityFocusedUIElement:(NSPoint)point {
+ return NSAccessibilityUnignoredAncestor(self);
+}
+
+@end