trunk/src/osd/modules/debugger/osx/debugosxdebugview.m
| r243534 | r243535 | |
| 58 | 58 | |
| 59 | 59 | - (debug_view_xy)convertLocation:(NSPoint)location { |
| 60 | 60 | debug_view_xy position; |
| 61 | | position.x = lround(floor(location.x / fontWidth)); |
| 61 | |
| 62 | 62 | position.y = lround(floor(location.y / fontHeight)); |
| 63 | if (position.y < 0) |
| 64 | position.y = 0; |
| 65 | else if (position.y >= totalHeight) |
| 66 | position.y = totalHeight - 1; |
| 67 | |
| 68 | debug_view_xy const origin = view->visible_position(); |
| 69 | debug_view_xy const size = view->visible_size(); |
| 70 | debug_view_char const *data = view->viewdata(); |
| 71 | if (!data || (position.y < origin.y) || (position.y >= origin.y + size.y)) |
| 72 | { |
| 73 | // y coordinate outside visible area, x will be a guess |
| 74 | position.x = lround(floor(location.x / fontWidth)); |
| 75 | } |
| 76 | else |
| 77 | { |
| 78 | data += ((position.y - view->visible_position().y) * view->visible_size().x); |
| 79 | int attr = -1; |
| 80 | NSUInteger start = 0, length = 0; |
| 81 | for (UINT32 col = origin.x; col < origin.x + size.x; col++) |
| 82 | { |
| 83 | [[text mutableString] appendFormat:@"%c", data[col - origin.x].byte]; |
| 84 | if ((start < length) && (attr != data[col - origin.x].attrib)) |
| 85 | { |
| 86 | NSRange const run = NSMakeRange(start, length - start); |
| 87 | [text addAttribute:NSFontAttributeName |
| 88 | value:font |
| 89 | range:NSMakeRange(0, length)]; |
| 90 | [text addAttribute:NSForegroundColorAttributeName |
| 91 | value:[self foregroundForAttribute:attr] |
| 92 | range:run]; |
| 93 | start = length; |
| 94 | } |
| 95 | attr = data[col - origin.x].attrib; |
| 96 | length = [text length]; |
| 97 | } |
| 98 | if (start < length) |
| 99 | { |
| 100 | NSRange const run = NSMakeRange(start, length - start); |
| 101 | [text addAttribute:NSFontAttributeName |
| 102 | value:font |
| 103 | range:NSMakeRange(0, length)]; |
| 104 | [text addAttribute:NSForegroundColorAttributeName |
| 105 | value:[self foregroundForAttribute:attr] |
| 106 | range:run]; |
| 107 | } |
| 108 | CGFloat fraction; |
| 109 | NSUInteger const glyph = [layoutManager glyphIndexForPoint:NSMakePoint(location.x, fontHeight / 2) |
| 110 | inTextContainer:textContainer |
| 111 | fractionOfDistanceThroughGlyph:&fraction]; |
| 112 | position.x = [layoutManager characterIndexForGlyphAtIndex:glyph]; // FIXME: assumes 1:1 character mapping |
| 113 | } |
| 63 | 114 | if (position.x < 0) |
| 64 | 115 | position.x = 0; |
| 65 | 116 | else if (position.x >= totalWidth) |
| 66 | 117 | position.x = totalWidth - 1; |
| 67 | | if (position.y < 0) |
| 68 | | position.y = 0; |
| 69 | | else if (position.y >= totalHeight) |
| 70 | | position.y = totalHeight - 1; |
| 118 | |
| 71 | 119 | return position; |
| 72 | 120 | } |
| 73 | 121 | |
| r243534 | r243535 | |
| 75 | 123 | - (void)convertBounds:(NSRect)b toPosition:(debug_view_xy *)origin size:(debug_view_xy *)size { |
| 76 | 124 | origin->x = lround(floor(b.origin.x / fontWidth)); |
| 77 | 125 | origin->y = lround(floor(b.origin.y / fontHeight)); |
| 126 | |
| 127 | // FIXME: this is not using proper font metrics horizontally |
| 78 | 128 | size->x = lround(ceil((b.origin.x + b.size.width) / fontWidth)) - origin->x; |
| 79 | 129 | size->y = lround(ceil((b.origin.y + b.size.height) / fontHeight)) - origin->y; |
| 80 | 130 | } |
| r243534 | r243535 | |
| 107 | 157 | { |
| 108 | 158 | debug_view_xy newPos = view->cursor_position(); |
| 109 | 159 | if ((newPos.x != oldPos.x) || (newPos.y != oldPos.y)) { |
| 110 | | [self scrollRectToVisible:NSMakeRect(newPos.x * fontWidth, |
| 160 | [self scrollRectToVisible:NSMakeRect(newPos.x * fontWidth, // FIXME - use proper metrics |
| 111 | 161 | newPos.y * fontHeight, |
| 112 | 162 | fontWidth, |
| 113 | 163 | fontHeight)]; |
| r243534 | r243535 | |
| 120 | 170 | |
| 121 | 171 | |
| 122 | 172 | + (NSFont *)defaultFont { |
| 123 | | // maybe we should get the configured system fixed-width font... |
| 124 | | return [NSFont fontWithName:@"Monaco" size:10]; |
| 173 | return [NSFont userFixedPitchFontOfSize:0]; |
| 125 | 174 | } |
| 126 | 175 | |
| 127 | 176 | |
| r243534 | r243535 | |
| 138 | 187 | totalWidth = totalHeight = 0; |
| 139 | 188 | originLeft = originTop = 0; |
| 140 | 189 | [self setFont:[[self class] defaultFont]]; |
| 190 | text = [[NSTextStorage alloc] init]; |
| 191 | textContainer = [[NSTextContainer alloc] init]; |
| 192 | layoutManager = [[NSLayoutManager alloc] init]; |
| 193 | [layoutManager addTextContainer:textContainer]; |
| 194 | [text addLayoutManager:layoutManager]; |
| 141 | 195 | return self; |
| 142 | 196 | } |
| 143 | 197 | |
| 144 | 198 | |
| 145 | 199 | - (void)dealloc { |
| 146 | 200 | [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 147 | | if (font != nil) |
| 148 | | [font release]; |
| 201 | if (font != nil) [font release]; |
| 202 | if (text != nil) [text release]; |
| 203 | if (textContainer != nil) [textContainer release]; |
| 204 | if (layoutManager != nil) [layoutManager release]; |
| 149 | 205 | [super dealloc]; |
| 150 | 206 | } |
| 151 | 207 | |
| r243534 | r243535 | |
| 156 | 212 | // resize our frame if the total size has changed |
| 157 | 213 | newSize = view->total_size(); |
| 158 | 214 | if ((newSize.x != totalWidth) || (newSize.y != totalHeight)) { |
| 159 | | [self setFrameSize:NSMakeSize(fontWidth * newSize.x, fontHeight * newSize.y)]; |
| 215 | [self setFrameSize:NSMakeSize(fontWidth * newSize.x, fontHeight * newSize.y)]; // FIXME: metrics |
| 160 | 216 | totalWidth = newSize.x; |
| 161 | 217 | totalHeight = newSize.y; |
| 162 | 218 | } |
| r243534 | r243535 | |
| 221 | 277 | debug_view_xy pos; |
| 222 | 278 | view->set_cursor_visible(true); |
| 223 | 279 | pos = view->cursor_position(); |
| 224 | | [self scrollRectToVisible:NSMakeRect(pos.x * fontWidth, pos.y * fontHeight, fontWidth, fontHeight)]; |
| 280 | [self scrollRectToVisible:NSMakeRect(pos.x * fontWidth, pos.y * fontHeight, fontWidth, fontHeight)]; // FIXME: metrics |
| 225 | 281 | [self setNeedsDisplay:YES]; |
| 226 | 282 | return [super becomeFirstResponder]; |
| 227 | 283 | } else { |
| r243534 | r243535 | |
| 266 | 322 | |
| 267 | 323 | |
| 268 | 324 | - (void)drawRect:(NSRect)dirtyRect { |
| 269 | | const debug_view_char *base; |
| 270 | | debug_view_xy origin, size; |
| 271 | | debug_view_xy position, clip; |
| 272 | | NSMutableString *text; |
| 273 | | NSMutableDictionary *attributes; |
| 274 | | UINT32 pass, row, col; |
| 325 | debug_view_xy position, clip; |
| 275 | 326 | |
| 276 | 327 | // work out how much we need to draw |
| 277 | 328 | [self recomputeVisible]; |
| 278 | | origin = view->visible_position(); |
| 279 | | size = view->visible_size(); |
| 329 | debug_view_xy const origin = view->visible_position(); |
| 330 | debug_view_xy const size = view->visible_size(); |
| 280 | 331 | [self convertBounds:dirtyRect toPosition:&position size:&clip]; |
| 281 | 332 | |
| 282 | 333 | // this gets the text for the whole visible area |
| 283 | | base = view->viewdata(); |
| 284 | | if (!base) |
| 334 | debug_view_char const *data = view->viewdata(); |
| 335 | if (!data) |
| 285 | 336 | return; |
| 286 | 337 | |
| 287 | | text = [[NSMutableString alloc] initWithCapacity:clip.x]; |
| 288 | | attributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:font, NSFontAttributeName, nil]; |
| 289 | | for (pass = 0; pass < 2; pass++) { |
| 290 | | const debug_view_char *data = base + ((position.y - origin.y) * size.x); |
| 291 | | for (row = position.y; row < position.y + clip.y; row++, data += size.x) { |
| 292 | | int attr = -1; |
| 338 | data += ((position.y - origin.y) * size.x); |
| 339 | for (UINT32 row = position.y; row < position.y + clip.y; row++, data += size.x) |
| 340 | { |
| 341 | if ((row < origin.y) || (row >= origin.y + size.y)) |
| 342 | continue; |
| 293 | 343 | |
| 294 | | if ((row < origin.y) || (row >= origin.y + size.y)) |
| 295 | | continue; |
| 296 | | |
| 297 | | // render entire lines to get character alignment right |
| 298 | | for (col = origin.x; col < origin.x + size.x; col++) { |
| 299 | | if ((attr != data[col - origin.x].attrib) && ([text length] > 0)) { |
| 300 | | if (pass == 0) { |
| 301 | | [[self backgroundForAttribute:attr] set]; |
| 302 | | [NSBezierPath fillRect:NSMakeRect((col - [text length]) * fontWidth, |
| 303 | | row * fontHeight, |
| 304 | | [text length] * fontWidth, |
| 305 | | fontHeight)]; |
| 306 | | } else { |
| 307 | | [attributes setObject:[self foregroundForAttribute:attr] |
| 308 | | forKey:NSForegroundColorAttributeName]; |
| 309 | | [text drawAtPoint:NSMakePoint((col - [text length]) * fontWidth, row * fontHeight) |
| 310 | | withAttributes:attributes]; |
| 311 | | } |
| 312 | | [text setString:@""]; |
| 313 | | } |
| 314 | | attr = data[col - origin.x].attrib; |
| 315 | | [text appendFormat:@"%c", data[col - origin.x].byte]; |
| 344 | // render entire lines to get character alignment right |
| 345 | int attr = -1; |
| 346 | NSUInteger start = 0, length = 0; |
| 347 | for (UINT32 col = origin.x; col < origin.x + size.x; col++) |
| 348 | { |
| 349 | [[text mutableString] appendFormat:@"%c", data[col - origin.x].byte]; |
| 350 | if ((start < length) && (attr != data[col - origin.x].attrib)) |
| 351 | { |
| 352 | NSRange const run = NSMakeRange(start, length - start); |
| 353 | [text addAttribute:NSFontAttributeName |
| 354 | value:font |
| 355 | range:NSMakeRange(0, length)]; |
| 356 | [text addAttribute:NSForegroundColorAttributeName |
| 357 | value:[self foregroundForAttribute:attr] |
| 358 | range:run]; |
| 359 | NSRange const glyphs = [layoutManager glyphRangeForCharacterRange:run |
| 360 | actualCharacterRange:NULL]; |
| 361 | NSRect const box = [layoutManager boundingRectForGlyphRange:glyphs |
| 362 | inTextContainer:textContainer]; |
| 363 | [[self backgroundForAttribute:attr] set]; |
| 364 | [NSBezierPath fillRect:NSMakeRect(box.origin.x, |
| 365 | row * fontHeight, |
| 366 | box.size.width, |
| 367 | fontHeight)]; |
| 368 | start = length; |
| 316 | 369 | } |
| 317 | | if ([text length] > 0) { |
| 318 | | if (pass == 0) { |
| 319 | | [[self backgroundForAttribute:attr] set]; |
| 320 | | [NSBezierPath fillRect:NSMakeRect((col - [text length]) * fontWidth, |
| 321 | | row * fontHeight, |
| 322 | | [text length] * fontWidth, |
| 323 | | fontHeight)]; |
| 324 | | } else { |
| 325 | | [attributes setObject:[self foregroundForAttribute:attr] |
| 326 | | forKey:NSForegroundColorAttributeName]; |
| 327 | | [text drawAtPoint:NSMakePoint((col - [text length]) * fontWidth, row * fontHeight) |
| 328 | | withAttributes:attributes]; |
| 329 | | } |
| 330 | | [text setString:@""]; |
| 331 | | } |
| 370 | attr = data[col - origin.x].attrib; |
| 371 | length = [text length]; |
| 332 | 372 | } |
| 373 | if (start < length) |
| 374 | { |
| 375 | NSRange const run = NSMakeRange(start, length - start); |
| 376 | [text addAttribute:NSFontAttributeName |
| 377 | value:font |
| 378 | range:NSMakeRange(0, length)]; |
| 379 | [text addAttribute:NSForegroundColorAttributeName |
| 380 | value:[self foregroundForAttribute:attr] |
| 381 | range:run]; |
| 382 | NSRange const glyphs = [layoutManager glyphRangeForCharacterRange:run |
| 383 | actualCharacterRange:NULL]; |
| 384 | NSRect const box = [layoutManager boundingRectForGlyphRange:glyphs |
| 385 | inTextContainer:textContainer]; |
| 386 | [[self backgroundForAttribute:attr] set]; |
| 387 | [NSBezierPath fillRect:NSMakeRect(box.origin.x, |
| 388 | row * fontHeight, |
| 389 | box.size.width, |
| 390 | fontHeight)]; |
| 391 | } |
| 392 | [layoutManager drawGlyphsForGlyphRange:[layoutManager glyphRangeForTextContainer:textContainer] |
| 393 | atPoint:NSMakePoint(0, row * fontHeight)]; |
| 394 | [text deleteCharactersInRange:NSMakeRange(0, length)]; |
| 333 | 395 | } |
| 334 | | [attributes release]; |
| 335 | | [text release]; |
| 336 | 396 | } |
| 337 | 397 | |
| 338 | 398 | |