SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
HexFiend/HFTextRepresenter.m
1 //
2 // HFTextRepresenter.m
3 // HexFiend_2
4 //
5 // Copyright 2007 ridiculous_fish. All rights reserved.
6 //
7
8 #import <HexFiend/HFTextRepresenter_Internal.h>
9 #import <HexFiend/HFRepresenterTextView.h>
10 #import <HexFiend/HFPasteboardOwner.h>
11 #import <HexFiend/HFByteArray.h>
12 #import <HexFiend/HFTextVisualStyleRun.h>
13
14 @implementation HFTextRepresenter
15
16 - (Class)_textViewClass {
17 UNIMPLEMENTED();
18 }
19
20 - (instancetype)init {
21 self = [super init];
22
23 if (@available(macOS 10.14, *)) {
24 _rowBackgroundColors = [[NSColor alternatingContentBackgroundColors] retain];
25 } else {
26 NSColor *color1 = [NSColor windowBackgroundColor];
27 NSColor *color2 = [NSColor colorWithDeviceWhite:0.96 alpha:1];
28 _rowBackgroundColors = [@[color1, color2] retain];
29 }
30
31 return self;
32 }
33
34 - (void)dealloc {
35 if ([self isViewLoaded]) {
36 [[self view] clearRepresenter];
37 }
38 [_rowBackgroundColors release];
39 [super dealloc];
40 }
41
42 - (void)encodeWithCoder:(NSCoder *)coder {
43 HFASSERT([coder allowsKeyedCoding]);
44 [super encodeWithCoder:coder];
45 [coder encodeBool:_behavesAsTextField forKey:@"HFBehavesAsTextField"];
46 [coder encodeObject:_rowBackgroundColors forKey:@"HFRowBackgroundColors"];
47 }
48
49 - (instancetype)initWithCoder:(NSCoder *)coder {
50 HFASSERT([coder allowsKeyedCoding]);
51 self = [super initWithCoder:coder];
52 _behavesAsTextField = [coder decodeBoolForKey:@"HFBehavesAsTextField"];
53 _rowBackgroundColors = [[coder decodeObjectForKey:@"HFRowBackgroundColors"] retain];
54 return self;
55 }
56
57 - (NSView *)createView {
58 HFRepresenterTextView *view = [[[self _textViewClass] alloc] initWithRepresenter:self];
59 [view setAutoresizingMask:NSViewHeightSizable];
60 return view;
61 }
62
63 - (HFByteArrayDataStringType)byteArrayDataStringType {
64 UNIMPLEMENTED();
65 }
66
67 - (HFRange)entireDisplayedRange {
68 HFController *controller = [self controller];
69 unsigned long long contentsLength = [controller contentsLength];
70 HFASSERT(controller != NULL);
71 HFFPRange displayedLineRange = [controller displayedLineRange];
72 NSUInteger bytesPerLine = [controller bytesPerLine];
73 unsigned long long lineStart = HFFPToUL(floorl(displayedLineRange.location));
74 unsigned long long lineEnd = HFFPToUL(ceill(displayedLineRange.location + displayedLineRange.length));
75 HFASSERT(lineEnd >= lineStart);
76 HFRange byteRange = HFRangeMake(HFProductULL(bytesPerLine, lineStart), HFProductULL(lineEnd - lineStart, bytesPerLine));
77 if (byteRange.length == 0) {
78 /* This can happen if we are too small to even show one line */
79 return HFRangeMake(0, 0);
80 }
81 else {
82 HFASSERT(byteRange.location <= contentsLength);
83 byteRange.length = MIN(byteRange.length, contentsLength - byteRange.location);
84 HFASSERT(HFRangeIsSubrangeOfRange(byteRange, HFRangeMake(0, [controller contentsLength])));
85 return byteRange;
86 }
87 }
88
89 - (NSRect)furthestRectOnEdge:(NSRectEdge)edge forByteRange:(HFRange)byteRange {
90 HFASSERT(byteRange.length > 0);
91 HFRange displayedRange = [self entireDisplayedRange];
92 HFRange intersection = HFIntersectionRange(displayedRange, byteRange);
93 NSRect result = {{0,},};
94 if (intersection.length > 0) {
95 NSRange intersectionNSRange = NSMakeRange(ll2l(intersection.location - displayedRange.location), ll2l(intersection.length));
96 if (intersectionNSRange.length > 0) {
97 result = [[self view] furthestRectOnEdge:edge forRange:intersectionNSRange];
98 }
99 }
100 else if (byteRange.location < displayedRange.location) {
101 /* We're below it. */
102 return NSMakeRect(-CGFLOAT_MAX, -CGFLOAT_MAX, 0, 0);
103 }
104 else if (byteRange.location >= HFMaxRange(displayedRange)) {
105 /* We're above it */
106 return NSMakeRect(CGFLOAT_MAX, CGFLOAT_MAX, 0, 0);
107 }
108 else {
109 /* Shouldn't be possible to get here */
110 [NSException raise:NSInternalInconsistencyException format:@"furthestRectOnEdge: expected an intersection, or a range below or above the byte range, but nothin'"];
111 }
112 return result;
113 }
114
115 - (NSPoint)locationOfCharacterAtByteIndex:(unsigned long long)index {
116 NSPoint result;
117 HFRange displayedRange = [self entireDisplayedRange];
118 if (HFLocationInRange(index, displayedRange) || index == HFMaxRange(displayedRange)) {
119 NSUInteger location = ll2l(index - displayedRange.location);
120 result = [[self view] originForCharacterAtByteIndex:location];
121 }
122 else if (index < displayedRange.location) {
123 result = NSMakePoint(-CGFLOAT_MAX, -CGFLOAT_MAX);
124 }
125 else {
126 result = NSMakePoint(CGFLOAT_MAX, CGFLOAT_MAX);
127 }
128 return result;
129 }
130
131 - (HFTextVisualStyleRun *)styleForAttributes:(NSSet *)attributes range:(NSRange)range {
132 HFTextVisualStyleRun *run = [[[HFTextVisualStyleRun alloc] init] autorelease];
133 [run setRange:range];
134 [run setForegroundColor:[NSColor blackColor]];
135
136 return run;
137 }
138
139 - (NSArray *)stylesForRange:(HFRange)range {
140 return nil;
141 }
142
143 - (void)updateText {
144 HFController *controller = [self controller];
145 HFRepresenterTextView *view = [self view];
146 HFRange entireDisplayedRange = [self entireDisplayedRange];
147 [view setData:[controller dataForRange:entireDisplayedRange]];
148 [view setStyles:[self stylesForRange:entireDisplayedRange]];
149 HFFPRange lineRange = [controller displayedLineRange];
150 long double offsetLongDouble = lineRange.location - floorl(lineRange.location);
151 CGFloat offset = ld2f(offsetLongDouble);
152 [view setVerticalOffset:offset];
153 [view setStartingLineBackgroundColorIndex:ll2l(HFFPToUL(floorl(lineRange.location)) % NSUIntegerMax)];
154 }
155
156 - (void)initializeView {
157 [super initializeView];
158 HFRepresenterTextView *view = [self view];
159 HFController *controller = [self controller];
160 if (controller) {
161 [view setFont:[controller font]];
162 [view setEditable:[controller editable]];
163 [self updateText];
164 }
165 else {
166 [view setFont:[NSFont fontWithName:HFDEFAULT_FONT size:HFDEFAULT_FONTSIZE]];
167 }
168 }
169
170 - (void)scrollWheel:(NSEvent *)event {
171 [[self controller] scrollWithScrollEvent:event];
172 }
173
174 - (void)selectAll:(id)sender {
175 [[self controller] selectAll:sender];
176 }
177
178 - (double)selectionPulseAmount {
179 return [[self controller] selectionPulseAmount];
180 }
181
182 - (void)controllerDidChange:(HFControllerPropertyBits)bits {
183 if (bits & (HFControllerFont | HFControllerLineHeight)) {
184 [[self view] setFont:[[self controller] font]];
185 }
186 if (bits & (HFControllerContentValue | HFControllerDisplayedLineRange | HFControllerByteRangeAttributes)) {
187 [self updateText];
188 }
189 if (bits & (HFControllerSelectedRanges | HFControllerDisplayedLineRange)) {
190 [[self view] updateSelectedRanges];
191 }
192 if (bits & (HFControllerEditable)) {
193 [[self view] setEditable:[[self controller] editable]];
194 }
195 if (bits & (HFControllerAntialias)) {
196 [[self view] setShouldAntialias:[[self controller] shouldAntialias]];
197 }
198 if (bits & (HFControllerShowCallouts)) {
199 [[self view] setShouldDrawCallouts:[[self controller] shouldShowCallouts]];
200 }
201 if (bits & (HFControllerColorBytes)) {
202 if([[self controller] shouldColorBytes]) {
203 [[self view] setByteColoring: ^(uint8_t byte, uint8_t *r, uint8_t *g, uint8_t *b, uint8_t *a){
204 *r = *g = *b = (uint8_t)(255 * ((255-byte)/255.0*0.6+0.4));
205 *a = (uint8_t)(255 * 0.7);
206 }];
207 } else {
208 [[self view] setByteColoring:NULL];
209 }
210 }
211 [super controllerDidChange:bits];
212 }
213
214 - (double)maximumAvailableLinesForViewHeight:(CGFloat)viewHeight {
215 return [[self view] maximumAvailableLinesForViewHeight:viewHeight];
216 }
217
218 - (NSUInteger)maximumBytesPerLineForViewWidth:(CGFloat)viewWidth {
219 return [[self view] maximumBytesPerLineForViewWidth:viewWidth];
220 }
221
222 - (CGFloat)minimumViewWidthForBytesPerLine:(NSUInteger)bytesPerLine {
223 return [[self view] minimumViewWidthForBytesPerLine:bytesPerLine];
224 }
225
226 - (NSUInteger)byteGranularity {
227 HFRepresenterTextView *view = [self view];
228 NSUInteger bytesPerColumn = MAX([view bytesPerColumn], 1u), bytesPerCharacter = [view bytesPerCharacter];
229 return HFLeastCommonMultiple(bytesPerColumn, bytesPerCharacter);
230 }
231
232 - (NSArray *)displayedSelectedContentsRanges {
233 HFController *controller = [self controller];
234 NSArray *result;
235 NSArray *selectedRanges = [controller selectedContentsRanges];
236 HFRange displayedRange = [self entireDisplayedRange];
237
238 HFASSERT(displayedRange.length <= NSUIntegerMax);
239 NEW_ARRAY(NSValue *, clippedSelectedRanges, [selectedRanges count]);
240 NSUInteger clippedRangeIndex = 0;
241 FOREACH(HFRangeWrapper *, wrapper, selectedRanges) {
242 HFRange selectedRange = [wrapper HFRange];
243 BOOL clippedRangeIsVisible;
244 NSRange clippedSelectedRange = {0,};
245 /* Necessary because zero length ranges do not intersect anything */
246 if (selectedRange.length == 0) {
247 /* Remember that {6, 0} is considered a subrange of {3, 3} */
248 clippedRangeIsVisible = HFRangeIsSubrangeOfRange(selectedRange, displayedRange);
249 if (clippedRangeIsVisible) {
250 HFASSERT(selectedRange.location >= displayedRange.location);
251 clippedSelectedRange.location = ll2l(selectedRange.location - displayedRange.location);
252 clippedSelectedRange.length = 0;
253 }
254 }
255 else {
256 // selectedRange.length > 0
257 clippedRangeIsVisible = HFIntersectsRange(selectedRange, displayedRange);
258 if (clippedRangeIsVisible) {
259 HFRange intersectionRange = HFIntersectionRange(selectedRange, displayedRange);
260 HFASSERT(intersectionRange.location >= displayedRange.location);
261 clippedSelectedRange.location = ll2l(intersectionRange.location - displayedRange.location);
262 clippedSelectedRange.length = ll2l(intersectionRange.length);
263 }
264 }
265 if (clippedRangeIsVisible) clippedSelectedRanges[clippedRangeIndex++] = [NSValue valueWithRange:clippedSelectedRange];
266 }
267 result = [NSArray arrayWithObjects:clippedSelectedRanges count:clippedRangeIndex];
268 FREE_ARRAY(clippedSelectedRanges);
269 return result;
270 }
271
272 //maps bookmark keys as NSNumber to byte locations as NSNumbers. Because bookmark callouts may extend beyond the lines containing them, allow a larger range by 10 lines.
273 - (NSDictionary *)displayedBookmarkLocations {
274 NSMutableDictionary *result = nil;
275 HFController *controller = [self controller];
276 NSUInteger rangeExtension = 10 * [controller bytesPerLine];
277 HFRange displayedRange = [self entireDisplayedRange];
278
279 HFRange includedRange = displayedRange;
280
281 /* Extend the bottom */
282 unsigned long long bottomExtension = MIN(includedRange.location, rangeExtension);
283 includedRange.location -= bottomExtension;
284 includedRange.length += bottomExtension;
285
286 /* Extend the top */
287 unsigned long long topExtension = MIN([controller contentsLength] - HFMaxRange(includedRange), rangeExtension);
288 includedRange.length = HFSum(includedRange.length, topExtension);
289
290 return result;
291 }
292
293 - (unsigned long long)byteIndexForCharacterIndex:(NSUInteger)characterIndex {
294 HFController *controller = [self controller];
295 HFFPRange lineRange = [controller displayedLineRange];
296 unsigned long long scrollAmount = HFFPToUL(floorl(lineRange.location));
297 unsigned long long byteIndex = HFProductULL(scrollAmount, [controller bytesPerLine]) + characterIndex * [[self view] bytesPerCharacter];
298 return byteIndex;
299 }
300
301 - (void)beginSelectionWithEvent:(NSEvent *)event forCharacterIndex:(NSUInteger)characterIndex {
302 [[self controller] beginSelectionWithEvent:event forByteIndex:[self byteIndexForCharacterIndex:characterIndex]];
303 }
304
305 - (void)continueSelectionWithEvent:(NSEvent *)event forCharacterIndex:(NSUInteger)characterIndex {
306 [[self controller] continueSelectionWithEvent:event forByteIndex:[self byteIndexForCharacterIndex:characterIndex]];
307 }
308
309 - (void)endSelectionWithEvent:(NSEvent *)event forCharacterIndex:(NSUInteger)characterIndex {
310 [[self controller] endSelectionWithEvent:event forByteIndex:[self byteIndexForCharacterIndex:characterIndex]];
311 }
312
313 - (void)insertText:(NSString *)text {
314 USE(text);
315 UNIMPLEMENTED_VOID();
316 }
317
318 - (void)copySelectedBytesToPasteboard:(NSPasteboard *)pb {
319 USE(pb);
320 UNIMPLEMENTED_VOID();
321 }
322
323 - (void)cutSelectedBytesToPasteboard:(NSPasteboard *)pb {
324 [self copySelectedBytesToPasteboard:pb];
325 [[self controller] deleteSelection];
326 }
327
328 - (NSData *)dataFromPasteboardString:(NSString *)string {
329 USE(string);
330 UNIMPLEMENTED();
331 }
332
333 - (BOOL)canPasteFromPasteboard:(NSPasteboard *)pb {
334 REQUIRE_NOT_NULL(pb);
335 if ([[self controller] editable]) {
336 // we can paste if the pboard contains text or contains an HFByteArray
337 return [HFPasteboardOwner unpackByteArrayFromPasteboard:pb] || [pb availableTypeFromArray:@[NSStringPboardType]];
338 }
339 return NO;
340 }
341
342 - (BOOL)canCut {
343 /* We can cut if we are editable, we have at least one byte selected, and we are not in overwrite mode */
344 HFController *controller = [self controller];
345 if ([controller editMode] != HFInsertMode) return NO;
346 if (! [controller editable]) return NO;
347
348 FOREACH(HFRangeWrapper *, rangeWrapper, [controller selectedContentsRanges]) {
349 if ([rangeWrapper HFRange].length > 0) return YES; //we have something selected
350 }
351 return NO; // we did not find anything selected
352 }
353
354 - (BOOL)pasteBytesFromPasteboard:(NSPasteboard *)pb {
355 REQUIRE_NOT_NULL(pb);
356 BOOL result = NO;
357 HFByteArray *byteArray = [HFPasteboardOwner unpackByteArrayFromPasteboard:pb];
358 if (byteArray) {
359 [[self controller] insertByteArray:byteArray replacingPreviousBytes:0 allowUndoCoalescing:NO];
360 result = YES;
361 }
362 else {
363 NSString *stringType = [pb availableTypeFromArray:@[NSStringPboardType]];
364 if (stringType) {
365 NSString *stringValue = [pb stringForType:stringType];
366 if (stringValue) {
367 NSData *data = [self dataFromPasteboardString:stringValue];
368 if (data) {
369 [[self controller] insertData:data replacingPreviousBytes:0 allowUndoCoalescing:NO];
370 }
371 }
372 }
373 }
374 return result;
375 }
376
377 @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.