SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
HexFiend/HFLineCountingRepresenter.m
1 //
2 // HFLineCountingRepresenter.m
3 // HexFiend_2
4 //
5 // Copyright 2007 ridiculous_fish. All rights reserved.
6 //
7
8 #import <HexFiend/HFLineCountingRepresenter.h>
9 #import <HexFiend/HFLineCountingView.h>
10
11 NSString *const HFLineCountingRepresenterMinimumViewWidthChanged = @"HFLineCountingRepresenterMinimumViewWidthChanged";
12
13 /* Returns the maximum advance in points for a hexadecimal digit for the given font (interpreted as a screen font) */
14 static CGFloat maximumDigitAdvanceForFont(NSFont *font) {
15 REQUIRE_NOT_NULL(font);
16 font = [font screenFont];
17 CGFloat maxDigitAdvance = 0;
18 NSDictionary *attributesDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:font, NSFontAttributeName, nil];
19 NSTextStorage *storage = [[NSTextStorage alloc] init];
20 NSLayoutManager *manager = [[NSLayoutManager alloc] init];
21 [storage setFont:font];
22 [storage addLayoutManager:manager];
23
24 NSSize advancements[16] = {};
25 NSGlyph glyphs[16];
26
27 /* Generate a glyph for every hex digit */
28 for (NSUInteger i=0; i < 16; i++) {
29 char c = "0123456789ABCDEF"[i];
30 NSString *string = [[NSString alloc] initWithBytes:&c length:1 encoding:NSASCIIStringEncoding];
31 [storage replaceCharactersInRange:NSMakeRange(0, (i ? 1 : 0)) withString:string];
32 [string release];
33 glyphs[i] = [manager glyphAtIndex:0 isValidIndex:NULL];
34 HFASSERT(glyphs[i] != NSNullGlyph);
35 }
36
37 /* Get the advancements of each of those glyphs */
38 [font getAdvancements:advancements forGlyphs:glyphs count:sizeof glyphs / sizeof *glyphs];
39
40 [manager release];
41 [attributesDictionary release];
42 [storage release];
43
44 /* Find the widest digit */
45 for (NSUInteger i=0; i < sizeof glyphs / sizeof *glyphs; i++) {
46 maxDigitAdvance = HFMax(maxDigitAdvance, advancements[i].width);
47 }
48 return maxDigitAdvance;
49 }
50
51 @implementation HFLineCountingRepresenter
52
53 - (instancetype)init {
54 if ((self = [super init])) {
55 minimumDigitCount = 2;
56 digitsToRepresentContentsLength = minimumDigitCount;
57 interiorShadowEdge = NSMaxXEdge;
58
59 _borderedEdges = (1 << NSMaxXEdge);
60 _borderColor = [[NSColor controlShadowColor] retain];
61 _backgroundColor = [[NSColor windowBackgroundColor] retain];
62 }
63 return self;
64 }
65
66 - (void)encodeWithCoder:(NSCoder *)coder {
67 HFASSERT([coder allowsKeyedCoding]);
68 [super encodeWithCoder:coder];
69 [coder encodeDouble:lineHeight forKey:@"HFLineHeight"];
70 [coder encodeInt64:minimumDigitCount forKey:@"HFMinimumDigitCount"];
71 [coder encodeInt64:lineNumberFormat forKey:@"HFLineNumberFormat"];
72 [coder encodeObject:self.backgroundColor forKey:@"HFBackgroundColor"];
73 [coder encodeObject:self.borderColor forKey:@"HFBorderColor"];
74 [coder encodeInt64:self.borderedEdges forKey:@"HFBorderedEdges"];
75 }
76
77 - (instancetype)initWithCoder:(NSCoder *)coder {
78 HFASSERT([coder allowsKeyedCoding]);
79 self = [super initWithCoder:coder];
80 lineHeight = (CGFloat)[coder decodeDoubleForKey:@"HFLineHeight"];
81 minimumDigitCount = (NSUInteger)[coder decodeInt64ForKey:@"HFMinimumDigitCount"];
82 lineNumberFormat = (HFLineNumberFormat)[coder decodeInt64ForKey:@"HFLineNumberFormat"];
83
84 _borderedEdges = [coder decodeObjectForKey:@"HFBorderedEdges"] ? (NSInteger)[coder decodeInt64ForKey:@"HFBorderedEdges"] : 0;
85 _borderColor = [[NSColor controlShadowColor] retain];
86 _backgroundColor = [[NSColor windowBackgroundColor] retain];
87
88 return self;
89 }
90
91 - (void)dealloc {
92 [_borderColor release];
93 [_backgroundColor release];
94 [super dealloc];
95 }
96
97 - (NSView *)createView {
98 HFLineCountingView *result = [[HFLineCountingView alloc] initWithFrame:NSMakeRect(0, 0, 60, 10)];
99 [result setRepresenter:self];
100 [result setAutoresizingMask:NSViewHeightSizable];
101 return result;
102 }
103
104 - (void)postMinimumViewWidthChangedNotification {
105 [[NSNotificationCenter defaultCenter] postNotificationName:HFLineCountingRepresenterMinimumViewWidthChanged object:self];
106 }
107
108 - (void)updateDigitAdvanceWithFont:(NSFont *)font {
109 CGFloat newDigitAdvance = maximumDigitAdvanceForFont(font);
110 if (digitAdvance != newDigitAdvance) {
111 digitAdvance = newDigitAdvance;
112 [self postMinimumViewWidthChangedNotification];
113 }
114 }
115
116 - (void)updateFontAndLineHeight {
117 HFLineCountingView *view = [self view];
118 HFController *controller = [self controller];
119 NSFont *font = controller ? [controller font] : [NSFont fontWithName:HFDEFAULT_FONT size:HFDEFAULT_FONTSIZE];
120 [view setFont:font];
121 [view setLineHeight: controller ? [controller lineHeight] : HFDEFAULT_FONTSIZE];
122 [self updateDigitAdvanceWithFont:font];
123 }
124
125 - (void)updateLineNumberFormat {
126 [[self view] setLineNumberFormat:lineNumberFormat];
127 }
128
129 - (void)updateBytesPerLine {
130 [[self view] setBytesPerLine:[[self controller] bytesPerLine]];
131 }
132
133 - (void)updateLineRangeToDraw {
134 HFFPRange lineRange = {0, 0};
135 HFController *controller = [self controller];
136 if (controller) {
137 lineRange = [controller displayedLineRange];
138 }
139 [[self view] setLineRangeToDraw:lineRange];
140 }
141
142 - (CGFloat)preferredWidth {
143 if (digitAdvance == 0) {
144 /* This may happen if we were loaded from a nib. We are lazy about fetching the controller's font to avoid ordering issues with nib unarchival. */
145 [self updateFontAndLineHeight];
146 }
147 return (CGFloat)10. + digitsToRepresentContentsLength * digitAdvance;
148 }
149
150 - (void)updateMinimumViewWidth {
151 HFController *controller = [self controller];
152 if (controller) {
153 unsigned long long contentsLength = [controller contentsLength];
154 NSUInteger bytesPerLine = [controller bytesPerLine];
155 /* We want to know how many lines are displayed. That's equal to the contentsLength divided by bytesPerLine rounded down, except in the case that we're at the end of a line, in which case we need to show one more. Hence adding 1 and dividing gets us the right result. */
156 unsigned long long lineCount = contentsLength / bytesPerLine;
157 unsigned long long contentsLengthRoundedToLine = HFProductULL(lineCount, bytesPerLine) - 1;
158 NSUInteger digitCount = [HFLineCountingView digitsRequiredToDisplayLineNumber:contentsLengthRoundedToLine inFormat:lineNumberFormat];
159 NSUInteger digitWidth = MAX(minimumDigitCount, digitCount);
160 if (digitWidth != digitsToRepresentContentsLength) {
161 digitsToRepresentContentsLength = digitWidth;
162 [self postMinimumViewWidthChangedNotification];
163 }
164 }
165 }
166
167 - (CGFloat)minimumViewWidthForBytesPerLine:(NSUInteger)bytesPerLine {
168 USE(bytesPerLine);
169 return [self preferredWidth];
170 }
171
172 - (HFLineNumberFormat)lineNumberFormat {
173 return lineNumberFormat;
174 }
175
176 - (void)setLineNumberFormat:(HFLineNumberFormat)format {
177 HFASSERT(format < HFLineNumberFormatMAXIMUM);
178 lineNumberFormat = format;
179 [self updateLineNumberFormat];
180 [self updateMinimumViewWidth];
181 }
182
183
184 - (void)cycleLineNumberFormat {
185 lineNumberFormat = (lineNumberFormat + 1) % HFLineNumberFormatMAXIMUM;
186 [self updateLineNumberFormat];
187 [self updateMinimumViewWidth];
188 }
189
190 - (void)initializeView {
191 [self updateFontAndLineHeight];
192 [self updateLineNumberFormat];
193 [self updateBytesPerLine];
194 [self updateLineRangeToDraw];
195 [self updateMinimumViewWidth];
196 }
197
198 - (void)controllerDidChange:(HFControllerPropertyBits)bits {
199 if (bits & HFControllerDisplayedLineRange) [self updateLineRangeToDraw];
200 if (bits & HFControllerBytesPerLine) [self updateBytesPerLine];
201 if (bits & (HFControllerFont | HFControllerLineHeight)) [self updateFontAndLineHeight];
202 if (bits & (HFControllerContentLength)) [self updateMinimumViewWidth];
203 }
204
205 - (void)setMinimumDigitCount:(NSUInteger)width {
206 minimumDigitCount = width;
207 [self updateMinimumViewWidth];
208 }
209
210 - (NSUInteger)minimumDigitCount {
211 return minimumDigitCount;
212 }
213
214 - (NSUInteger)digitCount {
215 return digitsToRepresentContentsLength;
216 }
217
218 + (NSPoint)defaultLayoutPosition {
219 return NSMakePoint(-1, 0);
220 }
221
222 - (void)setInteriorShadowEdge:(NSInteger)edge {
223 self->interiorShadowEdge = edge;
224 if ([self isViewLoaded]) {
225 [[self view] setNeedsDisplay:YES];
226 }
227 }
228
229 - (NSInteger)interiorShadowEdge {
230 return interiorShadowEdge;
231 }
232
233
234 - (void)setBorderColor:(NSColor *)color {
235 [_borderColor autorelease];
236 _borderColor = [color copy];
237 if ([self isViewLoaded]) {
238 [[self view] setNeedsDisplay:YES];
239 }
240 }
241
242 - (void)setBackgroundColor:(NSColor *)color {
243 [_backgroundColor autorelease];
244 _backgroundColor = [color copy];
245 if ([self isViewLoaded]) {
246 [[self view] setNeedsDisplay:YES];
247 }
248 }
249
250 @end
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.