This is MiscSwitchView.m in view mode; [Download] [Up]
// Suppress compiler warning about rcsid being unused, yet prevent assembler
// code for this function from being produced.
inline extern const char *suppressCompilerWarning(void)
{
static const char *rcsid = "$Id$ cc: "__FILE__" "__DATE__" "__TIME__;
return rcsid;
}
//
// ------------------ MiscSwitchView Class Implementation ---------------------
//
// Yet another view that supports a switchable subview. Features a selection
// of border styles including a border suitable for using the MiscTabCell to
// create a file folder interface. Supports various alignments of the
// switchable subview within MiscSwitchView's frame.
//
// Written by Art Isbell (inspired by TTools' SwitchView and UHSelectView).
// Copyright 1996 by Art Isbell.
// Version 1.0. All rights reserved.
//
// This notice may not be removed from this source code.
//
// This object is included in the MiscKit by permission from the author
// and its use is governed by the MiscKit license, found in the file
// "License.rtf" in the MiscKit distribution. Please refer to that file
// for a list of all applicable permissions and restrictions.
//
// ----------------------------------------------------------------------------
//
// ----------------------------- Header Files ---------------------------------
#import <AppKit/AppKit.h>
#ifndef NOMISC
#import <misckit/MiscSwitchView.h>
#else NOMISC
#import "MiscSwitchView.h"
#endif NOMISC
// ---------------- Typedef, Struct, and Union Declarations -------------------
// --------------------- Constant and Enum Definitions ------------------------
int MiscNoView = -1;
NSString *MiscViewWillSwitchNotification = @"MiscViewWillSwitch";
NSString *MiscViewDidSwitchNotification = @"MiscViewDidSwitch";
NSString *MiscNextViewNumberKey = @"MiscNextViewNumber";
static const unsigned MiscCurrentVersion = 2;
static const MiscPosition MiscDefaultPosition = MiscCenter;
static const MiscBorderType MiscDefaultBorderType = MiscTab;
// ------------------------- Function Declarations ----------------------------
@interface MiscSwitchView(Private)
// ---------------------- Private Method Declarations -------------------------
- (void)_positionView;
@end
@implementation MiscSwitchView
// ---------------------- Factory Method Definitions --------------------------
+ (void)initialize
{
[self setVersion:MiscCurrentVersion];
}
// ---------------- Overridden Instance Method Definitions --------------------
- (id)initWithFrame:(NSRect)frameRect
{
self = [super initWithFrame:frameRect];
if (self != nil)
{
_position = MiscDefaultPosition;
_borderType = MiscDefaultBorderType;
_viewNumber = MiscNoView;
_useMatrixBehavior = NO;
_views = [[NSMutableArray allocWithZone:[self zone]] init];
[self setAutoresizesSubviews:YES];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self != nil)
{
_viewNumber = MiscNoView;
if ([aDecoder versionForClassName:NSStringFromClass([self class])] ==
MiscCurrentVersion)
{
[aDecoder decodeValuesOfObjCTypes:"iiC", &_position, &_borderType,
&_useMatrixBehavior];
}
else
{
// If viewNumber were merely unarchived, setViewNumber: wouldn't
// set the view because it does nothing when its argument is
// identical to viewNumber which it would be in this case.
int unarchivedViewNumberL;
[aDecoder decodeValuesOfObjCTypes:"iii", &_position, &_borderType,
&unarchivedViewNumberL];
[self setViewNumber:unarchivedViewNumberL];
}
_views = [[aDecoder decodeObject] retain];
[self setAutoresizesSubviews:YES];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeValuesOfObjCTypes:"iiC", &_position, &_borderType,
&_useMatrixBehavior];
[aCoder encodeObject:_views];
}
- (void)dealloc
{
if (delegate != nil)
{
[[NSNotificationCenter defaultCenter] removeObserver:delegate
name:nil object:self];
}
[_views release];
[super dealloc];
}
- (void)drawRect:(NSRect)aRect
{
// Here we only draw peripheral stuff. The selected view will be
// displayed as a subview.
[[NSColor controlColor] set];
NSRectFill(aRect);
if (_borderType != MiscNone)
{
NSRect boundsL = [self bounds];
NSRect insideBorderRectL = NSInsetRect(boundsL, 2.0, 2.0);
// Redraw border only if aRect extends into the border.
if (!NSContainsRect(insideBorderRectL, aRect))
{
switch (_borderType)
{
case MiscTab:
{
NSRectEdge sidesL[] = {NSMinXEdge, NSMinYEdge, NSMaxXEdge,
NSMaxXEdge, NSMinYEdge};
float graysL[] = {NSWhite, NSBlack, NSBlack, NSDarkGray,
NSDarkGray};
NSDrawTiledRects(boundsL , boundsL , sidesL, graysL, 5);
break;
}
// If an unsupported borderType is specified, default to
// MiscNone.
case MiscNone:
default:
break;
case MiscLine:
[[NSColor blackColor] set];
NSFrameRect(boundsL);
break;
case MiscBezel:
NSDrawGrayBezel(boundsL, boundsL);
break;
case MiscGroove:
NSDrawGroove(boundsL, boundsL);
break;
case MiscButton:
NSDrawButton(boundsL, boundsL);
break;
}
}
}
}
// -------------------- New Instance Method Definitions -----------------------
- (void)setBorderType:(MiscBorderType)aType
{
// MiscNone <= aType is always true because MiscBorderType is an unsigned
// type and MiscNone == 0.
if (aType <= MiscTab)
{
_borderType = aType;
}
else
{
_borderType = MiscDefaultBorderType;
}
[self setNeedsDisplay:YES];
}
- (MiscBorderType)borderType
{
return _borderType;
}
- (void)setDelegate:(id)aDelegate
{
SEL delegateSelectorL;
NSNotificationCenter *defaultCenterL = [NSNotificationCenter
defaultCenter];
if (delegate != nil)
{
[defaultCenterL removeObserver:delegate name:nil object:self];
}
delegate = aDelegate;
delegateSelectorL = @selector(viewWillSwitch:);
if ([delegate respondsToSelector:delegateSelectorL])
{
[defaultCenterL addObserver:delegate selector:delegateSelectorL
name:MiscViewWillSwitchNotification
object:self];
}
delegateSelectorL = @selector(viewDidSwitch:);
if ([delegate respondsToSelector:delegateSelectorL])
{
[defaultCenterL addObserver:delegate selector:delegateSelectorL
name:MiscViewDidSwitchNotification object:self];
}
}
- (void)setPosition:(MiscPosition)aPosition
{
// MiscTopLeft <= aPosition is always true because MiscPosition is an
// unsigned type and MiscTopLeft == 0.
if (aPosition <= MiscBottomRight)
{
_position = aPosition;
}
else
{
_position = MiscDefaultPosition;
}
}
- (MiscPosition)position
{
return _position;
}
- (void)setUseMatrixBehavior:(BOOL)aFlag
{
_useMatrixBehavior = aFlag;
}
- (BOOL)useMatrixBehavior
{
return _useMatrixBehavior;
}
- (void)setViewNumber:(int)aViewNumber
{
unsigned viewCountL = [_views count];
if (0 < viewCountL)
{
if ((0 <= aViewNumber) && (aViewNumber < viewCountL))
{
// If the viewNumber was changed, switch the new view.
if (aViewNumber != _viewNumber)
{
NSView *viewL;
NSNotificationCenter *notificationCenterL =
[NSNotificationCenter defaultCenter];
[notificationCenterL
postNotificationName:MiscViewWillSwitchNotification
object:self userInfo:[NSDictionary
dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:aViewNumber],
MiscNextViewNumberKey,
nil]];
// This assumes that viewNumber, if not MiscNoView, must be
// within range of views indices.
if (_viewNumber != MiscNoView)
{
// Return current view to its original superview.
viewL = [_views objectAtIndex:_viewNumber];
[viewL removeFromSuperview];
[_originalSuperview addSubview:viewL];
[viewL setFrame:_originalFrame];
}
_viewNumber = aViewNumber;
viewL = [_views objectAtIndex:_viewNumber];
_originalSuperview = [viewL superview];
_originalFrame = [viewL frame];
[viewL removeFromSuperview];
[self addSubview:viewL];
[self _positionView];
[notificationCenterL
postNotificationName:MiscViewDidSwitchNotification
object:self];
}
}
else
{
NSLog(@"View number, %d, is outside of range of available view numbers, 0 - %d",
aViewNumber, viewCountL - 1);
}
}
else
{
NSLog(@"No switchable views exist");
}
}
- (int)viewNumber
{
return _viewNumber;
}
- (NSArray *)views
{
return _views;
}
- (void)takeViewNumberFrom:(id)aSender
{
int newViewNumberL;
if (aSender != nil)
{
SEL valueSelectorL = [self valueSelectorForSwitchSource:aSender];
if (valueSelectorL != (SEL)NULL)
{
newViewNumberL = (int)[aSender performSelector:valueSelectorL];
}
else
{
newViewNumberL = MiscNoView;
}
}
else
{
newViewNumberL = MiscNoView;
}
[self setViewNumber:newViewNumberL];
}
- (void)takeTagFrom:(id)aSender
{
[self setViewNumber:[aSender tag]];
}
- (void)takeIntValueFrom:(id)aSender
{
[self setViewNumber:[aSender intValue]];
}
- (void)takeSelectedRowFrom:(id)aSender
{
[self setViewNumber:[aSender selectedRow]];
}
- (void)takeSelectedColumnFrom:(id)aSender
{
[self setViewNumber:[aSender selectedColumn]];
}
- (unsigned)count
{
return [_views count];
}
- (NSView *)currentView
{
if (_viewNumber != MiscNoView)
{
return [_views objectAtIndex:_viewNumber];
}
else
{
return nil;
}
}
- (NSView *)viewAtIndex:(unsigned)anIndex
{
if (anIndex < [_views count])
{
return [_views objectAtIndex:anIndex];
}
else
{
return nil;
}
}
- (unsigned)indexOfView:(NSView *)aView
{
return [_views indexOfObjectIdenticalTo:aView];
}
- (void)addView:(NSView *)aView
{
if ((aView != nil) &&
([_views indexOfObjectIdenticalTo:aView] == NSNotFound))
{
[_views addObject:aView];
if (_viewNumber == MiscNoView)
{
_viewNumber = 0;
}
}
}
- (void)addView:(NSView *)aView atIndex:(unsigned)anIndex
{
if ((aView != nil) &&
([_views indexOfObjectIdenticalTo:aView] == NSNotFound))
{
if (anIndex < [_views count])
{
[_views insertObject:aView atIndex:anIndex];
}
else
{
[_views addObject:aView];
}
if (_viewNumber == MiscNoView)
{
_viewNumber = 0;
}
}
}
- (void)removeView:(NSView *)aView
{
[_views removeObjectIdenticalTo:aView];
if ([_views count] == 0)
{
_viewNumber = MiscNoView;
}
}
- (void)removeViewAtIndex:(unsigned)anIndex
{
unsigned viewCountL = [_views count];
if (anIndex < viewCountL)
{
[_views removeObjectAtIndex:anIndex];
if (viewCountL == 1)
{
_viewNumber = MiscNoView;
}
}
}
- (SEL)valueSelectorForSwitchSource:aSender
{
SEL valueSelectorL;
if ([aSender isKindOfClass:[NSMatrix class]])
{
int rowNumber;
int columnNumber;
[aSender getNumberOfRows:&rowNumber columns:&columnNumber];
if (columnNumber <= rowNumber)
{
valueSelectorL = @selector(selectedRow);
}
else
{
valueSelectorL = @selector(selectedColumn);
}
}
else if ([aSender respondsToSelector:@selector(isEditable)] &&
[aSender isEditable] &&
[aSender respondsToSelector:@selector(intValue)])
{
valueSelectorL = @selector(intValue);
}
else if ([aSender isKindOfClass:[NSButton class]] ||
[aSender isKindOfClass:[NSButtonCell class]])
{
valueSelectorL = @selector(tag);
}
else if ([aSender respondsToSelector:@selector(intValue)])
{
valueSelectorL = @selector(intValue);
}
else if ([aSender respondsToSelector:@selector(tag)])
{
valueSelectorL = @selector(tag);
}
else
{
valueSelectorL = (SEL)NULL;
}
return valueSelectorL;
}
- (void)subviewFrameChanged:(NSNotification *)aNotification
{
if ([self indexOfView:[aNotification object]] == _viewNumber)
{
[self _positionView];
}
}
// ----------------- Delegate Instance Method Definitions ---------------------
@end
@implementation MiscSwitchView(Private)
// ---------------------- Private Method Definitions --------------------------
- (void)_positionView
{
if (_viewNumber != MiscNoView)
{
float borderWidthL;
NSRect boundsRectL;
NSRect subviewFrameL;
NSPoint frameOriginL;
NSView *viewL;
if (_borderType == MiscNone)
{
borderWidthL = 0.0;
}
else
{
borderWidthL = 2.0;
}
viewL = [_views objectAtIndex:_viewNumber];
boundsRectL = [self bounds];
subviewFrameL = [viewL frame];
// Cases ordered in decreasing probability.
switch (_position)
{
// Centering is most common and is the default should an
// unsupported position be specified.
case MiscCenter:
default:
frameOriginL = NSMakePoint((NSWidth(boundsRectL) -
NSWidth(subviewFrameL)) / 2.0,
(NSHeight(boundsRectL) -
NSHeight(subviewFrameL)) / 2.0);
break;
case MiscTopCenter:
frameOriginL = NSMakePoint((NSWidth(boundsRectL) -
NSWidth(subviewFrameL)) / 2.0,
NSHeight(boundsRectL) -
NSHeight(subviewFrameL) -
borderWidthL);
break;
case MiscBottomCenter:
frameOriginL = NSMakePoint((NSWidth(boundsRectL) -
NSWidth(subviewFrameL)) / 2.0,
borderWidthL);
break;
case MiscTopLeft:
frameOriginL = NSMakePoint(borderWidthL,
NSHeight(boundsRectL) -
NSHeight(subviewFrameL) -
borderWidthL);
break;
case MiscTopRight:
frameOriginL = NSMakePoint(NSWidth(boundsRectL) -
NSWidth(subviewFrameL) -
borderWidthL,
NSHeight(boundsRectL) -
NSHeight(subviewFrameL) -
borderWidthL);
break;
case MiscLeft:
frameOriginL = NSMakePoint(borderWidthL,
(NSHeight(boundsRectL) -
NSHeight(subviewFrameL)) / 2.0);
break;
case MiscRight:
frameOriginL = NSMakePoint(NSWidth(boundsRectL) -
NSWidth(subviewFrameL) -
borderWidthL,
(NSHeight(boundsRectL) -
NSHeight(subviewFrameL)) / 2.0);
break;
case MiscBottomLeft:
frameOriginL = NSMakePoint(borderWidthL, borderWidthL);
break;
case MiscBottomRight:
frameOriginL = NSMakePoint(NSWidth(boundsRectL) -
NSWidth(subviewFrameL) -
borderWidthL,
borderWidthL);
break;
}
[viewL setFrameOrigin:frameOriginL];
[viewL setNeedsDisplay:YES];
}
}
@end
// ------------------------- Function Definitions -----------------------------
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.