bsnes/HexFiend/HFStatusBarRepresenter.m

267 lines
9.7 KiB
Objective-C

//
// HFStatusBarRepresenter.m
// HexFiend_2
//
// Copyright 2007 ridiculous_fish. All rights reserved.
//
#import <HexFiend/HFStatusBarRepresenter.h>
#import <HexFiend/HFFunctions.h>
#define kHFStatusBarDefaultModeUserDefaultsKey @"HFStatusBarDefaultMode"
@interface HFStatusBarView : NSView {
NSCell *cell;
NSSize cellSize;
HFStatusBarRepresenter *representer;
NSDictionary *cellAttributes;
BOOL registeredForAppNotifications;
}
- (void)setRepresenter:(HFStatusBarRepresenter *)rep;
- (void)setString:(NSString *)string;
@end
@implementation HFStatusBarView
- (void)_sharedInitStatusBarView {
NSMutableParagraphStyle *style = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] autorelease];
[style setAlignment:NSCenterTextAlignment];
cellAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:[NSColor colorWithCalibratedWhite:(CGFloat).15 alpha:1], NSForegroundColorAttributeName, [NSFont labelFontOfSize:10], NSFontAttributeName, style, NSParagraphStyleAttributeName, nil];
cell = [[NSCell alloc] initTextCell:@""];
[cell setAlignment:NSCenterTextAlignment];
[cell setBackgroundStyle:NSBackgroundStyleRaised];
}
- (instancetype)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
[self _sharedInitStatusBarView];
return self;
}
- (instancetype)initWithCoder:(NSCoder *)coder {
HFASSERT([coder allowsKeyedCoding]);
self = [super initWithCoder:coder];
[self _sharedInitStatusBarView];
return self;
}
// nothing to do in encodeWithCoder
- (BOOL)isFlipped { return YES; }
- (void)setRepresenter:(HFStatusBarRepresenter *)rep {
representer = rep;
}
- (void)setString:(NSString *)string {
[cell setAttributedStringValue:[[[NSAttributedString alloc] initWithString:string attributes:cellAttributes] autorelease]];
cellSize = [cell cellSize];
[self setNeedsDisplay:YES];
}
- (void)drawDividerWithClip:(NSRect)clipRect {
[[NSColor lightGrayColor] set];
NSRect bounds = [self bounds];
NSRect lineRect = bounds;
lineRect.size.height = 1;
NSRectFill(NSIntersectionRect(lineRect, clipRect));
}
- (NSGradient *)getGradient:(BOOL)active {
static NSGradient *sActiveGradient;
static NSGradient *sInactiveGradient;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sActiveGradient = [[NSGradient alloc] initWithColorsAndLocations:
[NSColor colorWithCalibratedWhite:.89 alpha:1.], 0.00,
[NSColor colorWithCalibratedWhite:.77 alpha:1.], 0.9,
[NSColor colorWithCalibratedWhite:.82 alpha:1.], 1.0,
nil];
sInactiveGradient = [[NSGradient alloc] initWithColorsAndLocations:
[NSColor colorWithCalibratedWhite:.93 alpha:1.], 0.00,
[NSColor colorWithCalibratedWhite:.87 alpha:1.], 0.9,
[NSColor colorWithCalibratedWhite:.90 alpha:1.], 1.0,
nil];
});
return active ? sActiveGradient : sInactiveGradient;
}
- (void)drawRect:(NSRect)clip {
USE(clip);
NSRect bounds = [self bounds];
// [[NSColor colorWithCalibratedWhite:(CGFloat).91 alpha:1] set];
// NSRectFill(clip);
NSWindow *window = [self window];
BOOL drawActive = (window == nil || [window isMainWindow] || [window isKeyWindow]);
[[self getGradient:drawActive] drawInRect:bounds angle:90.];
[self drawDividerWithClip:clip];
NSRect cellRect = NSMakeRect(NSMinX(bounds), HFCeil(NSMidY(bounds) - cellSize.height / 2), NSWidth(bounds), cellSize.height);
[cell drawWithFrame:cellRect inView:self];
}
- (void)mouseDown:(NSEvent *)event {
USE(event);
HFStatusBarMode newMode = ([representer statusMode] + 1) % HFSTATUSMODECOUNT;
[representer setStatusMode:newMode];
[[NSUserDefaults standardUserDefaults] setInteger:newMode forKey:kHFStatusBarDefaultModeUserDefaultsKey];
}
- (void)windowDidChangeKeyStatus:(NSNotification *)note {
USE(note);
[self setNeedsDisplay:YES];
}
- (void)viewDidMoveToWindow {
HFRegisterViewForWindowAppearanceChanges(self, @selector(windowDidChangeKeyStatus:), !registeredForAppNotifications);
registeredForAppNotifications = YES;
[super viewDidMoveToWindow];
}
- (void)viewWillMoveToWindow:(NSWindow *)newWindow {
HFUnregisterViewForWindowAppearanceChanges(self, NO);
[super viewWillMoveToWindow:newWindow];
}
- (void)dealloc {
HFUnregisterViewForWindowAppearanceChanges(self, registeredForAppNotifications);
[cell release];
[cellAttributes release];
[super dealloc];
}
@end
@implementation HFStatusBarRepresenter
- (void)encodeWithCoder:(NSCoder *)coder {
HFASSERT([coder allowsKeyedCoding]);
[super encodeWithCoder:coder];
[coder encodeInt64:statusMode forKey:@"HFStatusMode"];
}
- (instancetype)initWithCoder:(NSCoder *)coder {
HFASSERT([coder allowsKeyedCoding]);
self = [super initWithCoder:coder];
statusMode = (NSUInteger)[coder decodeInt64ForKey:@"HFStatusMode"];
return self;
}
- (instancetype)init {
self = [super init];
statusMode = [[NSUserDefaults standardUserDefaults] integerForKey:kHFStatusBarDefaultModeUserDefaultsKey];
return self;
}
- (NSView *)createView {
HFStatusBarView *view = [[HFStatusBarView alloc] initWithFrame:NSMakeRect(0, 0, 100, 18)];
[view setRepresenter:self];
[view setAutoresizingMask:NSViewWidthSizable];
return view;
}
- (NSString *)describeLength:(unsigned long long)length {
switch (statusMode) {
case HFStatusModeDecimal: return [NSString stringWithFormat:@"%llu byte%s", length, length == 1 ? "" : "s"];
case HFStatusModeHexadecimal: return [NSString stringWithFormat:@"0x%llX byte%s", length, length == 1 ? "" : "s"];
case HFStatusModeApproximate: return [NSString stringWithFormat:@"%@", HFDescribeByteCount(length)];
default: [NSException raise:NSInternalInconsistencyException format:@"Unknown status mode %lu", (unsigned long)statusMode]; return @"";
}
}
- (NSString *)describeOffset:(unsigned long long)offset {
switch (statusMode) {
case HFStatusModeDecimal: return [NSString stringWithFormat:@"%llu", offset];
case HFStatusModeHexadecimal: return [NSString stringWithFormat:@"0x%llX", offset];
case HFStatusModeApproximate: return [NSString stringWithFormat:@"%@", HFDescribeByteCount(offset)];
default: [NSException raise:NSInternalInconsistencyException format:@"Unknown status mode %lu", (unsigned long)statusMode]; return @"";
}
}
/* same as describeOffset, except we treat Approximate like Hexadecimal */
- (NSString *)describeOffsetExcludingApproximate:(unsigned long long)offset {
switch (statusMode) {
case HFStatusModeDecimal: return [NSString stringWithFormat:@"%llu", offset];
case HFStatusModeHexadecimal:
case HFStatusModeApproximate: return [NSString stringWithFormat:@"0x%llX", offset];
default: [NSException raise:NSInternalInconsistencyException format:@"Unknown status mode %lu", (unsigned long)statusMode]; return @"";
}
}
- (NSString *)stringForEmptySelectionAtOffset:(unsigned long long)offset length:(unsigned long long)length {
return [NSString stringWithFormat:@"%@ out of %@", [self describeOffset:offset], [self describeLength:length]];
}
- (NSString *)stringForSingleByteSelectionAtOffset:(unsigned long long)offset length:(unsigned long long)length {
return [NSString stringWithFormat:@"Byte %@ selected out of %@", [self describeOffset:offset], [self describeLength:length]];
}
- (NSString *)stringForSingleRangeSelection:(HFRange)range length:(unsigned long long)length {
return [NSString stringWithFormat:@"%@ selected at offset %@ out of %@", [self describeLength:range.length], [self describeOffsetExcludingApproximate:range.location], [self describeLength:length]];
}
- (NSString *)stringForMultipleSelectionsWithLength:(unsigned long long)multipleSelectionLength length:(unsigned long long)length {
return [NSString stringWithFormat:@"%@ selected at multiple offsets out of %@", [self describeLength:multipleSelectionLength], [self describeLength:length]];
}
- (void)updateString {
NSString *string = nil;
HFController *controller = [self controller];
if (controller) {
unsigned long long length = [controller contentsLength];
NSArray *ranges = [controller selectedContentsRanges];
NSUInteger rangeCount = [ranges count];
if (rangeCount == 1) {
HFRange range = [ranges[0] HFRange];
if (range.length == 0) {
string = [self stringForEmptySelectionAtOffset:range.location length:length];
}
else if (range.length == 1) {
string = [self stringForSingleByteSelectionAtOffset:range.location length:length];
}
else {
string = [self stringForSingleRangeSelection:range length:length];
}
}
else {
unsigned long long totalSelectionLength = 0;
FOREACH(HFRangeWrapper *, wrapper, ranges) {
HFRange range = [wrapper HFRange];
totalSelectionLength = HFSum(totalSelectionLength, range.length);
}
string = [self stringForMultipleSelectionsWithLength:totalSelectionLength length:length];
}
}
if (! string) string = @"";
[[self view] setString:string];
}
- (HFStatusBarMode)statusMode {
return statusMode;
}
- (void)setStatusMode:(HFStatusBarMode)mode {
statusMode = mode;
[self updateString];
}
- (void)controllerDidChange:(HFControllerPropertyBits)bits {
if (bits & (HFControllerContentLength | HFControllerSelectedRanges)) {
[self updateString];
}
}
+ (NSPoint)defaultLayoutPosition {
return NSMakePoint(0, -1);
}
@end