mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-11-28 09:13:08 +03:00
f85335a7f9
svn path=/trunk/netsurf/; revision=11396
536 lines
14 KiB
Objective-C
536 lines
14 KiB
Objective-C
//
|
|
// 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
|