SameBoy/HexFiend/HFVerticalScrollerRepresenter.m

134 lines
5.0 KiB
Objective-C

//
// HFRepresenterVerticalScroller.m
// HexFiend_2
//
// Copyright 2007 ridiculous_fish. All rights reserved.
//
/* Note that on Tiger, NSScroller did not support double in any meaningful way; [scroller doubleValue] always returns 0, and setDoubleValue: doesn't look like it works either. */
#import <HexFiend/HFVerticalScrollerRepresenter.h>
@implementation HFVerticalScrollerRepresenter
/* No special NSCoding support needed */
- (NSView *)createView {
NSScroller *scroller = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, [NSScroller scrollerWidthForControlSize:NSRegularControlSize scrollerStyle:NSScrollerStyleLegacy], 64)];
[scroller setTarget:self];
[scroller setContinuous:YES];
[scroller setEnabled:YES];
[scroller setTarget:self];
[scroller setAction:@selector(scrollerDidChangeValue:)];
[scroller setAutoresizingMask:NSViewHeightSizable];
return scroller;
}
- (NSUInteger)visibleLines {
HFController *controller = [self controller];
HFASSERT(controller != NULL);
return ll2l(HFFPToUL(ceill([controller displayedLineRange].length)));
}
- (void)scrollByKnobToValue:(double)newValue {
HFASSERT(newValue >= 0. && newValue <= 1.);
HFController *controller = [self controller];
unsigned long long contentsLength = [controller contentsLength];
NSUInteger bytesPerLine = [controller bytesPerLine];
HFASSERT(bytesPerLine > 0);
unsigned long long totalLineCountTimesBytesPerLine = HFRoundUpToNextMultipleSaturate(contentsLength - 1, bytesPerLine);
HFASSERT(totalLineCountTimesBytesPerLine == ULLONG_MAX || totalLineCountTimesBytesPerLine % bytesPerLine == 0);
unsigned long long totalLineCount = HFDivideULLRoundingUp(totalLineCountTimesBytesPerLine, bytesPerLine);
HFFPRange currentLineRange = [controller displayedLineRange];
HFASSERT(currentLineRange.length < HFULToFP(totalLineCount));
long double maxScroll = totalLineCount - currentLineRange.length;
long double newScroll = maxScroll * (long double)newValue;
[controller setDisplayedLineRange:(HFFPRange){newScroll, currentLineRange.length}];
}
- (void)scrollByLines:(long long)linesInt {
if (linesInt == 0) return;
//note - this properly computes the absolute value even for LLONG_MIN
long double lines = HFULToFP((unsigned long long)llabs(linesInt));
HFController *controller = [self controller];
HFASSERT(controller != NULL);
HFFPRange displayedRange = [[self controller] displayedLineRange];
if (linesInt < 0) {
displayedRange.location -= MIN(lines, displayedRange.location);
}
else {
long double availableLines = HFULToFP([controller totalLineCount]);
displayedRange.location = MIN(availableLines - displayedRange.length, displayedRange.location + lines);
}
[controller setDisplayedLineRange:displayedRange];
}
- (void)scrollerDidChangeValue:(NSScroller *)scroller {
assert(scroller == [self view]);
switch ([scroller hitPart]) {
case NSScrollerDecrementPage: [self scrollByLines: -(long long)[self visibleLines]]; break;
case NSScrollerIncrementPage: [self scrollByLines: (long long)[self visibleLines]]; break;
case NSScrollerDecrementLine: [self scrollByLines: -1LL]; break;
case NSScrollerIncrementLine: [self scrollByLines: 1LL]; break;
case NSScrollerKnob: [self scrollByKnobToValue:[scroller doubleValue]]; break;
default: break;
}
}
- (void)updateScrollerValue {
HFController *controller = [self controller];
CGFloat value, proportion;
NSScroller *scroller = [self view];
BOOL enable = YES;
if (controller == nil) {
value = 0;
proportion = 0;
}
else {
unsigned long long length = [controller contentsLength];
HFFPRange lineRange = [controller displayedLineRange];
HFASSERT(lineRange.location >= 0 && lineRange.length >= 0);
if (length == 0) {
value = 0;
proportion = 1;
enable = NO;
}
else {
long double availableLines = HFULToFP([controller totalLineCount]);
long double consumedLines = MAX(1., lineRange.length);
proportion = ld2f(lineRange.length / availableLines);
long double maxScroll = availableLines - consumedLines;
HFASSERT(maxScroll >= lineRange.location);
if (maxScroll == 0.) {
enable = NO;
value = 0;
}
else {
value = ld2f(lineRange.location / maxScroll);
}
}
}
[scroller setDoubleValue:value];
[scroller setKnobProportion:proportion];
[scroller setEnabled:enable];
}
- (CGFloat)minimumViewWidthForBytesPerLine:(NSUInteger)bytesPerLine {
USE(bytesPerLine);
return [NSScroller scrollerWidthForControlSize:[[self view] controlSize] scrollerStyle:NSScrollerStyleLegacy];
}
- (void)controllerDidChange:(HFControllerPropertyBits)bits {
if (bits & (HFControllerContentLength | HFControllerDisplayedLineRange)) [self updateScrollerValue];
}
+ (NSPoint)defaultLayoutPosition {
return NSMakePoint(2, 0);
}
@end