SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
Cocoa/GBTerminalTextFieldCell.m
1 #import <Carbon/Carbon.h>
2 #import "GBTerminalTextFieldCell.h"
3 #import "NSTextFieldCell+Inset.h"
4
5 @interface GBTerminalTextView : NSTextView
6 {
7 @public __weak NSTextField *_field;
8 }
9 @property GB_gameboy_t *gb;
10 @end
11
12 @implementation GBTerminalTextFieldCell
13 {
14 GBTerminalTextView *_fieldEditor;
15 }
16
17 - (NSTextView *)fieldEditorForView:(NSTextField *)controlView
18 {
19 if (_fieldEditor) {
20 _fieldEditor.gb = self.gb;
21 return _fieldEditor;
22 }
23 _fieldEditor = [[GBTerminalTextView alloc] init];
24 [_fieldEditor setFieldEditor:true];
25 _fieldEditor.gb = self.gb;
26 _fieldEditor->_field = (NSTextField *)controlView;
27 ((NSTextFieldCell *)controlView.cell).textInset =
28 _fieldEditor.textContainerInset =
29 NSMakeSize(7, 2);
30 return _fieldEditor;
31 }
32
33 @end
34
35 @implementation GBTerminalTextView
36 {
37 NSMutableOrderedSet *lines;
38 NSUInteger current_line;
39 bool reverse_search_mode;
40 NSRange auto_complete_range;
41 uintptr_t auto_complete_context;
42 }
43
44 - (instancetype)init
45 {
46 self = [super init];
47 if (!self) {
48 return nil;
49 }
50 lines = [[NSMutableOrderedSet alloc] init];
51 return self;
52 }
53
54 - (void)moveUp:(id)sender
55 {
56 reverse_search_mode = false;
57 if (current_line != 0) {
58 current_line--;
59 [self setString:[lines objectAtIndex:current_line]];
60 }
61 else {
62 [self setSelectedRange:NSMakeRange(0, 0)];
63 NSBeep();
64 }
65 }
66
67 - (void)moveDown:(id)sender
68 {
69 reverse_search_mode = false;
70 if (current_line == [lines count]) {
71 [self setString:@""];
72 NSBeep();
73 return;
74 }
75 current_line++;
76 if (current_line == [lines count]) {
77 [self setString:@""];
78 }
79 else {
80 [self setString:[lines objectAtIndex:current_line]];
81 }
82 }
83
84 -(void)insertNewline:(id)sender
85 {
86 if ([self.string length]) {
87 NSString *string = [self.string copy];
88 [lines removeObject:string];
89 [lines addObject:string];
90 }
91 [super insertNewline:sender];
92 current_line = [lines count];
93 reverse_search_mode = false;
94 }
95
96 - (void)keyDown:(NSEvent *)event
97 {
98 if (event.keyCode == kVK_ANSI_R && (event.modifierFlags & NSEventModifierFlagDeviceIndependentFlagsMask) == NSEventModifierFlagControl) {
99 if ([lines count] == 0) {
100 NSBeep();
101 return;
102 }
103 if (!reverse_search_mode) {
104 [self selectAll:self];
105 current_line = [lines count] - 1;
106 }
107 else {
108 if (current_line != 0) {
109 current_line--;
110 }
111 else {
112 NSBeep();
113 }
114 }
115
116 if (self.string.length) {
117 [self updateReverseSearch];
118 }
119 else {
120 [self setNeedsDisplay:true];
121 reverse_search_mode = true;
122 }
123
124 }
125 else {
126 [super keyDown:event];
127 }
128 }
129
130 - (void) updateReverseSearch
131 {
132 NSUInteger old_line = current_line;
133 reverse_search_mode = false;
134 NSString *substring = [self.string substringWithRange:self.selectedRange];
135 do {
136 NSString *line = [lines objectAtIndex:current_line];
137 NSRange range = [line rangeOfString:substring];
138 if (range.location != NSNotFound) {
139 self.string = line;
140 [self setSelectedRange:range];
141 reverse_search_mode = true;
142 return;
143 }
144 } while (current_line--);
145 current_line = old_line;
146 reverse_search_mode = true;
147 NSBeep();
148 }
149
150 - (void) insertText:(NSString *)string replacementRange:(NSRange)range
151 {
152 if (reverse_search_mode) {
153 range = self.selectedRange;
154 self.string = [[self.string substringWithRange:range] stringByAppendingString:string];
155 [self selectAll:nil];
156 [self updateReverseSearch];
157 }
158 else {
159 [super insertText:string replacementRange:range];
160 }
161 }
162
163 -(void)deleteBackward:(id)sender
164 {
165 if (reverse_search_mode && self.string.length) {
166 NSRange range = self.selectedRange;
167 range.length--;
168 self.string = [self.string substringWithRange:range];
169 if (range.length) {
170 [self selectAll:nil];
171 [self updateReverseSearch];
172 }
173 else {
174 reverse_search_mode = true;
175 current_line = [lines count] - 1;
176 }
177 }
178 else {
179 [super deleteBackward:sender];
180 }
181 }
182
183 -(void)setSelectedRanges:(NSArray<NSValue *> *)ranges affinity:(NSSelectionAffinity)affinity stillSelecting:(BOOL)stillSelectingFlag
184 {
185 reverse_search_mode = false;
186 auto_complete_context = 0;
187 [super setSelectedRanges:ranges affinity:affinity stillSelecting:stillSelectingFlag];
188 }
189
190 - (BOOL)resignFirstResponder
191 {
192 reverse_search_mode = false;
193 return [super resignFirstResponder];
194 }
195
196 - (NSColor *)backgroundColor
197 {
198 return nil;
199 }
200
201 - (void)drawRect:(NSRect)dirtyRect
202 {
203 if (reverse_search_mode && [super string].length == 0) {
204 NSMutableDictionary *attributes = [self.typingAttributes mutableCopy];
205 NSColor *color = [attributes[NSForegroundColorAttributeName] colorWithAlphaComponent:0.5];
206 [attributes setObject:color forKey:NSForegroundColorAttributeName];
207 [[[NSAttributedString alloc] initWithString:@"Reverse search..." attributes:attributes] drawAtPoint:NSMakePoint(9, 2)];
208 }
209 else {
210 [super drawRect:dirtyRect];
211 }
212 }
213
214 /* Todo: lazy design, make it use a delegate instead of having a gb reference*/
215
216 - (void)insertTab:(id)sender
217 {
218 if (auto_complete_context == 0) {
219 NSRange selection = self.selectedRange;
220 if (selection.length) {
221 [self delete:nil];
222 }
223 auto_complete_range = NSMakeRange(selection.location, 0);
224 }
225 char *substring = strdup([self.string substringToIndex:auto_complete_range.location].UTF8String);
226 uintptr_t context = auto_complete_context;
227 char *completion = GB_debugger_complete_substring(self.gb, substring, &context);
228 free(substring);
229 if (completion) {
230 NSString *ns_completion = @(completion);
231 free(completion);
232 if (!ns_completion) {
233 goto error;
234 }
235 self.selectedRange = auto_complete_range;
236 auto_complete_range.length = ns_completion.length;
237 [self replaceCharactersInRange:self.selectedRange withString:ns_completion];
238 auto_complete_context = context;
239 return;
240 }
241 error:
242 auto_complete_context = context;
243 NSBeep();
244 }
245
246 @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.