trunk/src/osd/modules/debugger/osx/debugconsole.m
| r0 | r243596 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:Vas Crabb |
| 3 | //============================================================ |
| 4 | // |
| 5 | // debugosxdebugconsole.m - MacOS X Cocoa debug window handling |
| 6 | // |
| 7 | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | // |
| 10 | //============================================================ |
| 11 | |
| 12 | #import "debugconsole.h" |
| 13 | |
| 14 | #import "debugcommandhistory.h" |
| 15 | #import "consoleview.h" |
| 16 | #import "debugview.h" |
| 17 | #import "disassemblyview.h" |
| 18 | #import "disassemblyviewer.h" |
| 19 | #import "errorlogviewer.h" |
| 20 | #import "memoryviewer.h" |
| 21 | #import "pointsviewer.h" |
| 22 | #import "registersview.h" |
| 23 | |
| 24 | #include "debug/debugcon.h" |
| 25 | #include "debug/debugcpu.h" |
| 26 | |
| 27 | |
| 28 | @implementation MAMEDebugConsole |
| 29 | |
| 30 | - (id)initWithMachine:(running_machine &)m { |
| 31 | NSSplitView *regSplit, *dasmSplit; |
| 32 | NSScrollView *regScroll, *dasmScroll, *consoleScroll; |
| 33 | NSView *consoleContainer; |
| 34 | NSPopUpButton *actionButton; |
| 35 | NSRect rct; |
| 36 | |
| 37 | // initialise superclass |
| 38 | if (!(self = [super initWithMachine:m title:@"Debug"])) |
| 39 | return nil; |
| 40 | history = [[MAMEDebugCommandHistory alloc] init]; |
| 41 | auxiliaryWindows = [[NSMutableArray alloc] init]; |
| 42 | |
| 43 | // create the register view |
| 44 | regView = [[MAMERegistersView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine]; |
| 45 | regScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 46 | [regScroll setDrawsBackground:YES]; |
| 47 | [regScroll setHasHorizontalScroller:YES]; |
| 48 | [regScroll setHasVerticalScroller:YES]; |
| 49 | [regScroll setAutohidesScrollers:YES]; |
| 50 | [regScroll setBorderType:NSBezelBorder]; |
| 51 | [regScroll setDocumentView:regView]; |
| 52 | [regView release]; |
| 53 | |
| 54 | // create the disassembly view |
| 55 | dasmView = [[MAMEDisassemblyView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) |
| 56 | machine:*machine |
| 57 | useConsole:YES]; |
| 58 | [dasmView setExpression:@"curpc"]; |
| 59 | dasmScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 60 | [dasmScroll setDrawsBackground:YES]; |
| 61 | [dasmScroll setHasHorizontalScroller:YES]; |
| 62 | [dasmScroll setHasVerticalScroller:YES]; |
| 63 | [dasmScroll setAutohidesScrollers:YES]; |
| 64 | [dasmScroll setBorderType:NSBezelBorder]; |
| 65 | [dasmScroll setDocumentView:dasmView]; |
| 66 | [dasmView release]; |
| 67 | |
| 68 | // create the console view |
| 69 | consoleView = [[MAMEConsoleView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine]; |
| 70 | consoleScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 71 | [consoleScroll setDrawsBackground:YES]; |
| 72 | [consoleScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 73 | [consoleScroll setHasHorizontalScroller:YES]; |
| 74 | [consoleScroll setHasVerticalScroller:YES]; |
| 75 | [consoleScroll setAutohidesScrollers:YES]; |
| 76 | [consoleScroll setBorderType:NSBezelBorder]; |
| 77 | [consoleScroll setDocumentView:consoleView]; |
| 78 | [consoleView release]; |
| 79 | |
| 80 | // create the command field |
| 81 | commandField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)]; |
| 82 | [commandField setAutoresizingMask:(NSViewWidthSizable | NSViewMaxYMargin)]; |
| 83 | [commandField setFont:[[MAMEDebugView class] defaultFont]]; |
| 84 | [commandField setFocusRingType:NSFocusRingTypeNone]; |
| 85 | [commandField setTarget:self]; |
| 86 | [commandField setAction:@selector(doCommand:)]; |
| 87 | [commandField setDelegate:self]; |
| 88 | rct = [commandField frame]; |
| 89 | [commandField setFrame:NSMakeRect(rct.size.height, 0, rct.size.width - rct.size.height, rct.size.height)]; |
| 90 | |
| 91 | // create the action pull-down button |
| 92 | actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0, 0, rct.size.height, rct.size.height)]; |
| 93 | [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMaxYMargin)]; |
| 94 | [dasmView insertActionItemsInMenu:[actionButton menu] atIndex:1]; |
| 95 | |
| 96 | // create the container for the console and command input field |
| 97 | consoleContainer = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 98 | [consoleScroll setFrame:NSMakeRect(0, |
| 99 | rct.size.height, |
| 100 | 100, |
| 101 | [consoleContainer bounds].size.height - rct.size.height)]; |
| 102 | [consoleContainer addSubview:consoleScroll]; |
| 103 | [consoleContainer addSubview:commandField]; |
| 104 | [consoleContainer addSubview:actionButton]; |
| 105 | [consoleScroll release]; |
| 106 | [commandField release]; |
| 107 | [actionButton release]; |
| 108 | |
| 109 | // create the split between the disassembly and the console |
| 110 | dasmSplit = [[NSSplitView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 111 | [dasmSplit setDelegate:self]; |
| 112 | [dasmSplit setVertical:NO]; |
| 113 | [dasmSplit addSubview:dasmScroll]; |
| 114 | [dasmSplit addSubview:consoleContainer]; |
| 115 | [dasmScroll release]; |
| 116 | [consoleContainer release]; |
| 117 | |
| 118 | // create the split between the registers and the console |
| 119 | regSplit = [[NSSplitView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 120 | [regSplit setDelegate:self]; |
| 121 | [regSplit setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 122 | [regSplit setVertical:YES]; |
| 123 | [regSplit addSubview:regScroll]; |
| 124 | [regSplit addSubview:dasmSplit]; |
| 125 | [regScroll release]; |
| 126 | [dasmSplit release]; |
| 127 | |
| 128 | // put the split views in the window and get them into a half-reasonable state |
| 129 | [window setContentView:regSplit]; |
| 130 | [regSplit release]; |
| 131 | [regSplit adjustSubviews]; |
| 132 | [dasmSplit adjustSubviews]; |
| 133 | |
| 134 | // keyboard focus should start on the command field |
| 135 | [window makeFirstResponder:commandField]; |
| 136 | |
| 137 | // calculate the optimal size for everything |
| 138 | { |
| 139 | NSRect available = [[NSScreen mainScreen] visibleFrame]; |
| 140 | NSRect windowFrame = [window frame]; |
| 141 | NSSize regCurrent = [regScroll frame].size; |
| 142 | NSSize regSize = [NSScrollView frameSizeForContentSize:[regView maximumFrameSize] |
| 143 | hasHorizontalScroller:YES |
| 144 | hasVerticalScroller:YES |
| 145 | borderType:[regScroll borderType]]; |
| 146 | NSSize dasmCurrent = [dasmScroll frame].size; |
| 147 | NSSize dasmSize = [NSScrollView frameSizeForContentSize:[dasmView maximumFrameSize] |
| 148 | hasHorizontalScroller:YES |
| 149 | hasVerticalScroller:YES |
| 150 | borderType:[dasmScroll borderType]]; |
| 151 | NSSize consoleCurrent = [consoleContainer frame].size; |
| 152 | NSSize consoleSize = [NSScrollView frameSizeForContentSize:[consoleView maximumFrameSize] |
| 153 | hasHorizontalScroller:YES |
| 154 | hasVerticalScroller:YES |
| 155 | borderType:[consoleScroll borderType]]; |
| 156 | NSSize adjustment; |
| 157 | NSRect lhsFrame, rhsFrame; |
| 158 | |
| 159 | consoleSize.width += consoleCurrent.width - [consoleScroll frame].size.width; |
| 160 | consoleSize.height += consoleCurrent.height - [consoleScroll frame].size.height; |
| 161 | adjustment.width = regSize.width - regCurrent.width; |
| 162 | adjustment.height = regSize.height - regCurrent.height; |
| 163 | adjustment.width += MAX(dasmSize.width - dasmCurrent.width, consoleSize.width - consoleCurrent.width); |
| 164 | |
| 165 | windowFrame.size.width += adjustment.width; |
| 166 | windowFrame.size.height += adjustment.height; // not used - better to go for fixed height |
| 167 | windowFrame.size.height = MIN(512.0, available.size.height); |
| 168 | windowFrame.size.width = MIN(windowFrame.size.width, available.size.width); |
| 169 | windowFrame.origin.x = available.origin.x + available.size.width - windowFrame.size.width; |
| 170 | windowFrame.origin.y = available.origin.y; |
| 171 | [window setFrame:windowFrame display:YES]; |
| 172 | |
| 173 | lhsFrame = [regScroll frame]; |
| 174 | rhsFrame = [dasmSplit frame]; |
| 175 | adjustment.width = MIN(regSize.width, ([regSplit frame].size.width - [regSplit dividerThickness]) / 2); |
| 176 | rhsFrame.origin.x -= lhsFrame.size.width - adjustment.width; |
| 177 | rhsFrame.size.width += lhsFrame.size.width - adjustment.width; |
| 178 | lhsFrame.size.width = adjustment.width; |
| 179 | [regScroll setFrame:lhsFrame]; |
| 180 | [dasmSplit setFrame:rhsFrame]; |
| 181 | } |
| 182 | |
| 183 | // select the current processor |
| 184 | [self setCPU:machine->firstcpu]; |
| 185 | |
| 186 | [[NSNotificationCenter defaultCenter] addObserver:self |
| 187 | selector:@selector(auxiliaryWindowWillClose:) |
| 188 | name:MAMEAuxiliaryDebugWindowWillCloseNotification |
| 189 | object:nil]; |
| 190 | |
| 191 | // don't forget the return value |
| 192 | return self; |
| 193 | } |
| 194 | |
| 195 | |
| 196 | - (void)dealloc { |
| 197 | [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 198 | |
| 199 | if (history != nil) |
| 200 | [history release]; |
| 201 | if (auxiliaryWindows != nil) |
| 202 | [auxiliaryWindows release]; |
| 203 | |
| 204 | [super dealloc]; |
| 205 | } |
| 206 | |
| 207 | |
| 208 | - (void)setCPU:(device_t *)device { |
| 209 | [regView selectSubviewForCPU:device]; |
| 210 | [dasmView selectSubviewForCPU:device]; |
| 211 | [window setTitle:[NSString stringWithFormat:@"Debug: %s - %s '%s'", |
| 212 | device->machine().system().name, |
| 213 | device->name(), |
| 214 | device->tag()]]; |
| 215 | } |
| 216 | |
| 217 | |
| 218 | - (IBAction)doCommand:(id)sender { |
| 219 | NSString *command = [sender stringValue]; |
| 220 | if ([command length] == 0) { |
| 221 | debug_cpu_get_visible_cpu(*machine)->debug()->single_step(); |
| 222 | [history reset]; |
| 223 | } else { |
| 224 | debug_console_execute_command(*machine, [command UTF8String], 1); |
| 225 | [history add:command]; |
| 226 | [history edit]; |
| 227 | } |
| 228 | [sender setStringValue:@""]; |
| 229 | } |
| 230 | |
| 231 | |
| 232 | - (IBAction)debugNewMemoryWindow:(id)sender { |
| 233 | MAMEMemoryViewer *win = [[MAMEMemoryViewer alloc] initWithMachine:*machine console:self]; |
| 234 | [auxiliaryWindows addObject:win]; |
| 235 | [win release]; |
| 236 | [win activate]; |
| 237 | } |
| 238 | |
| 239 | |
| 240 | - (IBAction)debugNewDisassemblyWindow:(id)sender { |
| 241 | MAMEDisassemblyViewer *win = [[MAMEDisassemblyViewer alloc] initWithMachine:*machine console:self]; |
| 242 | [auxiliaryWindows addObject:win]; |
| 243 | [win release]; |
| 244 | [win activate]; |
| 245 | } |
| 246 | |
| 247 | |
| 248 | - (IBAction)debugNewErrorLogWindow:(id)sender { |
| 249 | MAMEErrorLogViewer *win = [[MAMEErrorLogViewer alloc] initWithMachine:*machine console:self]; |
| 250 | [auxiliaryWindows addObject:win]; |
| 251 | [win release]; |
| 252 | [win activate]; |
| 253 | } |
| 254 | |
| 255 | |
| 256 | - (IBAction)debugNewPointsWindow:(id)sender{ |
| 257 | MAMEPointsViewer *win = [[MAMEPointsViewer alloc] initWithMachine:*machine console:self]; |
| 258 | [auxiliaryWindows addObject:win]; |
| 259 | [win release]; |
| 260 | [win activate]; |
| 261 | } |
| 262 | |
| 263 | |
| 264 | - (void)showDebugger:(NSNotification *)notification { |
| 265 | device_t *device = (device_t * )[[[notification userInfo] objectForKey:@"MAMEDebugDevice"] pointerValue]; |
| 266 | if (&device->machine() == machine) { |
| 267 | [self setCPU:device]; |
| 268 | [window makeKeyAndOrderFront:self]; |
| 269 | } |
| 270 | } |
| 271 | |
| 272 | |
| 273 | - (void)auxiliaryWindowWillClose:(NSNotification *)notification { |
| 274 | [auxiliaryWindows removeObjectIdenticalTo:[notification object]]; |
| 275 | } |
| 276 | |
| 277 | |
| 278 | - (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor { |
| 279 | if (control == commandField) |
| 280 | [history edit]; |
| 281 | |
| 282 | return YES; |
| 283 | } |
| 284 | |
| 285 | |
| 286 | - (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command { |
| 287 | if (control == commandField) { |
| 288 | if (command == @selector(cancelOperation:)) { |
| 289 | [commandField setStringValue:@""]; |
| 290 | [history reset]; |
| 291 | return YES; |
| 292 | } else if (command == @selector(moveUp:)) { |
| 293 | NSString *hist = [history previous:[commandField stringValue]]; |
| 294 | if (hist != nil) { |
| 295 | [commandField setStringValue:hist]; |
| 296 | [commandField selectText:self]; |
| 297 | [(NSText *)[window firstResponder] setSelectedRange:NSMakeRange([hist length], 0)]; |
| 298 | } |
| 299 | return YES; |
| 300 | } else if (command == @selector(moveDown:)) { |
| 301 | NSString *hist = [history next:[commandField stringValue]]; |
| 302 | if (hist != nil) { |
| 303 | [commandField setStringValue:hist]; |
| 304 | [commandField selectText:self]; |
| 305 | [(NSText *)[window firstResponder] setSelectedRange:NSMakeRange([hist length], 0)]; |
| 306 | } |
| 307 | return YES; |
| 308 | } |
| 309 | } |
| 310 | return NO; |
| 311 | } |
| 312 | |
| 313 | |
| 314 | - (void)windowWillClose:(NSNotification *)notification { |
| 315 | if ([notification object] != window) |
| 316 | return; |
| 317 | [[NSNotificationCenter defaultCenter] postNotificationName:MAMEHideDebuggerNotification object:self]; |
| 318 | debug_cpu_get_visible_cpu(*machine)->debug()->go(); |
| 319 | } |
| 320 | |
| 321 | |
| 322 | - (CGFloat)splitView:(NSSplitView *)sender constrainMinCoordinate:(CGFloat)min ofSubviewAt:(NSInteger)offs { |
| 323 | return (min < 100) ? 100 : min; |
| 324 | } |
| 325 | |
| 326 | |
| 327 | - (CGFloat)splitView:(NSSplitView *)sender constrainMaxCoordinate:(CGFloat)max ofSubviewAt:(NSInteger)offs { |
| 328 | NSSize sz = [sender bounds].size; |
| 329 | CGFloat allowed = ([sender isVertical] ? sz.width : sz.height) - 100 - [sender dividerThickness]; |
| 330 | return (max > allowed) ? allowed : max; |
| 331 | } |
| 332 | |
| 333 | |
| 334 | - (BOOL)splitView:(NSSplitView *)sender canCollapseSubview:(NSView *)subview { |
| 335 | // allow registers or disassembly to be collapsed, but not console |
| 336 | return [[sender subviews] indexOfObjectIdenticalTo:subview] == 0; |
| 337 | } |
| 338 | |
| 339 | |
| 340 | - (void)splitView:(NSSplitView *)sender resizeSubviewsWithOldSize:(NSSize)oldSize { |
| 341 | // This can only deal with a single split, but that's all we use, anyway |
| 342 | NSRect first, second; |
| 343 | [sender adjustSubviews]; |
| 344 | first = [[[sender subviews] objectAtIndex:0] frame]; |
| 345 | second = [[[sender subviews] objectAtIndex:1] frame]; |
| 346 | if ([sender isVertical]) { |
| 347 | if (first.size.width < 100) { |
| 348 | CGFloat diff = 100 - first.size.width; |
| 349 | first.size.width = 100; |
| 350 | second.origin.x += diff; |
| 351 | second.size.width -= diff; |
| 352 | } else if (second.size.width < 100) { |
| 353 | CGFloat diff = 100 - second.size.width; |
| 354 | second.size.width = 100; |
| 355 | second.origin.x -= diff; |
| 356 | first.size.width -= diff; |
| 357 | } |
| 358 | } else { |
| 359 | if (first.size.height < 100) { |
| 360 | CGFloat diff = 100 - first.size.height; |
| 361 | first.size.height = 100; |
| 362 | second.origin.y += diff; |
| 363 | second.size.height -= diff; |
| 364 | } else if (second.size.height < 100) { |
| 365 | CGFloat diff = 100 - second.size.height; |
| 366 | second.size.height = 100; |
| 367 | second.origin.y -= diff; |
| 368 | first.size.height -= diff; |
| 369 | } |
| 370 | } |
| 371 | [[[sender subviews] objectAtIndex:0] setFrame:first]; |
| 372 | [[[sender subviews] objectAtIndex:1] setFrame:second]; |
| 373 | } |
| 374 | |
| 375 | @end |
trunk/src/osd/modules/debugger/osx/debugosxdebugconsole.m
| r243595 | r243596 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // debugosxdebugconsole.m - MacOS X Cocoa debug window handling |
| 6 | | // |
| 7 | | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | | // |
| 10 | | //============================================================ |
| 11 | | |
| 12 | | #import "debugosxdebugconsole.h" |
| 13 | | |
| 14 | | #import "debugosxdebugcommandhistory.h" |
| 15 | | #import "debugosxconsoleview.h" |
| 16 | | #import "debugosxdebugview.h" |
| 17 | | #import "debugosxdisassemblyview.h" |
| 18 | | #import "debugosxdisassemblyviewer.h" |
| 19 | | #import "debugosxerrorlogviewer.h" |
| 20 | | #import "debugosxmemoryviewer.h" |
| 21 | | #import "debugosxpointsviewer.h" |
| 22 | | #import "debugosxregistersview.h" |
| 23 | | |
| 24 | | #include "debug/debugcon.h" |
| 25 | | #include "debug/debugcpu.h" |
| 26 | | |
| 27 | | |
| 28 | | @implementation MAMEDebugConsole |
| 29 | | |
| 30 | | - (id)initWithMachine:(running_machine &)m { |
| 31 | | NSSplitView *regSplit, *dasmSplit; |
| 32 | | NSScrollView *regScroll, *dasmScroll, *consoleScroll; |
| 33 | | NSView *consoleContainer; |
| 34 | | NSPopUpButton *actionButton; |
| 35 | | NSRect rct; |
| 36 | | |
| 37 | | // initialise superclass |
| 38 | | if (!(self = [super initWithMachine:m title:@"Debug"])) |
| 39 | | return nil; |
| 40 | | history = [[MAMEDebugCommandHistory alloc] init]; |
| 41 | | auxiliaryWindows = [[NSMutableArray alloc] init]; |
| 42 | | |
| 43 | | // create the register view |
| 44 | | regView = [[MAMERegistersView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine]; |
| 45 | | regScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 46 | | [regScroll setDrawsBackground:YES]; |
| 47 | | [regScroll setHasHorizontalScroller:YES]; |
| 48 | | [regScroll setHasVerticalScroller:YES]; |
| 49 | | [regScroll setAutohidesScrollers:YES]; |
| 50 | | [regScroll setBorderType:NSBezelBorder]; |
| 51 | | [regScroll setDocumentView:regView]; |
| 52 | | [regView release]; |
| 53 | | |
| 54 | | // create the disassembly view |
| 55 | | dasmView = [[MAMEDisassemblyView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) |
| 56 | | machine:*machine |
| 57 | | useConsole:YES]; |
| 58 | | [dasmView setExpression:@"curpc"]; |
| 59 | | dasmScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 60 | | [dasmScroll setDrawsBackground:YES]; |
| 61 | | [dasmScroll setHasHorizontalScroller:YES]; |
| 62 | | [dasmScroll setHasVerticalScroller:YES]; |
| 63 | | [dasmScroll setAutohidesScrollers:YES]; |
| 64 | | [dasmScroll setBorderType:NSBezelBorder]; |
| 65 | | [dasmScroll setDocumentView:dasmView]; |
| 66 | | [dasmView release]; |
| 67 | | |
| 68 | | // create the console view |
| 69 | | consoleView = [[MAMEConsoleView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine]; |
| 70 | | consoleScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 71 | | [consoleScroll setDrawsBackground:YES]; |
| 72 | | [consoleScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 73 | | [consoleScroll setHasHorizontalScroller:YES]; |
| 74 | | [consoleScroll setHasVerticalScroller:YES]; |
| 75 | | [consoleScroll setAutohidesScrollers:YES]; |
| 76 | | [consoleScroll setBorderType:NSBezelBorder]; |
| 77 | | [consoleScroll setDocumentView:consoleView]; |
| 78 | | [consoleView release]; |
| 79 | | |
| 80 | | // create the command field |
| 81 | | commandField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)]; |
| 82 | | [commandField setAutoresizingMask:(NSViewWidthSizable | NSViewMaxYMargin)]; |
| 83 | | [commandField setFont:[[MAMEDebugView class] defaultFont]]; |
| 84 | | [commandField setFocusRingType:NSFocusRingTypeNone]; |
| 85 | | [commandField setTarget:self]; |
| 86 | | [commandField setAction:@selector(doCommand:)]; |
| 87 | | [commandField setDelegate:self]; |
| 88 | | rct = [commandField frame]; |
| 89 | | [commandField setFrame:NSMakeRect(rct.size.height, 0, rct.size.width - rct.size.height, rct.size.height)]; |
| 90 | | |
| 91 | | // create the action pull-down button |
| 92 | | actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0, 0, rct.size.height, rct.size.height)]; |
| 93 | | [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMaxYMargin)]; |
| 94 | | [dasmView insertActionItemsInMenu:[actionButton menu] atIndex:1]; |
| 95 | | |
| 96 | | // create the container for the console and command input field |
| 97 | | consoleContainer = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 98 | | [consoleScroll setFrame:NSMakeRect(0, |
| 99 | | rct.size.height, |
| 100 | | 100, |
| 101 | | [consoleContainer bounds].size.height - rct.size.height)]; |
| 102 | | [consoleContainer addSubview:consoleScroll]; |
| 103 | | [consoleContainer addSubview:commandField]; |
| 104 | | [consoleContainer addSubview:actionButton]; |
| 105 | | [consoleScroll release]; |
| 106 | | [commandField release]; |
| 107 | | [actionButton release]; |
| 108 | | |
| 109 | | // create the split between the disassembly and the console |
| 110 | | dasmSplit = [[NSSplitView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 111 | | [dasmSplit setDelegate:self]; |
| 112 | | [dasmSplit setVertical:NO]; |
| 113 | | [dasmSplit addSubview:dasmScroll]; |
| 114 | | [dasmSplit addSubview:consoleContainer]; |
| 115 | | [dasmScroll release]; |
| 116 | | [consoleContainer release]; |
| 117 | | |
| 118 | | // create the split between the registers and the console |
| 119 | | regSplit = [[NSSplitView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 120 | | [regSplit setDelegate:self]; |
| 121 | | [regSplit setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 122 | | [regSplit setVertical:YES]; |
| 123 | | [regSplit addSubview:regScroll]; |
| 124 | | [regSplit addSubview:dasmSplit]; |
| 125 | | [regScroll release]; |
| 126 | | [dasmSplit release]; |
| 127 | | |
| 128 | | // put the split views in the window and get them into a half-reasonable state |
| 129 | | [window setContentView:regSplit]; |
| 130 | | [regSplit release]; |
| 131 | | [regSplit adjustSubviews]; |
| 132 | | [dasmSplit adjustSubviews]; |
| 133 | | |
| 134 | | // keyboard focus should start on the command field |
| 135 | | [window makeFirstResponder:commandField]; |
| 136 | | |
| 137 | | // calculate the optimal size for everything |
| 138 | | { |
| 139 | | NSRect available = [[NSScreen mainScreen] visibleFrame]; |
| 140 | | NSRect windowFrame = [window frame]; |
| 141 | | NSSize regCurrent = [regScroll frame].size; |
| 142 | | NSSize regSize = [NSScrollView frameSizeForContentSize:[regView maximumFrameSize] |
| 143 | | hasHorizontalScroller:YES |
| 144 | | hasVerticalScroller:YES |
| 145 | | borderType:[regScroll borderType]]; |
| 146 | | NSSize dasmCurrent = [dasmScroll frame].size; |
| 147 | | NSSize dasmSize = [NSScrollView frameSizeForContentSize:[dasmView maximumFrameSize] |
| 148 | | hasHorizontalScroller:YES |
| 149 | | hasVerticalScroller:YES |
| 150 | | borderType:[dasmScroll borderType]]; |
| 151 | | NSSize consoleCurrent = [consoleContainer frame].size; |
| 152 | | NSSize consoleSize = [NSScrollView frameSizeForContentSize:[consoleView maximumFrameSize] |
| 153 | | hasHorizontalScroller:YES |
| 154 | | hasVerticalScroller:YES |
| 155 | | borderType:[consoleScroll borderType]]; |
| 156 | | NSSize adjustment; |
| 157 | | NSRect lhsFrame, rhsFrame; |
| 158 | | |
| 159 | | consoleSize.width += consoleCurrent.width - [consoleScroll frame].size.width; |
| 160 | | consoleSize.height += consoleCurrent.height - [consoleScroll frame].size.height; |
| 161 | | adjustment.width = regSize.width - regCurrent.width; |
| 162 | | adjustment.height = regSize.height - regCurrent.height; |
| 163 | | adjustment.width += MAX(dasmSize.width - dasmCurrent.width, consoleSize.width - consoleCurrent.width); |
| 164 | | |
| 165 | | windowFrame.size.width += adjustment.width; |
| 166 | | windowFrame.size.height += adjustment.height; // not used - better to go for fixed height |
| 167 | | windowFrame.size.height = MIN(512.0, available.size.height); |
| 168 | | windowFrame.size.width = MIN(windowFrame.size.width, available.size.width); |
| 169 | | windowFrame.origin.x = available.origin.x + available.size.width - windowFrame.size.width; |
| 170 | | windowFrame.origin.y = available.origin.y; |
| 171 | | [window setFrame:windowFrame display:YES]; |
| 172 | | |
| 173 | | lhsFrame = [regScroll frame]; |
| 174 | | rhsFrame = [dasmSplit frame]; |
| 175 | | adjustment.width = MIN(regSize.width, ([regSplit frame].size.width - [regSplit dividerThickness]) / 2); |
| 176 | | rhsFrame.origin.x -= lhsFrame.size.width - adjustment.width; |
| 177 | | rhsFrame.size.width += lhsFrame.size.width - adjustment.width; |
| 178 | | lhsFrame.size.width = adjustment.width; |
| 179 | | [regScroll setFrame:lhsFrame]; |
| 180 | | [dasmSplit setFrame:rhsFrame]; |
| 181 | | } |
| 182 | | |
| 183 | | // select the current processor |
| 184 | | [self setCPU:machine->firstcpu]; |
| 185 | | |
| 186 | | [[NSNotificationCenter defaultCenter] addObserver:self |
| 187 | | selector:@selector(auxiliaryWindowWillClose:) |
| 188 | | name:MAMEAuxiliaryDebugWindowWillCloseNotification |
| 189 | | object:nil]; |
| 190 | | |
| 191 | | // don't forget the return value |
| 192 | | return self; |
| 193 | | } |
| 194 | | |
| 195 | | |
| 196 | | - (void)dealloc { |
| 197 | | [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 198 | | |
| 199 | | if (history != nil) |
| 200 | | [history release]; |
| 201 | | if (auxiliaryWindows != nil) |
| 202 | | [auxiliaryWindows release]; |
| 203 | | |
| 204 | | [super dealloc]; |
| 205 | | } |
| 206 | | |
| 207 | | |
| 208 | | - (void)setCPU:(device_t *)device { |
| 209 | | [regView selectSubviewForCPU:device]; |
| 210 | | [dasmView selectSubviewForCPU:device]; |
| 211 | | [window setTitle:[NSString stringWithFormat:@"Debug: %s - %s '%s'", |
| 212 | | device->machine().system().name, |
| 213 | | device->name(), |
| 214 | | device->tag()]]; |
| 215 | | } |
| 216 | | |
| 217 | | |
| 218 | | - (IBAction)doCommand:(id)sender { |
| 219 | | NSString *command = [sender stringValue]; |
| 220 | | if ([command length] == 0) { |
| 221 | | debug_cpu_get_visible_cpu(*machine)->debug()->single_step(); |
| 222 | | [history reset]; |
| 223 | | } else { |
| 224 | | debug_console_execute_command(*machine, [command UTF8String], 1); |
| 225 | | [history add:command]; |
| 226 | | [history edit]; |
| 227 | | } |
| 228 | | [sender setStringValue:@""]; |
| 229 | | } |
| 230 | | |
| 231 | | |
| 232 | | - (IBAction)debugNewMemoryWindow:(id)sender { |
| 233 | | MAMEMemoryViewer *win = [[MAMEMemoryViewer alloc] initWithMachine:*machine console:self]; |
| 234 | | [auxiliaryWindows addObject:win]; |
| 235 | | [win release]; |
| 236 | | [win activate]; |
| 237 | | } |
| 238 | | |
| 239 | | |
| 240 | | - (IBAction)debugNewDisassemblyWindow:(id)sender { |
| 241 | | MAMEDisassemblyViewer *win = [[MAMEDisassemblyViewer alloc] initWithMachine:*machine console:self]; |
| 242 | | [auxiliaryWindows addObject:win]; |
| 243 | | [win release]; |
| 244 | | [win activate]; |
| 245 | | } |
| 246 | | |
| 247 | | |
| 248 | | - (IBAction)debugNewErrorLogWindow:(id)sender { |
| 249 | | MAMEErrorLogViewer *win = [[MAMEErrorLogViewer alloc] initWithMachine:*machine console:self]; |
| 250 | | [auxiliaryWindows addObject:win]; |
| 251 | | [win release]; |
| 252 | | [win activate]; |
| 253 | | } |
| 254 | | |
| 255 | | |
| 256 | | - (IBAction)debugNewPointsWindow:(id)sender{ |
| 257 | | MAMEPointsViewer *win = [[MAMEPointsViewer alloc] initWithMachine:*machine console:self]; |
| 258 | | [auxiliaryWindows addObject:win]; |
| 259 | | [win release]; |
| 260 | | [win activate]; |
| 261 | | } |
| 262 | | |
| 263 | | |
| 264 | | - (void)showDebugger:(NSNotification *)notification { |
| 265 | | device_t *device = (device_t * )[[[notification userInfo] objectForKey:@"MAMEDebugDevice"] pointerValue]; |
| 266 | | if (&device->machine() == machine) { |
| 267 | | [self setCPU:device]; |
| 268 | | [window makeKeyAndOrderFront:self]; |
| 269 | | } |
| 270 | | } |
| 271 | | |
| 272 | | |
| 273 | | - (void)auxiliaryWindowWillClose:(NSNotification *)notification { |
| 274 | | [auxiliaryWindows removeObjectIdenticalTo:[notification object]]; |
| 275 | | } |
| 276 | | |
| 277 | | |
| 278 | | - (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor { |
| 279 | | if (control == commandField) |
| 280 | | [history edit]; |
| 281 | | |
| 282 | | return YES; |
| 283 | | } |
| 284 | | |
| 285 | | |
| 286 | | - (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command { |
| 287 | | if (control == commandField) { |
| 288 | | if (command == @selector(cancelOperation:)) { |
| 289 | | [commandField setStringValue:@""]; |
| 290 | | [history reset]; |
| 291 | | return YES; |
| 292 | | } else if (command == @selector(moveUp:)) { |
| 293 | | NSString *hist = [history previous:[commandField stringValue]]; |
| 294 | | if (hist != nil) { |
| 295 | | [commandField setStringValue:hist]; |
| 296 | | [commandField selectText:self]; |
| 297 | | [(NSText *)[window firstResponder] setSelectedRange:NSMakeRange([hist length], 0)]; |
| 298 | | } |
| 299 | | return YES; |
| 300 | | } else if (command == @selector(moveDown:)) { |
| 301 | | NSString *hist = [history next:[commandField stringValue]]; |
| 302 | | if (hist != nil) { |
| 303 | | [commandField setStringValue:hist]; |
| 304 | | [commandField selectText:self]; |
| 305 | | [(NSText *)[window firstResponder] setSelectedRange:NSMakeRange([hist length], 0)]; |
| 306 | | } |
| 307 | | return YES; |
| 308 | | } |
| 309 | | } |
| 310 | | return NO; |
| 311 | | } |
| 312 | | |
| 313 | | |
| 314 | | - (void)windowWillClose:(NSNotification *)notification { |
| 315 | | if ([notification object] != window) |
| 316 | | return; |
| 317 | | [[NSNotificationCenter defaultCenter] postNotificationName:MAMEHideDebuggerNotification object:self]; |
| 318 | | debug_cpu_get_visible_cpu(*machine)->debug()->go(); |
| 319 | | } |
| 320 | | |
| 321 | | |
| 322 | | - (CGFloat)splitView:(NSSplitView *)sender constrainMinCoordinate:(CGFloat)min ofSubviewAt:(NSInteger)offs { |
| 323 | | return (min < 100) ? 100 : min; |
| 324 | | } |
| 325 | | |
| 326 | | |
| 327 | | - (CGFloat)splitView:(NSSplitView *)sender constrainMaxCoordinate:(CGFloat)max ofSubviewAt:(NSInteger)offs { |
| 328 | | NSSize sz = [sender bounds].size; |
| 329 | | CGFloat allowed = ([sender isVertical] ? sz.width : sz.height) - 100 - [sender dividerThickness]; |
| 330 | | return (max > allowed) ? allowed : max; |
| 331 | | } |
| 332 | | |
| 333 | | |
| 334 | | - (BOOL)splitView:(NSSplitView *)sender canCollapseSubview:(NSView *)subview { |
| 335 | | // allow registers or disassembly to be collapsed, but not console |
| 336 | | return [[sender subviews] indexOfObjectIdenticalTo:subview] == 0; |
| 337 | | } |
| 338 | | |
| 339 | | |
| 340 | | - (void)splitView:(NSSplitView *)sender resizeSubviewsWithOldSize:(NSSize)oldSize { |
| 341 | | // This can only deal with a single split, but that's all we use, anyway |
| 342 | | NSRect first, second; |
| 343 | | [sender adjustSubviews]; |
| 344 | | first = [[[sender subviews] objectAtIndex:0] frame]; |
| 345 | | second = [[[sender subviews] objectAtIndex:1] frame]; |
| 346 | | if ([sender isVertical]) { |
| 347 | | if (first.size.width < 100) { |
| 348 | | CGFloat diff = 100 - first.size.width; |
| 349 | | first.size.width = 100; |
| 350 | | second.origin.x += diff; |
| 351 | | second.size.width -= diff; |
| 352 | | } else if (second.size.width < 100) { |
| 353 | | CGFloat diff = 100 - second.size.width; |
| 354 | | second.size.width = 100; |
| 355 | | second.origin.x -= diff; |
| 356 | | first.size.width -= diff; |
| 357 | | } |
| 358 | | } else { |
| 359 | | if (first.size.height < 100) { |
| 360 | | CGFloat diff = 100 - first.size.height; |
| 361 | | first.size.height = 100; |
| 362 | | second.origin.y += diff; |
| 363 | | second.size.height -= diff; |
| 364 | | } else if (second.size.height < 100) { |
| 365 | | CGFloat diff = 100 - second.size.height; |
| 366 | | second.size.height = 100; |
| 367 | | second.origin.y -= diff; |
| 368 | | first.size.height -= diff; |
| 369 | | } |
| 370 | | } |
| 371 | | [[[sender subviews] objectAtIndex:0] setFrame:first]; |
| 372 | | [[[sender subviews] objectAtIndex:1] setFrame:second]; |
| 373 | | } |
| 374 | | |
| 375 | | @end |
trunk/src/osd/modules/debugger/osx/debugosxdebugview.m
| r243595 | r243596 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // debugosxdebugview.h - MacOS X Cocoa debug window handling |
| 6 | | // |
| 7 | | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | | // |
| 10 | | //============================================================ |
| 11 | | |
| 12 | | #import "debugosxdebugview.h" |
| 13 | | |
| 14 | | #include "debug/debugcpu.h" |
| 15 | | |
| 16 | | |
| 17 | | static void debugwin_view_update(debug_view &view, void *osdprivate) |
| 18 | | { |
| 19 | | [(MAMEDebugView *)osdprivate update]; |
| 20 | | } |
| 21 | | |
| 22 | | |
| 23 | | @implementation MAMEDebugView |
| 24 | | |
| 25 | | - (NSColor *)foregroundForAttribute:(UINT8)attrib { |
| 26 | | const CGFloat alpha = (attrib & DCA_DISABLED) ? 0.5 : 1.0; |
| 27 | | if (attrib & DCA_COMMENT) |
| 28 | | return [NSColor colorWithCalibratedRed:0.0 green:0.375 blue:0.0 alpha:1.0]; |
| 29 | | else if (attrib & DCA_INVALID) |
| 30 | | return [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:1.0 alpha:alpha]; |
| 31 | | else if (attrib & DCA_CHANGED) |
| 32 | | return [NSColor colorWithCalibratedRed:0.875 green:0.0 blue:0.0 alpha:alpha]; |
| 33 | | else |
| 34 | | return [NSColor colorWithCalibratedWhite:0.0 alpha:alpha]; |
| 35 | | } |
| 36 | | |
| 37 | | |
| 38 | | - (NSColor *)backgroundForAttribute:(UINT8)attrib { |
| 39 | | if ((attrib & DCA_SELECTED) && (attrib & DCA_CURRENT)) { |
| 40 | | if ([[self window] isKeyWindow] && ([[self window] firstResponder] == self)) |
| 41 | | return [NSColor colorWithCalibratedRed:0.875 green:0.625 blue:0.875 alpha:1.0]; |
| 42 | | else |
| 43 | | return [NSColor colorWithCalibratedRed:0.875 green:0.5 blue:0.625 alpha:1.0]; |
| 44 | | } else if (attrib & DCA_CURRENT) { |
| 45 | | return [NSColor colorWithCalibratedRed:1.0 green:0.625 blue:0.625 alpha:1.0]; |
| 46 | | } else if (attrib & DCA_SELECTED) { |
| 47 | | if ([[self window] isKeyWindow] && ([[self window] firstResponder] == self)) |
| 48 | | return [NSColor colorWithCalibratedRed:0.75 green:0.875 blue:1.0 alpha:1.0]; |
| 49 | | else |
| 50 | | return [NSColor colorWithCalibratedWhite:0.875 alpha:1.0]; |
| 51 | | } else if (attrib & DCA_ANCILLARY) { |
| 52 | | return [NSColor colorWithCalibratedWhite:0.75 alpha:1.0]; |
| 53 | | } else { |
| 54 | | return [NSColor colorWithCalibratedWhite:1.0 alpha:1.0]; |
| 55 | | } |
| 56 | | } |
| 57 | | |
| 58 | | |
| 59 | | - (debug_view_xy)convertLocation:(NSPoint)location { |
| 60 | | debug_view_xy position; |
| 61 | | |
| 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 | | [text deleteCharactersInRange:NSMakeRange(0, length)]; |
| 114 | | } |
| 115 | | if (position.x < 0) |
| 116 | | position.x = 0; |
| 117 | | else if (position.x >= totalWidth) |
| 118 | | position.x = totalWidth - 1; |
| 119 | | |
| 120 | | return position; |
| 121 | | } |
| 122 | | |
| 123 | | |
| 124 | | - (void)convertBounds:(NSRect)b toPosition:(debug_view_xy *)origin size:(debug_view_xy *)size { |
| 125 | | origin->x = lround(floor(b.origin.x / fontWidth)); |
| 126 | | origin->y = lround(floor(b.origin.y / fontHeight)); |
| 127 | | |
| 128 | | // FIXME: this is not using proper font metrics horizontally |
| 129 | | size->x = lround(ceil((b.origin.x + b.size.width) / fontWidth)) - origin->x; |
| 130 | | size->y = lround(ceil((b.origin.y + b.size.height) / fontHeight)) - origin->y; |
| 131 | | } |
| 132 | | |
| 133 | | |
| 134 | | - (void)recomputeVisible { |
| 135 | | if ([self window] != nil) { |
| 136 | | debug_view_xy origin, size; |
| 137 | | |
| 138 | | // this gets all the characters that are at least paritally visible |
| 139 | | [self convertBounds:[self visibleRect] toPosition:&origin size:&size]; |
| 140 | | |
| 141 | | // need to render entire lines or we get screwed up characters when widening views |
| 142 | | origin.x = 0; |
| 143 | | size.x = totalWidth; |
| 144 | | |
| 145 | | // tell them what we think |
| 146 | | view->set_visible_size(size); |
| 147 | | view->set_visible_position(origin); |
| 148 | | originLeft = origin.x; |
| 149 | | originTop = origin.y; |
| 150 | | } |
| 151 | | } |
| 152 | | |
| 153 | | |
| 154 | | - (void)typeCharacterAndScrollToCursor:(char)ch { |
| 155 | | if (view->cursor_supported()) { |
| 156 | | debug_view_xy oldPos = view->cursor_position(); |
| 157 | | view->process_char(ch); |
| 158 | | { |
| 159 | | debug_view_xy newPos = view->cursor_position(); |
| 160 | | if ((newPos.x != oldPos.x) || (newPos.y != oldPos.y)) { |
| 161 | | [self scrollRectToVisible:NSMakeRect(newPos.x * fontWidth, // FIXME - use proper metrics |
| 162 | | newPos.y * fontHeight, |
| 163 | | fontWidth, |
| 164 | | fontHeight)]; |
| 165 | | } |
| 166 | | } |
| 167 | | } else { |
| 168 | | view->process_char(ch); |
| 169 | | } |
| 170 | | } |
| 171 | | |
| 172 | | |
| 173 | | + (NSFont *)defaultFont { |
| 174 | | return [NSFont userFixedPitchFontOfSize:0]; |
| 175 | | } |
| 176 | | |
| 177 | | |
| 178 | | - (id)initWithFrame:(NSRect)f type:(debug_view_type)t machine:(running_machine &)m { |
| 179 | | if (!(self = [super initWithFrame:f])) |
| 180 | | return nil; |
| 181 | | type = t; |
| 182 | | machine = &m; |
| 183 | | view = machine->debug_view().alloc_view((debug_view_type)type, debugwin_view_update, self); |
| 184 | | if (view == nil) { |
| 185 | | [self release]; |
| 186 | | return nil; |
| 187 | | } |
| 188 | | totalWidth = totalHeight = 0; |
| 189 | | originLeft = originTop = 0; |
| 190 | | |
| 191 | | text = [[NSTextStorage alloc] init]; |
| 192 | | textContainer = [[NSTextContainer alloc] init]; |
| 193 | | layoutManager = [[NSLayoutManager alloc] init]; |
| 194 | | [layoutManager addTextContainer:textContainer]; |
| 195 | | [textContainer release]; |
| 196 | | [text addLayoutManager:layoutManager]; |
| 197 | | [layoutManager release]; |
| 198 | | |
| 199 | | [self setFont:[[self class] defaultFont]]; |
| 200 | | |
| 201 | | return self; |
| 202 | | } |
| 203 | | |
| 204 | | |
| 205 | | - (void)dealloc { |
| 206 | | [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 207 | | if (font != nil) [font release]; |
| 208 | | if (text != nil) [text release]; |
| 209 | | [super dealloc]; |
| 210 | | } |
| 211 | | |
| 212 | | |
| 213 | | - (void)update { |
| 214 | | debug_view_xy newSize, newOrigin; |
| 215 | | |
| 216 | | // resize our frame if the total size has changed |
| 217 | | newSize = view->total_size(); |
| 218 | | if ((newSize.x != totalWidth) || (newSize.y != totalHeight)) { |
| 219 | | [self setFrameSize:NSMakeSize(fontWidth * newSize.x, fontHeight * newSize.y)]; // FIXME: metrics |
| 220 | | totalWidth = newSize.x; |
| 221 | | totalHeight = newSize.y; |
| 222 | | } |
| 223 | | |
| 224 | | // scroll the view if we're being told to |
| 225 | | newOrigin = view->visible_position(); |
| 226 | | if (newOrigin.y != originTop) { |
| 227 | | [self scrollPoint:NSMakePoint([self visibleRect].origin.x, newOrigin.y * fontHeight)]; |
| 228 | | originTop = newOrigin.y; |
| 229 | | } |
| 230 | | |
| 231 | | // recompute the visible area and mark as dirty |
| 232 | | [self recomputeVisible]; |
| 233 | | [self setNeedsDisplay:YES]; |
| 234 | | } |
| 235 | | |
| 236 | | |
| 237 | | - (NSSize)maximumFrameSize { |
| 238 | | debug_view_xy max = view->total_size(); |
| 239 | | return NSMakeSize(max.x * fontWidth, max.y * fontHeight); |
| 240 | | } |
| 241 | | |
| 242 | | |
| 243 | | - (NSFont *)font { |
| 244 | | return [[font retain] autorelease]; |
| 245 | | } |
| 246 | | |
| 247 | | |
| 248 | | - (void)setFont:(NSFont *)f { |
| 249 | | [font autorelease]; |
| 250 | | font = [f retain]; |
| 251 | | fontWidth = [font maximumAdvancement].width; |
| 252 | | fontHeight = ceil([font ascender] - [font descender]); |
| 253 | | fontAscent = [font ascender]; |
| 254 | | [[self enclosingScrollView] setLineScroll:fontHeight]; |
| 255 | | totalWidth = totalHeight = 0; |
| 256 | | [self update]; |
| 257 | | } |
| 258 | | |
| 259 | | |
| 260 | | - (void)windowDidBecomeKey:(NSNotification *)notification { |
| 261 | | NSWindow *win = [notification object]; |
| 262 | | if ((win == [self window]) && ([win firstResponder] == self) && view->cursor_supported()) |
| 263 | | [self setNeedsDisplay:YES]; |
| 264 | | } |
| 265 | | |
| 266 | | |
| 267 | | - (void)windowDidResignKey:(NSNotification *)notification { |
| 268 | | NSWindow *win = [notification object]; |
| 269 | | if ((win == [self window]) && ([win firstResponder] == self) && view->cursor_supported()) |
| 270 | | [self setNeedsDisplay:YES]; |
| 271 | | } |
| 272 | | |
| 273 | | |
| 274 | | - (BOOL)acceptsFirstResponder { |
| 275 | | return view->cursor_supported(); |
| 276 | | } |
| 277 | | |
| 278 | | |
| 279 | | - (BOOL)becomeFirstResponder { |
| 280 | | if (view->cursor_supported()) { |
| 281 | | debug_view_xy pos; |
| 282 | | view->set_cursor_visible(true); |
| 283 | | pos = view->cursor_position(); |
| 284 | | [self scrollRectToVisible:NSMakeRect(pos.x * fontWidth, pos.y * fontHeight, fontWidth, fontHeight)]; // FIXME: metrics |
| 285 | | [self setNeedsDisplay:YES]; |
| 286 | | return [super becomeFirstResponder]; |
| 287 | | } else { |
| 288 | | return NO; |
| 289 | | } |
| 290 | | } |
| 291 | | |
| 292 | | |
| 293 | | - (BOOL)resignFirstResponder { |
| 294 | | if (view->cursor_supported()) |
| 295 | | [self setNeedsDisplay:YES]; |
| 296 | | return [super resignFirstResponder]; |
| 297 | | } |
| 298 | | |
| 299 | | |
| 300 | | - (void)viewDidMoveToSuperview { |
| 301 | | [[self enclosingScrollView] setLineScroll:fontHeight]; |
| 302 | | [super viewDidMoveToSuperview]; |
| 303 | | } |
| 304 | | |
| 305 | | |
| 306 | | - (void)viewDidMoveToWindow { |
| 307 | | [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil]; |
| 308 | | [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResignKeyNotification object:nil]; |
| 309 | | if ([self window] != nil) { |
| 310 | | [[NSNotificationCenter defaultCenter] addObserver:self |
| 311 | | selector:@selector(windowDidBecomeKey:) |
| 312 | | name:NSWindowDidBecomeKeyNotification |
| 313 | | object:[self window]]; |
| 314 | | [[NSNotificationCenter defaultCenter] addObserver:self |
| 315 | | selector:@selector(windowDidResignKey:) |
| 316 | | name:NSWindowDidResignKeyNotification |
| 317 | | object:[self window]]; |
| 318 | | [self recomputeVisible]; |
| 319 | | } |
| 320 | | } |
| 321 | | |
| 322 | | |
| 323 | | - (BOOL)isFlipped { |
| 324 | | return YES; |
| 325 | | } |
| 326 | | |
| 327 | | |
| 328 | | - (void)drawRect:(NSRect)dirtyRect { |
| 329 | | debug_view_xy position, clip; |
| 330 | | |
| 331 | | // work out how much we need to draw |
| 332 | | [self recomputeVisible]; |
| 333 | | debug_view_xy const origin = view->visible_position(); |
| 334 | | debug_view_xy const size = view->visible_size(); |
| 335 | | [self convertBounds:dirtyRect toPosition:&position size:&clip]; |
| 336 | | |
| 337 | | // this gets the text for the whole visible area |
| 338 | | debug_view_char const *data = view->viewdata(); |
| 339 | | if (!data) |
| 340 | | return; |
| 341 | | |
| 342 | | data += ((position.y - origin.y) * size.x); |
| 343 | | for (UINT32 row = position.y; row < position.y + clip.y; row++, data += size.x) |
| 344 | | { |
| 345 | | if ((row < origin.y) || (row >= origin.y + size.y)) |
| 346 | | continue; |
| 347 | | |
| 348 | | // render entire lines to get character alignment right |
| 349 | | int attr = -1; |
| 350 | | NSUInteger start = 0, length = 0; |
| 351 | | for (UINT32 col = origin.x; col < origin.x + size.x; col++) |
| 352 | | { |
| 353 | | [[text mutableString] appendFormat:@"%c", data[col - origin.x].byte]; |
| 354 | | if ((start < length) && (attr != data[col - origin.x].attrib)) |
| 355 | | { |
| 356 | | NSRange const run = NSMakeRange(start, length - start); |
| 357 | | [text addAttribute:NSFontAttributeName |
| 358 | | value:font |
| 359 | | range:NSMakeRange(0, length)]; |
| 360 | | [text addAttribute:NSForegroundColorAttributeName |
| 361 | | value:[self foregroundForAttribute:attr] |
| 362 | | range:run]; |
| 363 | | NSRange const glyphs = [layoutManager glyphRangeForCharacterRange:run |
| 364 | | actualCharacterRange:NULL]; |
| 365 | | NSRect const box = [layoutManager boundingRectForGlyphRange:glyphs |
| 366 | | inTextContainer:textContainer]; |
| 367 | | [[self backgroundForAttribute:attr] set]; |
| 368 | | [NSBezierPath fillRect:NSMakeRect(box.origin.x, |
| 369 | | row * fontHeight, |
| 370 | | box.size.width, |
| 371 | | fontHeight)]; |
| 372 | | start = length; |
| 373 | | } |
| 374 | | attr = data[col - origin.x].attrib; |
| 375 | | length = [text length]; |
| 376 | | } |
| 377 | | if (start < length) |
| 378 | | { |
| 379 | | NSRange const run = NSMakeRange(start, length - start); |
| 380 | | [text addAttribute:NSFontAttributeName |
| 381 | | value:font |
| 382 | | range:NSMakeRange(0, length)]; |
| 383 | | [text addAttribute:NSForegroundColorAttributeName |
| 384 | | value:[self foregroundForAttribute:attr] |
| 385 | | range:run]; |
| 386 | | NSRange const glyphs = [layoutManager glyphRangeForCharacterRange:run |
| 387 | | actualCharacterRange:NULL]; |
| 388 | | NSRect const box = [layoutManager boundingRectForGlyphRange:glyphs |
| 389 | | inTextContainer:textContainer]; |
| 390 | | [[self backgroundForAttribute:attr] set]; |
| 391 | | [NSBezierPath fillRect:NSMakeRect(box.origin.x, |
| 392 | | row * fontHeight, |
| 393 | | box.size.width, |
| 394 | | fontHeight)]; |
| 395 | | } |
| 396 | | [layoutManager drawGlyphsForGlyphRange:[layoutManager glyphRangeForTextContainer:textContainer] |
| 397 | | atPoint:NSMakePoint(0, row * fontHeight)]; |
| 398 | | [text deleteCharactersInRange:NSMakeRange(0, length)]; |
| 399 | | } |
| 400 | | } |
| 401 | | |
| 402 | | |
| 403 | | - (void)mouseDown:(NSEvent *)event { |
| 404 | | NSPoint const location = [self convertPoint:[event locationInWindow] fromView:nil]; |
| 405 | | view->process_click(DCK_LEFT_CLICK, [self convertLocation:location]); |
| 406 | | [self setNeedsDisplay:YES]; |
| 407 | | } |
| 408 | | |
| 409 | | |
| 410 | | - (void)rightMouseDown:(NSEvent *)event { |
| 411 | | NSPoint const location = [self convertPoint:[event locationInWindow] fromView:nil]; |
| 412 | | view->process_click(DCK_RIGHT_CLICK, [self convertLocation:location]); |
| 413 | | [self setNeedsDisplay:YES]; |
| 414 | | [super rightMouseDown:event]; |
| 415 | | } |
| 416 | | |
| 417 | | |
| 418 | | - (void)keyDown:(NSEvent *)event { |
| 419 | | NSUInteger modifiers = [event modifierFlags]; |
| 420 | | NSString *str = [event charactersIgnoringModifiers]; |
| 421 | | |
| 422 | | if ([str length] == 1) { |
| 423 | | if (modifiers & NSNumericPadKeyMask) { |
| 424 | | switch ([str characterAtIndex:0]) { |
| 425 | | case NSUpArrowFunctionKey: |
| 426 | | if (modifiers & NSCommandKeyMask) |
| 427 | | view->process_char(DCH_CTRLHOME); |
| 428 | | else |
| 429 | | view->process_char(DCH_UP); |
| 430 | | return; |
| 431 | | case NSDownArrowFunctionKey: |
| 432 | | if (modifiers & NSCommandKeyMask) |
| 433 | | view->process_char(DCH_CTRLEND); |
| 434 | | else |
| 435 | | view->process_char(DCH_DOWN); |
| 436 | | return; |
| 437 | | case NSLeftArrowFunctionKey: |
| 438 | | if (modifiers & NSCommandKeyMask) |
| 439 | | [self typeCharacterAndScrollToCursor:DCH_HOME]; |
| 440 | | else if (modifiers & NSAlternateKeyMask) |
| 441 | | [self typeCharacterAndScrollToCursor:DCH_CTRLLEFT]; |
| 442 | | else |
| 443 | | [self typeCharacterAndScrollToCursor:DCH_LEFT]; |
| 444 | | return; |
| 445 | | case NSRightArrowFunctionKey: |
| 446 | | if (modifiers & NSCommandKeyMask) |
| 447 | | [self typeCharacterAndScrollToCursor:DCH_END]; |
| 448 | | else if (modifiers & NSAlternateKeyMask) |
| 449 | | [self typeCharacterAndScrollToCursor:DCH_CTRLRIGHT]; |
| 450 | | else |
| 451 | | [self typeCharacterAndScrollToCursor:DCH_RIGHT]; |
| 452 | | return; |
| 453 | | default: |
| 454 | | [self interpretKeyEvents:[NSArray arrayWithObject:event]]; |
| 455 | | return; |
| 456 | | } |
| 457 | | } else if (modifiers & NSFunctionKeyMask) { |
| 458 | | switch ([str characterAtIndex:0]) { |
| 459 | | case NSPageUpFunctionKey: |
| 460 | | if (modifiers & NSAlternateKeyMask) { |
| 461 | | view->process_char(DCH_PUP); |
| 462 | | return; |
| 463 | | } |
| 464 | | case NSPageDownFunctionKey: |
| 465 | | if (modifiers & NSAlternateKeyMask) { |
| 466 | | view->process_char(DCH_PDOWN); |
| 467 | | return; |
| 468 | | } |
| 469 | | default: |
| 470 | | ; |
| 471 | | } |
| 472 | | [super keyDown:event]; |
| 473 | | return; |
| 474 | | } |
| 475 | | } |
| 476 | | [self interpretKeyEvents:[NSArray arrayWithObject:event]]; |
| 477 | | } |
| 478 | | |
| 479 | | |
| 480 | | - (void)insertTab:(id)sender { |
| 481 | | if ([[self window] firstResponder] == self) |
| 482 | | [[self window] selectNextKeyView:self]; |
| 483 | | } |
| 484 | | |
| 485 | | |
| 486 | | - (void)insertBacktab:(id)sender { |
| 487 | | if ([[self window] firstResponder] == self) |
| 488 | | [[self window] selectPreviousKeyView:self]; |
| 489 | | } |
| 490 | | |
| 491 | | |
| 492 | | - (void)insertNewline:(id)sender { |
| 493 | | debug_cpu_get_visible_cpu(*machine)->debug()->single_step(); |
| 494 | | } |
| 495 | | |
| 496 | | |
| 497 | | - (void)insertText:(id)string { |
| 498 | | NSUInteger len; |
| 499 | | NSRange found; |
| 500 | | if ([string isKindOfClass:[NSAttributedString class]]) |
| 501 | | string = [string string]; |
| 502 | | for (len = [string length], found = NSMakeRange(0, 0); |
| 503 | | found.location < len; |
| 504 | | found.location += found.length) { |
| 505 | | found = [string rangeOfComposedCharacterSequenceAtIndex:found.location]; |
| 506 | | if (found.length == 1) { |
| 507 | | unichar ch = [string characterAtIndex:found.location]; |
| 508 | | if ((ch >= 32) && (ch < 127)) |
| 509 | | [self typeCharacterAndScrollToCursor:ch]; |
| 510 | | } |
| 511 | | } |
| 512 | | } |
| 513 | | |
| 514 | | @end |
trunk/src/osd/modules/debugger/osx/debugosxdebugwindowhandler.m
| r243595 | r243596 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // debugosxdebugwindowhandler.m - MacOS X Cocoa debug window handling |
| 6 | | // |
| 7 | | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | | // |
| 10 | | //============================================================ |
| 11 | | |
| 12 | | #import "debugosxdebugwindowhandler.h" |
| 13 | | |
| 14 | | #import "debugosxdebugcommandhistory.h" |
| 15 | | #import "debugosxdebugview.h" |
| 16 | | |
| 17 | | #include "debug/debugcpu.h" |
| 18 | | |
| 19 | | |
| 20 | | //============================================================ |
| 21 | | // NOTIFICATIONS |
| 22 | | //============================================================ |
| 23 | | |
| 24 | | NSString *const MAMEHideDebuggerNotification = @"MAMEHideDebuggerNotification"; |
| 25 | | NSString *const MAMEShowDebuggerNotification = @"MAMEShowDebuggerNotification"; |
| 26 | | NSString *const MAMEAuxiliaryDebugWindowWillCloseNotification = @"MAMEAuxiliaryDebugWindowWillCloseNotification"; |
| 27 | | |
| 28 | | |
| 29 | | //============================================================ |
| 30 | | // MAMEDebugWindowHandler class |
| 31 | | //============================================================ |
| 32 | | |
| 33 | | @implementation MAMEDebugWindowHandler |
| 34 | | |
| 35 | | + (void)addCommonActionItems:(NSMenu *)menu { |
| 36 | | { |
| 37 | | NSMenuItem *runParentItem = [menu addItemWithTitle:@"Run" |
| 38 | | action:@selector(debugRun:) |
| 39 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF5FunctionKey]]; |
| 40 | | NSMenu *runMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Run"]; |
| 41 | | [runParentItem setSubmenu:runMenu]; |
| 42 | | [runMenu release]; |
| 43 | | [runParentItem setKeyEquivalentModifierMask:0]; |
| 44 | | [[runMenu addItemWithTitle:@"and Hide Debugger" |
| 45 | | action:@selector(debugRunAndHide:) |
| 46 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF12FunctionKey]] |
| 47 | | setKeyEquivalentModifierMask:0]; |
| 48 | | [[runMenu addItemWithTitle:@"to Next CPU" |
| 49 | | action:@selector(debugRunToNextCPU:) |
| 50 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF6FunctionKey]] |
| 51 | | setKeyEquivalentModifierMask:0]; |
| 52 | | [[runMenu addItemWithTitle:@"until Next Interrupt on Current CPU" |
| 53 | | action:@selector(debugRunToNextInterrupt:) |
| 54 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF7FunctionKey]] |
| 55 | | setKeyEquivalentModifierMask:0]; |
| 56 | | [[runMenu addItemWithTitle:@"until Next VBLANK" |
| 57 | | action:@selector(debugRunToNextVBLANK:) |
| 58 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF8FunctionKey]] |
| 59 | | setKeyEquivalentModifierMask:0]; |
| 60 | | } |
| 61 | | { |
| 62 | | NSMenuItem *stepParentItem = [menu addItemWithTitle:@"Step" action:NULL keyEquivalent:@""]; |
| 63 | | NSMenu *stepMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Step"]; |
| 64 | | [stepParentItem setSubmenu:stepMenu]; |
| 65 | | [stepMenu release]; |
| 66 | | [[stepMenu addItemWithTitle:@"Into" |
| 67 | | action:@selector(debugStepInto:) |
| 68 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF11FunctionKey]] |
| 69 | | setKeyEquivalentModifierMask:0]; |
| 70 | | [[stepMenu addItemWithTitle:@"Over" |
| 71 | | action:@selector(debugStepOver:) |
| 72 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF10FunctionKey]] |
| 73 | | setKeyEquivalentModifierMask:0]; |
| 74 | | [[stepMenu addItemWithTitle:@"Out" |
| 75 | | action:@selector(debugStepOut:) |
| 76 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF10FunctionKey]] |
| 77 | | setKeyEquivalentModifierMask:NSShiftKeyMask]; |
| 78 | | } |
| 79 | | { |
| 80 | | NSMenuItem *resetParentItem = [menu addItemWithTitle:@"Reset" action:NULL keyEquivalent:@""]; |
| 81 | | NSMenu *resetMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Reset"]; |
| 82 | | [resetParentItem setSubmenu:resetMenu]; |
| 83 | | [resetMenu release]; |
| 84 | | [[resetMenu addItemWithTitle:@"Soft" |
| 85 | | action:@selector(debugSoftReset:) |
| 86 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF3FunctionKey]] |
| 87 | | setKeyEquivalentModifierMask:0]; |
| 88 | | [[resetMenu addItemWithTitle:@"Hard" |
| 89 | | action:@selector(debugHardReset:) |
| 90 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF3FunctionKey]] |
| 91 | | setKeyEquivalentModifierMask:NSShiftKeyMask]; |
| 92 | | } |
| 93 | | [menu addItem:[NSMenuItem separatorItem]]; |
| 94 | | { |
| 95 | | NSMenuItem *newParentItem = [menu addItemWithTitle:@"New" action:NULL keyEquivalent:@""]; |
| 96 | | NSMenu *newMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"New"]; |
| 97 | | [newParentItem setSubmenu:newMenu]; |
| 98 | | [newMenu release]; |
| 99 | | [newMenu addItemWithTitle:@"Memory Window" |
| 100 | | action:@selector(debugNewMemoryWindow:) |
| 101 | | keyEquivalent:@"d"]; |
| 102 | | [newMenu addItemWithTitle:@"Disassembly Window" |
| 103 | | action:@selector(debugNewDisassemblyWindow:) |
| 104 | | keyEquivalent:@"a"]; |
| 105 | | [newMenu addItemWithTitle:@"Error Log Window" |
| 106 | | action:@selector(debugNewErrorLogWindow:) |
| 107 | | keyEquivalent:@"l"]; |
| 108 | | [newMenu addItemWithTitle:@"(Break|Watch)points Window" |
| 109 | | action:@selector(debugNewPointsWindow:) |
| 110 | | keyEquivalent:@"b"]; |
| 111 | | } |
| 112 | | [menu addItem:[NSMenuItem separatorItem]]; |
| 113 | | [menu addItemWithTitle:@"Close Window" action:@selector(performClose:) keyEquivalent:@"w"]; |
| 114 | | [menu addItemWithTitle:@"Exit" action:@selector(debugExit:) keyEquivalent:@""]; |
| 115 | | } |
| 116 | | |
| 117 | | |
| 118 | | + (NSPopUpButton *)newActionButtonWithFrame:(NSRect)frame { |
| 119 | | NSPopUpButton *actionButton = [[NSPopUpButton alloc] initWithFrame:frame pullsDown:YES]; |
| 120 | | [actionButton setTitle:@""]; |
| 121 | | [actionButton addItemWithTitle:@""]; |
| 122 | | [actionButton setBezelStyle:NSShadowlessSquareBezelStyle]; |
| 123 | | [actionButton setFocusRingType:NSFocusRingTypeNone]; |
| 124 | | [[actionButton cell] setArrowPosition:NSPopUpArrowAtCenter]; |
| 125 | | [[self class] addCommonActionItems:[actionButton menu]]; |
| 126 | | return actionButton; |
| 127 | | } |
| 128 | | |
| 129 | | |
| 130 | | - (id)initWithMachine:(running_machine &)m title:(NSString *)t { |
| 131 | | if (!(self = [super init])) |
| 132 | | return nil; |
| 133 | | |
| 134 | | window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 320, 240) |
| 135 | | styleMask:(NSTitledWindowMask | |
| 136 | | NSClosableWindowMask | |
| 137 | | NSMiniaturizableWindowMask | |
| 138 | | NSResizableWindowMask) |
| 139 | | backing:NSBackingStoreBuffered |
| 140 | | defer:YES]; |
| 141 | | [window setReleasedWhenClosed:NO]; |
| 142 | | [window setDelegate:self]; |
| 143 | | [window setTitle:t]; |
| 144 | | [window setContentMinSize:NSMakeSize(320, 240)]; |
| 145 | | |
| 146 | | [[NSNotificationCenter defaultCenter] addObserver:self |
| 147 | | selector:@selector(showDebugger:) |
| 148 | | name:MAMEShowDebuggerNotification |
| 149 | | object:nil]; |
| 150 | | [[NSNotificationCenter defaultCenter] addObserver:self |
| 151 | | selector:@selector(hideDebugger:) |
| 152 | | name:MAMEHideDebuggerNotification |
| 153 | | object:nil]; |
| 154 | | |
| 155 | | machine = &m; |
| 156 | | |
| 157 | | return self; |
| 158 | | } |
| 159 | | |
| 160 | | |
| 161 | | - (void)dealloc { |
| 162 | | [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 163 | | |
| 164 | | if (window != nil) |
| 165 | | [window release]; |
| 166 | | |
| 167 | | [super dealloc]; |
| 168 | | } |
| 169 | | |
| 170 | | |
| 171 | | - (void)activate { |
| 172 | | [window makeKeyAndOrderFront:self]; |
| 173 | | } |
| 174 | | |
| 175 | | |
| 176 | | - (IBAction)debugRun:(id)sender { |
| 177 | | debug_cpu_get_visible_cpu(*machine)->debug()->go(); |
| 178 | | } |
| 179 | | |
| 180 | | |
| 181 | | - (IBAction)debugRunAndHide:(id)sender { |
| 182 | | [[NSNotificationCenter defaultCenter] postNotificationName:MAMEHideDebuggerNotification object:self]; |
| 183 | | debug_cpu_get_visible_cpu(*machine)->debug()->go(); |
| 184 | | } |
| 185 | | |
| 186 | | |
| 187 | | - (IBAction)debugRunToNextCPU:(id)sender { |
| 188 | | debug_cpu_get_visible_cpu(*machine)->debug()->go_next_device(); |
| 189 | | } |
| 190 | | |
| 191 | | |
| 192 | | - (IBAction)debugRunToNextInterrupt:(id)sender { |
| 193 | | debug_cpu_get_visible_cpu(*machine)->debug()->go_interrupt(); |
| 194 | | } |
| 195 | | |
| 196 | | |
| 197 | | - (IBAction)debugRunToNextVBLANK:(id)sender { |
| 198 | | debug_cpu_get_visible_cpu(*machine)->debug()->go_vblank(); |
| 199 | | } |
| 200 | | |
| 201 | | |
| 202 | | - (IBAction)debugStepInto:(id)sender { |
| 203 | | debug_cpu_get_visible_cpu(*machine)->debug()->single_step(); |
| 204 | | } |
| 205 | | |
| 206 | | |
| 207 | | - (IBAction)debugStepOver:(id)sender { |
| 208 | | debug_cpu_get_visible_cpu(*machine)->debug()->single_step_over(); |
| 209 | | } |
| 210 | | |
| 211 | | |
| 212 | | - (IBAction)debugStepOut:(id)sender { |
| 213 | | debug_cpu_get_visible_cpu(*machine)->debug()->single_step_out(); |
| 214 | | } |
| 215 | | |
| 216 | | |
| 217 | | - (IBAction)debugSoftReset:(id)sender { |
| 218 | | machine->schedule_soft_reset(); |
| 219 | | debug_cpu_get_visible_cpu(*machine)->debug()->go(); |
| 220 | | } |
| 221 | | |
| 222 | | |
| 223 | | - (IBAction)debugHardReset:(id)sender { |
| 224 | | machine->schedule_hard_reset(); |
| 225 | | } |
| 226 | | |
| 227 | | |
| 228 | | - (IBAction)debugExit:(id)sender { |
| 229 | | machine->schedule_exit(); |
| 230 | | } |
| 231 | | |
| 232 | | |
| 233 | | - (void)showDebugger:(NSNotification *)notification { |
| 234 | | device_t *device = (device_t *) [[[notification userInfo] objectForKey:@"MAMEDebugDevice"] pointerValue]; |
| 235 | | if (&device->machine() == machine) { |
| 236 | | if (![window isVisible] && ![window isMiniaturized]) |
| 237 | | [window orderFront:self]; |
| 238 | | } |
| 239 | | } |
| 240 | | |
| 241 | | |
| 242 | | - (void)hideDebugger:(NSNotification *)notification { |
| 243 | | [window orderOut:self]; |
| 244 | | } |
| 245 | | |
| 246 | | @end |
| 247 | | |
| 248 | | |
| 249 | | //============================================================ |
| 250 | | // MAMEAuxiliaryDebugWindowHandler class |
| 251 | | //============================================================ |
| 252 | | |
| 253 | | @implementation MAMEAuxiliaryDebugWindowHandler |
| 254 | | |
| 255 | | + (void)cascadeWindow:(NSWindow *)window { |
| 256 | | static NSPoint lastPosition = { 0, 0 }; |
| 257 | | if (NSEqualPoints(lastPosition, NSZeroPoint)) { |
| 258 | | NSRect available = [[NSScreen mainScreen] visibleFrame]; |
| 259 | | lastPosition = NSMakePoint(available.origin.x + 12, available.origin.y + available.size.height - 8); |
| 260 | | } |
| 261 | | lastPosition = [window cascadeTopLeftFromPoint:lastPosition]; |
| 262 | | } |
| 263 | | |
| 264 | | |
| 265 | | - (id)initWithMachine:(running_machine &)m title:(NSString *)t console:(MAMEDebugConsole *)c { |
| 266 | | if (!(self = [super initWithMachine:m title:t])) |
| 267 | | return nil; |
| 268 | | console = c; |
| 269 | | return self; |
| 270 | | } |
| 271 | | |
| 272 | | |
| 273 | | - (void)dealloc { |
| 274 | | [super dealloc]; |
| 275 | | } |
| 276 | | |
| 277 | | |
| 278 | | - (IBAction)debugNewMemoryWindow:(id)sender { |
| 279 | | [console debugNewMemoryWindow:sender]; |
| 280 | | } |
| 281 | | |
| 282 | | |
| 283 | | - (IBAction)debugNewDisassemblyWindow:(id)sender { |
| 284 | | [console debugNewDisassemblyWindow:sender]; |
| 285 | | } |
| 286 | | |
| 287 | | |
| 288 | | - (IBAction)debugNewErrorLogWindow:(id)sender { |
| 289 | | [console debugNewErrorLogWindow:sender]; |
| 290 | | } |
| 291 | | |
| 292 | | |
| 293 | | - (IBAction)debugNewPointsWindow:(id)sender { |
| 294 | | [console debugNewPointsWindow:sender]; |
| 295 | | } |
| 296 | | |
| 297 | | |
| 298 | | - (void)windowWillClose:(NSNotification *)notification { |
| 299 | | [[NSNotificationCenter defaultCenter] postNotificationName:MAMEAuxiliaryDebugWindowWillCloseNotification |
| 300 | | object:self]; |
| 301 | | } |
| 302 | | |
| 303 | | - (void)cascadeWindowWithDesiredSize:(NSSize)desired forView:(NSView *)view { |
| 304 | | NSRect available = [[NSScreen mainScreen] visibleFrame]; |
| 305 | | NSRect windowFrame = [window frame]; |
| 306 | | NSSize current = [view frame].size; |
| 307 | | |
| 308 | | desired.width -= current.width; |
| 309 | | desired.height -= current.height; |
| 310 | | |
| 311 | | windowFrame.size.width += desired.width; |
| 312 | | windowFrame.size.height += desired.height; |
| 313 | | windowFrame.size.height = MIN(MIN(windowFrame.size.height, 240), available.size.height); |
| 314 | | windowFrame.size.width = MIN(windowFrame.size.width, available.size.width); |
| 315 | | windowFrame.origin.x = available.origin.x + available.size.width - windowFrame.size.width; |
| 316 | | windowFrame.origin.y = available.origin.y; |
| 317 | | [window setFrame:windowFrame display:YES]; |
| 318 | | [[self class] cascadeWindow:window]; |
| 319 | | |
| 320 | | windowFrame = [[window contentView] frame]; |
| 321 | | desired = [window contentMinSize]; |
| 322 | | [window setContentMinSize:NSMakeSize(MIN(windowFrame.size.width, desired.width), |
| 323 | | MIN(windowFrame.size.height, desired.height))]; |
| 324 | | } |
| 325 | | |
| 326 | | @end |
| 327 | | |
| 328 | | |
| 329 | | //============================================================ |
| 330 | | // MAMEExpreesionAuxiliaryDebugWindowHandler class |
| 331 | | //============================================================ |
| 332 | | |
| 333 | | @implementation MAMEExpressionAuxiliaryDebugWindowHandler |
| 334 | | |
| 335 | | - (id)initWithMachine:(running_machine &)m title:(NSString *)t console:(MAMEDebugConsole *)c { |
| 336 | | if (!(self = [super initWithMachine:m title:t console:c])) |
| 337 | | return nil; |
| 338 | | history = [[MAMEDebugCommandHistory alloc] init]; |
| 339 | | return self; |
| 340 | | } |
| 341 | | |
| 342 | | |
| 343 | | - (void)dealloc { |
| 344 | | if (history != nil) |
| 345 | | [history release]; |
| 346 | | [super dealloc]; |
| 347 | | } |
| 348 | | |
| 349 | | |
| 350 | | - (id <MAMEDebugViewExpressionSupport>)documentView { |
| 351 | | return nil; |
| 352 | | } |
| 353 | | |
| 354 | | |
| 355 | | - (IBAction)doExpression:(id)sender { |
| 356 | | NSString *expr = [sender stringValue]; |
| 357 | | if ([expr length] > 0) { |
| 358 | | [history add:expr]; |
| 359 | | [[self documentView] setExpression:expr]; |
| 360 | | } else { |
| 361 | | [sender setStringValue:[[self documentView] expression]]; |
| 362 | | [history reset]; |
| 363 | | } |
| 364 | | [sender selectText:self]; |
| 365 | | } |
| 366 | | |
| 367 | | |
| 368 | | - (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor |
| 369 | | { |
| 370 | | if (control == expressionField) |
| 371 | | [history edit]; |
| 372 | | |
| 373 | | return YES; |
| 374 | | } |
| 375 | | |
| 376 | | |
| 377 | | - (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command { |
| 378 | | if (control == expressionField) { |
| 379 | | if (command == @selector(cancelOperation:)) { |
| 380 | | [history reset]; |
| 381 | | [expressionField setStringValue:[[self documentView] expression]]; |
| 382 | | [expressionField selectText:self]; |
| 383 | | return YES; |
| 384 | | } else if (command == @selector(moveUp:)) { |
| 385 | | NSString *hist = [history previous:[expressionField stringValue]]; |
| 386 | | if (hist != nil) { |
| 387 | | [expressionField setStringValue:hist]; |
| 388 | | [expressionField selectText:self]; |
| 389 | | } |
| 390 | | return YES; |
| 391 | | } else if (command == @selector(moveDown:)) { |
| 392 | | NSString *hist = [history next:[expressionField stringValue]]; |
| 393 | | if (hist != nil) { |
| 394 | | [expressionField setStringValue:hist]; |
| 395 | | [expressionField selectText:self]; |
| 396 | | } |
| 397 | | return YES; |
| 398 | | } |
| 399 | | } |
| 400 | | return NO; |
| 401 | | } |
| 402 | | |
| 403 | | @end |
| | No newline at end of file |
trunk/src/osd/modules/debugger/osx/debugosxdisassemblyview.m
| r243595 | r243596 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // debugosxdisassemblyview.m - MacOS X Cocoa debug window handling |
| 6 | | // |
| 7 | | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | | // |
| 10 | | //============================================================ |
| 11 | | |
| 12 | | #import "debugosxdisassemblyview.h" |
| 13 | | |
| 14 | | #include "debug/debugcon.h" |
| 15 | | #include "debug/debugcpu.h" |
| 16 | | #include "debug/debugvw.h" |
| 17 | | #include "debug/dvdisasm.h" |
| 18 | | |
| 19 | | |
| 20 | | @implementation MAMEDisassemblyView |
| 21 | | |
| 22 | | - (device_debug::breakpoint *)findBreakpointAtAddress:(offs_t)address inAddressSpace:(address_space &)space { |
| 23 | | device_debug *cpuinfo = space.device().debug(); |
| 24 | | device_debug::breakpoint *bp; |
| 25 | | for (bp = cpuinfo->breakpoint_first(); (bp != NULL) && (address != bp->address()); bp = bp->next()) {} |
| 26 | | return bp; |
| 27 | | } |
| 28 | | |
| 29 | | - (void)createContextMenu { |
| 30 | | NSMenu *contextMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Disassembly"]; |
| 31 | | NSMenuItem *item; |
| 32 | | |
| 33 | | item = [contextMenu addItemWithTitle:@"Toggle Breakpoint" |
| 34 | | action:@selector(debugToggleBreakpoint:) |
| 35 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey]]; |
| 36 | | [item setKeyEquivalentModifierMask:0]; |
| 37 | | [item setTarget:self]; |
| 38 | | |
| 39 | | item = [contextMenu addItemWithTitle:@"Disable Breakpoint" |
| 40 | | action:@selector(debugToggleBreakpointEnable:) |
| 41 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey]]; |
| 42 | | [item setKeyEquivalentModifierMask:NSShiftKeyMask]; |
| 43 | | [item setTarget:self]; |
| 44 | | |
| 45 | | [contextMenu addItem:[NSMenuItem separatorItem]]; |
| 46 | | |
| 47 | | item = [contextMenu addItemWithTitle:@"Run to Cursor" |
| 48 | | action:@selector(debugRunToCursor:) |
| 49 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF4FunctionKey]]; |
| 50 | | [item setKeyEquivalentModifierMask:0]; |
| 51 | | [item setTarget:self]; |
| 52 | | |
| 53 | | [contextMenu addItem:[NSMenuItem separatorItem]]; |
| 54 | | |
| 55 | | item = [contextMenu addItemWithTitle:@"Raw Opcodes" |
| 56 | | action:@selector(showRightColumn:) |
| 57 | | keyEquivalent:@"r"]; |
| 58 | | [item setTarget:self]; |
| 59 | | [item setTag:DASM_RIGHTCOL_RAW]; |
| 60 | | |
| 61 | | item = [contextMenu addItemWithTitle:@"Encrypted Opcodes" |
| 62 | | action:@selector(showRightColumn:) |
| 63 | | keyEquivalent:@"e"]; |
| 64 | | [item setTarget:self]; |
| 65 | | [item setTag:DASM_RIGHTCOL_ENCRYPTED]; |
| 66 | | |
| 67 | | item = [contextMenu addItemWithTitle:@"Comments" |
| 68 | | action:@selector(showRightColumn:) |
| 69 | | keyEquivalent:@"n"]; |
| 70 | | [item setTarget:self]; |
| 71 | | [item setTag:DASM_RIGHTCOL_COMMENTS]; |
| 72 | | |
| 73 | | [self setMenu:contextMenu]; |
| 74 | | [contextMenu release]; |
| 75 | | } |
| 76 | | |
| 77 | | |
| 78 | | - (id)initWithFrame:(NSRect)f machine:(running_machine &)m useConsole:(BOOL)uc { |
| 79 | | if (!(self = [super initWithFrame:f type:DVT_DISASSEMBLY machine:m])) |
| 80 | | return nil; |
| 81 | | useConsole = uc; |
| 82 | | [self createContextMenu]; |
| 83 | | return self; |
| 84 | | } |
| 85 | | |
| 86 | | |
| 87 | | - (void)dealloc { |
| 88 | | [super dealloc]; |
| 89 | | } |
| 90 | | |
| 91 | | |
| 92 | | - (BOOL)validateMenuItem:(NSMenuItem *)item { |
| 93 | | SEL action = [item action]; |
| 94 | | BOOL inContextMenu = ([item menu] == [self menu]); |
| 95 | | BOOL haveCursor = NO, isCurrent = NO; |
| 96 | | device_debug::breakpoint *breakpoint = NULL; |
| 97 | | |
| 98 | | if (view->cursor_visible()) { |
| 99 | | if (debug_cpu_get_visible_cpu(*machine) == view->source()->device()) { |
| 100 | | isCurrent = YES; |
| 101 | | if (!useConsole || isCurrent) { |
| 102 | | offs_t address = downcast<debug_view_disasm *>(view)->selected_address(); |
| 103 | | haveCursor = YES; |
| 104 | | breakpoint = [self findBreakpointAtAddress:address inAddressSpace:downcast<const debug_view_disasm_source *>(view->source())->space()]; |
| 105 | | } |
| 106 | | } |
| 107 | | } |
| 108 | | |
| 109 | | if (action == @selector(debugToggleBreakpoint:)) { |
| 110 | | if (haveCursor) { |
| 111 | | if (breakpoint != NULL) { |
| 112 | | if (inContextMenu) |
| 113 | | [item setTitle:@"Clear Breakpoint"]; |
| 114 | | else |
| 115 | | [item setTitle:@"Clear Breakpoint at Cursor"]; |
| 116 | | } else { |
| 117 | | if (inContextMenu) |
| 118 | | [item setTitle:@"Set Breakpoint"]; |
| 119 | | else |
| 120 | | [item setTitle:@"Set Breakpoint at Cursor"]; |
| 121 | | } |
| 122 | | } else { |
| 123 | | if (inContextMenu) |
| 124 | | [item setTitle:@"Toggle Breakpoint"]; |
| 125 | | else |
| 126 | | [item setTitle:@"Toggle Breakpoint at Cursor"]; |
| 127 | | } |
| 128 | | return haveCursor; |
| 129 | | } else if (action == @selector(debugToggleBreakpointEnable:)) { |
| 130 | | if ((breakpoint != NULL) && !breakpoint->enabled()) { |
| 131 | | if (inContextMenu) |
| 132 | | [item setTitle:@"Enable Breakpoint"]; |
| 133 | | else |
| 134 | | [item setTitle:@"Enable Breakpoint at Cursor"]; |
| 135 | | } else { |
| 136 | | if (inContextMenu) |
| 137 | | [item setTitle:@"Disable Breakpoint"]; |
| 138 | | else |
| 139 | | [item setTitle:@"Disable Breakpoint at Cursor"]; |
| 140 | | } |
| 141 | | return (breakpoint != NULL); |
| 142 | | } else if (action == @selector(debugRunToCursor:)) { |
| 143 | | return isCurrent; |
| 144 | | } else if (action == @selector(showRightColumn:)) { |
| 145 | | [item setState:((downcast<debug_view_disasm *>(view)->right_column() == [item tag]) ? NSOnState : NSOffState)]; |
| 146 | | return YES; |
| 147 | | } else { |
| 148 | | return YES; |
| 149 | | } |
| 150 | | } |
| 151 | | |
| 152 | | |
| 153 | | - (NSSize)maximumFrameSize { |
| 154 | | debug_view_xy max; |
| 155 | | device_t *curcpu = debug_cpu_get_visible_cpu(*machine); |
| 156 | | const debug_view_source *source = view->source_for_device(curcpu); |
| 157 | | |
| 158 | | max.x = max.y = 0; |
| 159 | | for (const debug_view_source *source = view->source_list().first(); source != NULL; source = source->next()) |
| 160 | | { |
| 161 | | debug_view_xy current; |
| 162 | | view->set_source(*source); |
| 163 | | current = view->total_size(); |
| 164 | | if (current.x > max.x) |
| 165 | | max.x = current.x; |
| 166 | | if (current.y > max.y) |
| 167 | | max.y = current.y; |
| 168 | | } |
| 169 | | view->set_source(*source); |
| 170 | | return NSMakeSize(max.x * fontWidth, max.y * fontHeight); |
| 171 | | } |
| 172 | | |
| 173 | | |
| 174 | | - (NSString *)selectedSubviewName { |
| 175 | | const debug_view_source *source = view->source(); |
| 176 | | if (source != NULL) |
| 177 | | return [NSString stringWithUTF8String:source->name()]; |
| 178 | | else |
| 179 | | return @""; |
| 180 | | } |
| 181 | | |
| 182 | | |
| 183 | | - (int)selectedSubviewIndex { |
| 184 | | const debug_view_source *source = view->source(); |
| 185 | | if (source != NULL) |
| 186 | | return view->source_list().indexof(*source); |
| 187 | | else |
| 188 | | return -1; |
| 189 | | } |
| 190 | | |
| 191 | | |
| 192 | | - (void)selectSubviewAtIndex:(int)index { |
| 193 | | const int selected = view->source_list().indexof(*view->source()); |
| 194 | | if (selected != index) { |
| 195 | | view->set_source(*view->source_list().find(index)); |
| 196 | | if ([[self window] firstResponder] != self) |
| 197 | | view->set_cursor_visible(false); |
| 198 | | } |
| 199 | | } |
| 200 | | |
| 201 | | |
| 202 | | - (void)selectSubviewForCPU:(device_t *)device { |
| 203 | | const debug_view_source *selected = view->source(); |
| 204 | | const debug_view_source *source = view->source_for_device(device); |
| 205 | | if ( selected != source ) { |
| 206 | | view->set_source(*source); |
| 207 | | if ([[self window] firstResponder] != self) |
| 208 | | view->set_cursor_visible(false); |
| 209 | | } |
| 210 | | } |
| 211 | | |
| 212 | | |
| 213 | | - (NSString *)expression { |
| 214 | | return [NSString stringWithUTF8String:downcast<debug_view_disasm *>(view)->expression()]; |
| 215 | | } |
| 216 | | |
| 217 | | |
| 218 | | - (void)setExpression:(NSString *)exp { |
| 219 | | downcast<debug_view_disasm *>(view)->set_expression([exp UTF8String]); |
| 220 | | } |
| 221 | | |
| 222 | | |
| 223 | | - (IBAction)debugToggleBreakpoint:(id)sender { |
| 224 | | if (view->cursor_visible()) { |
| 225 | | address_space &space = downcast<const debug_view_disasm_source *>(view->source())->space(); |
| 226 | | if (!useConsole || (debug_cpu_get_visible_cpu(*machine) == &space.device())) { |
| 227 | | offs_t address = downcast<debug_view_disasm *>(view)->selected_address(); |
| 228 | | device_debug::breakpoint *bp = [self findBreakpointAtAddress:address inAddressSpace:space]; |
| 229 | | |
| 230 | | // if it doesn't exist, add a new one |
| 231 | | if (useConsole) { |
| 232 | | NSString *command; |
| 233 | | if (bp == NULL) |
| 234 | | command = [NSString stringWithFormat:@"bpset %lX", (unsigned long)address]; |
| 235 | | else |
| 236 | | command = [NSString stringWithFormat:@"bpclear %X", (unsigned)bp->index()]; |
| 237 | | debug_console_execute_command(*machine, [command UTF8String], 1); |
| 238 | | } else { |
| 239 | | if (bp == NULL) |
| 240 | | space.device().debug()->breakpoint_set(address, NULL, NULL); |
| 241 | | else |
| 242 | | space.device().debug()->breakpoint_clear(bp->index()); |
| 243 | | } |
| 244 | | } |
| 245 | | } |
| 246 | | } |
| 247 | | |
| 248 | | |
| 249 | | - (IBAction)debugToggleBreakpointEnable:(id)sender { |
| 250 | | if (view->cursor_visible()) { |
| 251 | | address_space &space = downcast<const debug_view_disasm_source *>(view->source())->space(); |
| 252 | | if (!useConsole || (debug_cpu_get_visible_cpu(*machine) == &space.device())) { |
| 253 | | offs_t address = downcast<debug_view_disasm *>(view)->selected_address(); |
| 254 | | device_debug::breakpoint *bp = [self findBreakpointAtAddress:address inAddressSpace:space]; |
| 255 | | |
| 256 | | if (bp != NULL) { |
| 257 | | NSString *command; |
| 258 | | if (useConsole) { |
| 259 | | if (bp->enabled()) |
| 260 | | command = [NSString stringWithFormat:@"bpdisable %X", (unsigned)bp->index()]; |
| 261 | | else |
| 262 | | command = [NSString stringWithFormat:@"bpenable %X", (unsigned)bp->index()]; |
| 263 | | debug_console_execute_command(*machine, [command UTF8String], 1); |
| 264 | | } else { |
| 265 | | space.device().debug()->breakpoint_enable(bp->index(), !bp->enabled()); |
| 266 | | } |
| 267 | | } |
| 268 | | } |
| 269 | | } |
| 270 | | } |
| 271 | | |
| 272 | | |
| 273 | | - (IBAction)debugRunToCursor:(id)sender { |
| 274 | | if (view->cursor_visible()) { |
| 275 | | address_space &space = downcast<const debug_view_disasm_source *>(view->source())->space(); |
| 276 | | if (debug_cpu_get_visible_cpu(*machine) == &space.device()) { |
| 277 | | offs_t address = downcast<debug_view_disasm *>(view)->selected_address(); |
| 278 | | if (useConsole) { |
| 279 | | NSString *command = [NSString stringWithFormat:@"go 0x%lX", (unsigned long)address]; |
| 280 | | debug_console_execute_command(*machine, [command UTF8String], 1); |
| 281 | | } else { |
| 282 | | debug_cpu_get_visible_cpu(*machine)->debug()->go(address); |
| 283 | | } |
| 284 | | } |
| 285 | | } |
| 286 | | } |
| 287 | | |
| 288 | | |
| 289 | | - (IBAction)showRightColumn:(id)sender { |
| 290 | | downcast<debug_view_disasm *>(view)->set_right_column((disasm_right_column) [sender tag]); |
| 291 | | } |
| 292 | | |
| 293 | | |
| 294 | | - (void)insertActionItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index { |
| 295 | | { |
| 296 | | NSMenuItem *breakItem = [menu insertItemWithTitle:@"Toggle Breakpoint at Cursor" |
| 297 | | action:@selector(debugToggleBreakpoint:) |
| 298 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey] |
| 299 | | atIndex:index++]; |
| 300 | | [breakItem setKeyEquivalentModifierMask:0]; |
| 301 | | [breakItem setTarget:self]; |
| 302 | | } |
| 303 | | { |
| 304 | | NSMenuItem *disableItem = [menu insertItemWithTitle:@"Disable Breakpoint at Cursor" |
| 305 | | action:@selector(debugToggleBreakpointEnable:) |
| 306 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey] |
| 307 | | atIndex:index++]; |
| 308 | | [disableItem setKeyEquivalentModifierMask:NSShiftKeyMask]; |
| 309 | | [disableItem setAlternate:YES]; |
| 310 | | [disableItem setTarget:self]; |
| 311 | | } |
| 312 | | { |
| 313 | | NSMenu *runMenu = [[menu itemWithTitle:@"Run"] submenu]; |
| 314 | | NSMenuItem *runItem; |
| 315 | | if (runMenu != nil) { |
| 316 | | runItem = [runMenu addItemWithTitle:@"to Cursor" |
| 317 | | action:@selector(debugRunToCursor:) |
| 318 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF4FunctionKey]]; |
| 319 | | } else { |
| 320 | | runItem = [menu insertItemWithTitle:@"Run to Cursor" |
| 321 | | action:@selector(debugRunToCursor:) |
| 322 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF4FunctionKey] |
| 323 | | atIndex:index++]; |
| 324 | | } |
| 325 | | [runItem setKeyEquivalentModifierMask:0]; |
| 326 | | [runItem setTarget:self]; |
| 327 | | } |
| 328 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 329 | | { |
| 330 | | NSMenuItem *rawItem = [menu insertItemWithTitle:@"Show Raw Opcodes" |
| 331 | | action:@selector(showRightColumn:) |
| 332 | | keyEquivalent:@"r" |
| 333 | | atIndex:index++]; |
| 334 | | [rawItem setTarget:self]; |
| 335 | | [rawItem setTag:DASM_RIGHTCOL_RAW]; |
| 336 | | } |
| 337 | | { |
| 338 | | NSMenuItem *encItem = [menu insertItemWithTitle:@"Show Encrypted Opcodes" |
| 339 | | action:@selector(showRightColumn:) |
| 340 | | keyEquivalent:@"e" |
| 341 | | atIndex:index++]; |
| 342 | | [encItem setTarget:self]; |
| 343 | | [encItem setTag:DASM_RIGHTCOL_ENCRYPTED]; |
| 344 | | } |
| 345 | | { |
| 346 | | NSMenuItem *commentsItem = [menu insertItemWithTitle:@"Show Comments" |
| 347 | | action:@selector(showRightColumn:) |
| 348 | | keyEquivalent:@"n" |
| 349 | | atIndex:index++]; |
| 350 | | [commentsItem setTarget:self]; |
| 351 | | [commentsItem setTag:DASM_RIGHTCOL_COMMENTS]; |
| 352 | | } |
| 353 | | if (index < [menu numberOfItems]) |
| 354 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 355 | | } |
| 356 | | |
| 357 | | |
| 358 | | - (void)insertSubviewItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index { |
| 359 | | for (const debug_view_source *source = view->source_list().first(); source != NULL; source = source->next()) |
| 360 | | { |
| 361 | | [[menu insertItemWithTitle:[NSString stringWithUTF8String:source->name()] |
| 362 | | action:NULL |
| 363 | | keyEquivalent:@"" |
| 364 | | atIndex:index++] setTag:view->source_list().indexof(*source)]; |
| 365 | | } |
| 366 | | if (index < [menu numberOfItems]) |
| 367 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 368 | | } |
| 369 | | |
| 370 | | @end |
trunk/src/osd/modules/debugger/osx/debugosxdisassemblyviewer.m
| r243595 | r243596 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // debugosxdisassemblyviewer.m - MacOS X Cocoa debug window handling |
| 6 | | // |
| 7 | | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | | // |
| 10 | | //============================================================ |
| 11 | | |
| 12 | | #import "debugosxdisassemblyviewer.h" |
| 13 | | |
| 14 | | #import "debugosxdebugview.h" |
| 15 | | #import "debugosxdisassemblyview.h" |
| 16 | | |
| 17 | | #include "debug/debugcpu.h" |
| 18 | | |
| 19 | | |
| 20 | | @implementation MAMEDisassemblyViewer |
| 21 | | |
| 22 | | - (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c { |
| 23 | | NSScrollView *dasmScroll; |
| 24 | | NSView *expressionContainer; |
| 25 | | NSPopUpButton *actionButton, *subviewButton; |
| 26 | | NSRect contentBounds, expressionFrame; |
| 27 | | |
| 28 | | if (!(self = [super initWithMachine:m title:@"Disassembly" console:c])) |
| 29 | | return nil; |
| 30 | | contentBounds = [[window contentView] bounds]; |
| 31 | | |
| 32 | | // create the expression field |
| 33 | | expressionField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)]; |
| 34 | | [expressionField setAutoresizingMask:(NSViewWidthSizable | NSViewMaxXMargin | NSViewMinYMargin)]; |
| 35 | | [expressionField setFont:[[MAMEDebugView class] defaultFont]]; |
| 36 | | [expressionField setFocusRingType:NSFocusRingTypeNone]; |
| 37 | | [expressionField setTarget:self]; |
| 38 | | [expressionField setAction:@selector(doExpression:)]; |
| 39 | | [expressionField setDelegate:self]; |
| 40 | | expressionFrame = [expressionField frame]; |
| 41 | | expressionFrame.size.width = (contentBounds.size.width - expressionFrame.size.height) / 2; |
| 42 | | [expressionField setFrameSize:expressionFrame.size]; |
| 43 | | |
| 44 | | // create the subview popup |
| 45 | | subviewButton = [[NSPopUpButton alloc] initWithFrame:NSOffsetRect(expressionFrame, |
| 46 | | expressionFrame.size.width, |
| 47 | | 0)]; |
| 48 | | [subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinXMargin | NSViewMinYMargin)]; |
| 49 | | [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle]; |
| 50 | | [subviewButton setFocusRingType:NSFocusRingTypeNone]; |
| 51 | | [subviewButton setFont:[[MAMEDebugView class] defaultFont]]; |
| 52 | | [subviewButton setTarget:self]; |
| 53 | | [subviewButton setAction:@selector(changeSubview:)]; |
| 54 | | [[subviewButton cell] setArrowPosition:NSPopUpArrowAtBottom]; |
| 55 | | |
| 56 | | // create a container for the expression field and subview popup |
| 57 | | expressionFrame = NSMakeRect(expressionFrame.size.height, |
| 58 | | contentBounds.size.height - expressionFrame.size.height, |
| 59 | | contentBounds.size.width - expressionFrame.size.height, |
| 60 | | expressionFrame.size.height); |
| 61 | | expressionContainer = [[NSView alloc] initWithFrame:expressionFrame]; |
| 62 | | [expressionContainer setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)]; |
| 63 | | [expressionContainer addSubview:expressionField]; |
| 64 | | [expressionField release]; |
| 65 | | [expressionContainer addSubview:subviewButton]; |
| 66 | | [subviewButton release]; |
| 67 | | [[window contentView] addSubview:expressionContainer]; |
| 68 | | [expressionContainer release]; |
| 69 | | |
| 70 | | // create the disassembly view |
| 71 | | dasmView = [[MAMEDisassemblyView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) |
| 72 | | machine:*machine |
| 73 | | useConsole:NO]; |
| 74 | | [dasmView insertSubviewItemsInMenu:[subviewButton menu] atIndex:0]; |
| 75 | | dasmScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, |
| 76 | | 0, |
| 77 | | contentBounds.size.width, |
| 78 | | expressionFrame.origin.y)]; |
| 79 | | [dasmScroll setDrawsBackground:YES]; |
| 80 | | [dasmScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 81 | | [dasmScroll setHasHorizontalScroller:YES]; |
| 82 | | [dasmScroll setHasVerticalScroller:YES]; |
| 83 | | [dasmScroll setAutohidesScrollers:YES]; |
| 84 | | [dasmScroll setBorderType:NSNoBorder]; |
| 85 | | [dasmScroll setDocumentView:dasmView]; |
| 86 | | [dasmView release]; |
| 87 | | [[window contentView] addSubview:dasmScroll]; |
| 88 | | [dasmScroll release]; |
| 89 | | |
| 90 | | // create the action popup |
| 91 | | actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0, |
| 92 | | expressionFrame.origin.y, |
| 93 | | expressionFrame.size.height, |
| 94 | | expressionFrame.size.height)]; |
| 95 | | [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)]; |
| 96 | | [dasmView insertActionItemsInMenu:[actionButton menu] atIndex:1]; |
| 97 | | [[window contentView] addSubview:actionButton]; |
| 98 | | [actionButton release]; |
| 99 | | |
| 100 | | // set default state |
| 101 | | [dasmView selectSubviewForCPU:debug_cpu_get_visible_cpu(*machine)]; |
| 102 | | [dasmView setExpression:@"curpc"]; |
| 103 | | [expressionField setStringValue:@"curpc"]; |
| 104 | | [expressionField selectText:self]; |
| 105 | | [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[dasmView selectedSubviewIndex]]]; |
| 106 | | [window makeFirstResponder:expressionField]; |
| 107 | | [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]]; |
| 108 | | |
| 109 | | // calculate the optimal size for everything |
| 110 | | { |
| 111 | | NSSize desired = [NSScrollView frameSizeForContentSize:[dasmView maximumFrameSize] |
| 112 | | hasHorizontalScroller:YES |
| 113 | | hasVerticalScroller:YES |
| 114 | | borderType:[dasmScroll borderType]]; |
| 115 | | [self cascadeWindowWithDesiredSize:desired forView:dasmScroll]; |
| 116 | | } |
| 117 | | |
| 118 | | // don't forget the result |
| 119 | | return self; |
| 120 | | } |
| 121 | | |
| 122 | | |
| 123 | | - (void)dealloc { |
| 124 | | [super dealloc]; |
| 125 | | } |
| 126 | | |
| 127 | | |
| 128 | | - (id <MAMEDebugViewExpressionSupport>)documentView { |
| 129 | | return dasmView; |
| 130 | | } |
| 131 | | |
| 132 | | |
| 133 | | - (IBAction)changeSubview:(id)sender { |
| 134 | | [dasmView selectSubviewAtIndex:[[sender selectedItem] tag]]; |
| 135 | | [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]]; |
| 136 | | } |
| 137 | | |
| 138 | | @end |
trunk/src/osd/modules/debugger/osx/debugosxmemoryview.m
| r243595 | r243596 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // debugosxmemoryview.m - MacOS X Cocoa debug window handling |
| 6 | | // |
| 7 | | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | | // |
| 10 | | //============================================================ |
| 11 | | |
| 12 | | #import "debugosxmemoryview.h" |
| 13 | | |
| 14 | | #include "debug/debugcpu.h" |
| 15 | | #include "debug/debugvw.h" |
| 16 | | #include "debug/dvmemory.h" |
| 17 | | |
| 18 | | |
| 19 | | @implementation MAMEMemoryView |
| 20 | | |
| 21 | | - (id)initWithFrame:(NSRect)f machine:(running_machine &)m { |
| 22 | | NSMenu *contextMenu; |
| 23 | | |
| 24 | | if (!(self = [super initWithFrame:f type:DVT_MEMORY machine:m])) |
| 25 | | return nil; |
| 26 | | |
| 27 | | contextMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Memory"]; |
| 28 | | [self insertActionItemsInMenu:contextMenu atIndex:0]; |
| 29 | | [self setMenu:contextMenu]; |
| 30 | | [contextMenu release]; |
| 31 | | |
| 32 | | return self; |
| 33 | | } |
| 34 | | |
| 35 | | |
| 36 | | - (void)dealloc { |
| 37 | | [super dealloc]; |
| 38 | | } |
| 39 | | |
| 40 | | |
| 41 | | - (BOOL)validateMenuItem:(NSMenuItem *)item { |
| 42 | | SEL action = [item action]; |
| 43 | | NSInteger tag = [item tag]; |
| 44 | | debug_view_memory *memview = downcast<debug_view_memory *>(view); |
| 45 | | |
| 46 | | if (action == @selector(showChunkSize:)) { |
| 47 | | [item setState:((tag == memview->bytes_per_chunk()) ? NSOnState : NSOffState)]; |
| 48 | | } else if (action == @selector(showPhysicalAddresses:)) { |
| 49 | | [item setState:((tag == memview->physical()) ? NSOnState : NSOffState)]; |
| 50 | | } else if (action == @selector(showReverseView:)) { |
| 51 | | [item setState:((tag == memview->reverse()) ? NSOnState : NSOffState)]; |
| 52 | | } else if (action == @selector(showReverseViewToggle:)) { |
| 53 | | [item setState:(memview->reverse() ? NSOnState : NSOffState)]; |
| 54 | | } |
| 55 | | return YES; |
| 56 | | } |
| 57 | | |
| 58 | | |
| 59 | | - (NSSize)maximumFrameSize { |
| 60 | | debug_view_xy max; |
| 61 | | device_t *curcpu = debug_cpu_get_visible_cpu(*machine); |
| 62 | | debug_view_source const *source = view->source_for_device(curcpu); |
| 63 | | |
| 64 | | max.x = max.y = 0; |
| 65 | | for (const debug_view_source *source = view->source_list().first(); |
| 66 | | source != NULL; |
| 67 | | source = source->next()) |
| 68 | | { |
| 69 | | debug_view_xy current; |
| 70 | | view->set_source(*source); |
| 71 | | current = view->total_size(); |
| 72 | | if (current.x > max.x) |
| 73 | | max.x = current.x; |
| 74 | | if (current.y > max.y) |
| 75 | | max.y = current.y; |
| 76 | | } |
| 77 | | view->set_source(*source); |
| 78 | | return NSMakeSize(max.x * fontWidth, max.y * fontHeight); |
| 79 | | } |
| 80 | | |
| 81 | | |
| 82 | | - (NSString *)selectedSubviewName { |
| 83 | | debug_view_source const *source = view->source(); |
| 84 | | if (source != NULL) |
| 85 | | return [NSString stringWithUTF8String:source->name()]; |
| 86 | | else |
| 87 | | return @""; |
| 88 | | } |
| 89 | | |
| 90 | | |
| 91 | | - (int)selectedSubviewIndex { |
| 92 | | debug_view_source const *source = view->source(); |
| 93 | | if (source != NULL) |
| 94 | | return view->source_list().indexof(*source); |
| 95 | | else |
| 96 | | return -1; |
| 97 | | } |
| 98 | | |
| 99 | | |
| 100 | | - (void)selectSubviewAtIndex:(int)index { |
| 101 | | int const selected = view->source_list().indexof(*view->source()); |
| 102 | | if (selected != index) { |
| 103 | | view->set_source(*view->source_list().find(index)); |
| 104 | | if ([[self window] firstResponder] != self) |
| 105 | | view->set_cursor_visible(false); |
| 106 | | } |
| 107 | | } |
| 108 | | |
| 109 | | |
| 110 | | - (void)selectSubviewForCPU:(device_t *)device { |
| 111 | | debug_view_source const *selected = view->source(); |
| 112 | | debug_view_source const *source = view->source_for_device(device); |
| 113 | | if ( selected != source ) { |
| 114 | | view->set_source(*source); |
| 115 | | if ([[self window] firstResponder] != self) |
| 116 | | view->set_cursor_visible(false); |
| 117 | | } |
| 118 | | } |
| 119 | | |
| 120 | | |
| 121 | | - (NSString *)expression { |
| 122 | | return [NSString stringWithUTF8String:downcast<debug_view_memory *>(view)->expression()]; |
| 123 | | } |
| 124 | | |
| 125 | | |
| 126 | | - (void)setExpression:(NSString *)exp { |
| 127 | | downcast<debug_view_memory *>(view)->set_expression([exp UTF8String]); |
| 128 | | } |
| 129 | | |
| 130 | | |
| 131 | | - (IBAction)showChunkSize:(id)sender { |
| 132 | | downcast<debug_view_memory *>(view)->set_bytes_per_chunk([sender tag]); |
| 133 | | } |
| 134 | | |
| 135 | | |
| 136 | | - (IBAction)showPhysicalAddresses:(id)sender { |
| 137 | | downcast<debug_view_memory *>(view)->set_physical([sender tag]); |
| 138 | | } |
| 139 | | |
| 140 | | |
| 141 | | - (IBAction)showReverseView:(id)sender { |
| 142 | | downcast<debug_view_memory *>(view)->set_reverse([sender tag]); |
| 143 | | } |
| 144 | | |
| 145 | | |
| 146 | | - (IBAction)showReverseViewToggle:(id)sender { |
| 147 | | downcast<debug_view_memory *>(view)->set_reverse(!downcast<debug_view_memory *>(view)->reverse()); |
| 148 | | } |
| 149 | | |
| 150 | | |
| 151 | | - (IBAction)changeBytesPerLine:(id)sender { |
| 152 | | debug_view_memory *const memView = downcast<debug_view_memory *>(view); |
| 153 | | memView->set_chunks_per_row(memView->chunks_per_row() + [sender tag]); |
| 154 | | } |
| 155 | | |
| 156 | | |
| 157 | | - (void)insertActionItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index { |
| 158 | | NSInteger tag; |
| 159 | | for (tag = 1; tag <= 8; tag <<= 1) { |
| 160 | | NSString *title = [NSString stringWithFormat:@"%ld-byte Chunks", (long)tag]; |
| 161 | | NSMenuItem *chunkItem = [menu insertItemWithTitle:title |
| 162 | | action:@selector(showChunkSize:) |
| 163 | | keyEquivalent:[NSString stringWithFormat:@"%ld", (long)tag] |
| 164 | | atIndex:index++]; |
| 165 | | [chunkItem setTarget:self]; |
| 166 | | [chunkItem setTag:tag]; |
| 167 | | } |
| 168 | | |
| 169 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 170 | | |
| 171 | | NSMenuItem *logicalItem = [menu insertItemWithTitle:@"Logical Addresses" |
| 172 | | action:@selector(showPhysicalAddresses:) |
| 173 | | keyEquivalent:@"v" |
| 174 | | atIndex:index++]; |
| 175 | | [logicalItem setTarget:self]; |
| 176 | | [logicalItem setTag:FALSE]; |
| 177 | | |
| 178 | | NSMenuItem *physicalItem = [menu insertItemWithTitle:@"Physical Addresses" |
| 179 | | action:@selector(showPhysicalAddresses:) |
| 180 | | keyEquivalent:@"y" |
| 181 | | atIndex:index++]; |
| 182 | | [physicalItem setTarget:self]; |
| 183 | | [physicalItem setTag:TRUE]; |
| 184 | | |
| 185 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 186 | | |
| 187 | | NSMenuItem *reverseItem = [menu insertItemWithTitle:@"Reverse View" |
| 188 | | action:@selector(showReverseViewToggle:) |
| 189 | | keyEquivalent:@"r" |
| 190 | | atIndex:index++]; |
| 191 | | [reverseItem setTarget:self]; |
| 192 | | |
| 193 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 194 | | |
| 195 | | NSMenuItem *increaseItem = [menu insertItemWithTitle:@"Increase Bytes Per Line" |
| 196 | | action:@selector(changeBytesPerLine:) |
| 197 | | keyEquivalent:@"p" |
| 198 | | atIndex:index++]; |
| 199 | | [increaseItem setTarget:self]; |
| 200 | | [increaseItem setTag:1]; |
| 201 | | |
| 202 | | NSMenuItem *decreaseItem = [menu insertItemWithTitle:@"Decrease Bytes Per Line" |
| 203 | | action:@selector(changeBytesPerLine:) |
| 204 | | keyEquivalent:@"o" |
| 205 | | atIndex:index++]; |
| 206 | | [decreaseItem setTarget:self]; |
| 207 | | [decreaseItem setTag:-1]; |
| 208 | | |
| 209 | | if (index < [menu numberOfItems]) |
| 210 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 211 | | } |
| 212 | | |
| 213 | | |
| 214 | | - (void)insertSubviewItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index { |
| 215 | | for (const debug_view_source *source = view->source_list().first(); source != NULL; source = source->next()) |
| 216 | | { |
| 217 | | [[menu insertItemWithTitle:[NSString stringWithUTF8String:source->name()] |
| 218 | | action:NULL |
| 219 | | keyEquivalent:@"" |
| 220 | | atIndex:index++] setTag:view->source_list().indexof(*source)]; |
| 221 | | } |
| 222 | | if (index < [menu numberOfItems]) |
| 223 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 224 | | } |
| 225 | | |
| 226 | | @end |
trunk/src/osd/modules/debugger/osx/debugosxmemoryviewer.m
| r243595 | r243596 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // debugosxmemoryviewer.m - MacOS X Cocoa debug window handling |
| 6 | | // |
| 7 | | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | | // |
| 10 | | //============================================================ |
| 11 | | |
| 12 | | #import "debugosxmemoryviewer.h" |
| 13 | | |
| 14 | | #import "debugosxdebugview.h" |
| 15 | | #import "debugosxmemoryview.h" |
| 16 | | |
| 17 | | #include "debug/debugcpu.h" |
| 18 | | |
| 19 | | |
| 20 | | @implementation MAMEMemoryViewer |
| 21 | | |
| 22 | | - (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c { |
| 23 | | NSScrollView *memoryScroll; |
| 24 | | NSView *expressionContainer; |
| 25 | | NSPopUpButton *actionButton, *subviewButton; |
| 26 | | NSRect contentBounds, expressionFrame; |
| 27 | | |
| 28 | | if (!(self = [super initWithMachine:m title:@"Memory" console:c])) |
| 29 | | return nil; |
| 30 | | contentBounds = [[window contentView] bounds]; |
| 31 | | |
| 32 | | // create the expression field |
| 33 | | expressionField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)]; |
| 34 | | [expressionField setAutoresizingMask:(NSViewWidthSizable | NSViewMaxXMargin | NSViewMinYMargin)]; |
| 35 | | [expressionField setFont:[[MAMEDebugView class] defaultFont]]; |
| 36 | | [expressionField setFocusRingType:NSFocusRingTypeNone]; |
| 37 | | [expressionField setTarget:self]; |
| 38 | | [expressionField setAction:@selector(doExpression:)]; |
| 39 | | [expressionField setDelegate:self]; |
| 40 | | expressionFrame = [expressionField frame]; |
| 41 | | expressionFrame.size.width = (contentBounds.size.width - expressionFrame.size.height) / 2; |
| 42 | | [expressionField setFrameSize:expressionFrame.size]; |
| 43 | | |
| 44 | | // create the subview popup |
| 45 | | subviewButton = [[NSPopUpButton alloc] initWithFrame:NSOffsetRect(expressionFrame, |
| 46 | | expressionFrame.size.width, |
| 47 | | 0)]; |
| 48 | | [subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinXMargin | NSViewMinYMargin)]; |
| 49 | | [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle]; |
| 50 | | [subviewButton setFocusRingType:NSFocusRingTypeNone]; |
| 51 | | [subviewButton setFont:[[MAMEDebugView class] defaultFont]]; |
| 52 | | [subviewButton setTarget:self]; |
| 53 | | [subviewButton setAction:@selector(changeSubview:)]; |
| 54 | | [[subviewButton cell] setArrowPosition:NSPopUpArrowAtBottom]; |
| 55 | | |
| 56 | | // create a container for the expression field and subview popup |
| 57 | | expressionFrame = NSMakeRect(expressionFrame.size.height, |
| 58 | | contentBounds.size.height - expressionFrame.size.height, |
| 59 | | contentBounds.size.width - expressionFrame.size.height, |
| 60 | | expressionFrame.size.height); |
| 61 | | expressionContainer = [[NSView alloc] initWithFrame:expressionFrame]; |
| 62 | | [expressionContainer setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)]; |
| 63 | | [expressionContainer addSubview:expressionField]; |
| 64 | | [expressionField release]; |
| 65 | | [expressionContainer addSubview:subviewButton]; |
| 66 | | [subviewButton release]; |
| 67 | | [[window contentView] addSubview:expressionContainer]; |
| 68 | | [expressionContainer release]; |
| 69 | | |
| 70 | | // create the memory view |
| 71 | | memoryView = [[MAMEMemoryView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) |
| 72 | | machine:*machine]; |
| 73 | | [memoryView insertSubviewItemsInMenu:[subviewButton menu] atIndex:0]; |
| 74 | | memoryScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, |
| 75 | | 0, |
| 76 | | contentBounds.size.width, |
| 77 | | expressionFrame.origin.y)]; |
| 78 | | [memoryScroll setDrawsBackground:YES]; |
| 79 | | [memoryScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 80 | | [memoryScroll setHasHorizontalScroller:YES]; |
| 81 | | [memoryScroll setHasVerticalScroller:YES]; |
| 82 | | [memoryScroll setAutohidesScrollers:YES]; |
| 83 | | [memoryScroll setBorderType:NSNoBorder]; |
| 84 | | [memoryScroll setDocumentView:memoryView]; |
| 85 | | [memoryView release]; |
| 86 | | [[window contentView] addSubview:memoryScroll]; |
| 87 | | [memoryScroll release]; |
| 88 | | |
| 89 | | // create the action popup |
| 90 | | actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0, |
| 91 | | expressionFrame.origin.y, |
| 92 | | expressionFrame.size.height, |
| 93 | | expressionFrame.size.height)]; |
| 94 | | [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)]; |
| 95 | | [memoryView insertActionItemsInMenu:[actionButton menu] atIndex:1]; |
| 96 | | [[window contentView] addSubview:actionButton]; |
| 97 | | [actionButton release]; |
| 98 | | |
| 99 | | // set default state |
| 100 | | [memoryView selectSubviewForCPU:debug_cpu_get_visible_cpu(*machine)]; |
| 101 | | [memoryView setExpression:@"0"]; |
| 102 | | [expressionField setStringValue:@"0"]; |
| 103 | | [expressionField selectText:self]; |
| 104 | | [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[memoryView selectedSubviewIndex]]]; |
| 105 | | [window makeFirstResponder:expressionField]; |
| 106 | | [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]]; |
| 107 | | |
| 108 | | // calculate the optimal size for everything |
| 109 | | NSSize const desired = [NSScrollView frameSizeForContentSize:[memoryView maximumFrameSize] |
| 110 | | hasHorizontalScroller:YES |
| 111 | | hasVerticalScroller:YES |
| 112 | | borderType:[memoryScroll borderType]]; |
| 113 | | [self cascadeWindowWithDesiredSize:desired forView:memoryScroll]; |
| 114 | | |
| 115 | | // don't forget the result |
| 116 | | return self; |
| 117 | | } |
| 118 | | |
| 119 | | |
| 120 | | - (void)dealloc { |
| 121 | | [super dealloc]; |
| 122 | | } |
| 123 | | |
| 124 | | |
| 125 | | - (id <MAMEDebugViewExpressionSupport>)documentView { |
| 126 | | return memoryView; |
| 127 | | } |
| 128 | | |
| 129 | | |
| 130 | | - (IBAction)changeSubview:(id)sender { |
| 131 | | [memoryView selectSubviewAtIndex:[[sender selectedItem] tag]]; |
| 132 | | [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]]; |
| 133 | | } |
| 134 | | |
| 135 | | @end |
trunk/src/osd/modules/debugger/osx/debugosxpointsviewer.m
| r243595 | r243596 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // debugosxpointsviewer.m - MacOS X Cocoa debug window handling |
| 6 | | // |
| 7 | | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | | // |
| 10 | | //============================================================ |
| 11 | | |
| 12 | | #import "debugosxpointsviewer.h" |
| 13 | | |
| 14 | | #import "debugosxbreakpointsview.h" |
| 15 | | #import "debugosxwatchpointsview.h" |
| 16 | | |
| 17 | | |
| 18 | | @implementation MAMEPointsViewer |
| 19 | | |
| 20 | | - (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c { |
| 21 | | MAMEDebugView *breakView, *watchView; |
| 22 | | NSScrollView *breakScroll, *watchScroll; |
| 23 | | NSTabViewItem *breakTab, *watchTab; |
| 24 | | NSPopUpButton *actionButton, *subviewButton; |
| 25 | | NSRect contentBounds; |
| 26 | | |
| 27 | | if (!(self = [super initWithMachine:m title:@"(Break|Watch)points" console:c])) |
| 28 | | return nil; |
| 29 | | contentBounds = [[window contentView] bounds]; |
| 30 | | |
| 31 | | // create the subview popup |
| 32 | | subviewButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(19, |
| 33 | | contentBounds.size.height - 19, |
| 34 | | contentBounds.size.width - 19, |
| 35 | | 19)]; |
| 36 | | [subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)]; |
| 37 | | [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle]; |
| 38 | | [subviewButton setFocusRingType:NSFocusRingTypeNone]; |
| 39 | | [subviewButton setFont:[[MAMEDebugView class] defaultFont]]; |
| 40 | | [subviewButton setTarget:self]; |
| 41 | | [subviewButton setAction:@selector(changeSubview:)]; |
| 42 | | [[subviewButton cell] setArrowPosition:NSPopUpArrowAtBottom]; |
| 43 | | [[[subviewButton menu] addItemWithTitle:@"All Breakpoints" |
| 44 | | action:NULL |
| 45 | | keyEquivalent:@""] setTag:0]; |
| 46 | | [[[subviewButton menu] addItemWithTitle:@"All Watchpoints" |
| 47 | | action:NULL |
| 48 | | keyEquivalent:@""] setTag:1]; |
| 49 | | [[window contentView] addSubview:subviewButton]; |
| 50 | | [subviewButton release]; |
| 51 | | |
| 52 | | // create the action popup |
| 53 | | actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0, |
| 54 | | contentBounds.size.height - 19, |
| 55 | | 19, |
| 56 | | 19)]; |
| 57 | | [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)]; |
| 58 | | [[window contentView] addSubview:actionButton]; |
| 59 | | [actionButton release]; |
| 60 | | |
| 61 | | // create the breakpoints view |
| 62 | | breakView = [[MAMEBreakpointsView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) |
| 63 | | machine:*machine]; |
| 64 | | breakScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, |
| 65 | | 0, |
| 66 | | contentBounds.size.width, |
| 67 | | contentBounds.size.height - 19)]; |
| 68 | | [breakScroll setDrawsBackground:YES]; |
| 69 | | [breakScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 70 | | [breakScroll setHasHorizontalScroller:YES]; |
| 71 | | [breakScroll setHasVerticalScroller:YES]; |
| 72 | | [breakScroll setAutohidesScrollers:YES]; |
| 73 | | [breakScroll setBorderType:NSNoBorder]; |
| 74 | | [breakScroll setDocumentView:breakView]; |
| 75 | | [breakView release]; |
| 76 | | breakTab = [[NSTabViewItem alloc] initWithIdentifier:nil]; |
| 77 | | [breakTab setView:breakScroll]; |
| 78 | | [breakScroll release]; |
| 79 | | |
| 80 | | // create the breakpoints view |
| 81 | | watchView = [[MAMEWatchpointsView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) |
| 82 | | machine:*machine]; |
| 83 | | watchScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, |
| 84 | | 0, |
| 85 | | contentBounds.size.width, |
| 86 | | contentBounds.size.height - 19)]; |
| 87 | | [watchScroll setDrawsBackground:YES]; |
| 88 | | [watchScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 89 | | [watchScroll setHasHorizontalScroller:YES]; |
| 90 | | [watchScroll setHasVerticalScroller:YES]; |
| 91 | | [watchScroll setAutohidesScrollers:YES]; |
| 92 | | [watchScroll setBorderType:NSNoBorder]; |
| 93 | | [watchScroll setDocumentView:watchView]; |
| 94 | | [watchView release]; |
| 95 | | watchTab = [[NSTabViewItem alloc] initWithIdentifier:nil]; |
| 96 | | [watchTab setView:watchScroll]; |
| 97 | | [watchScroll release]; |
| 98 | | |
| 99 | | // create a tabless tabview for the two subviews |
| 100 | | tabs = [[NSTabView alloc] initWithFrame:NSMakeRect(0, |
| 101 | | 0, |
| 102 | | contentBounds.size.width, |
| 103 | | contentBounds.size.height - 19)]; |
| 104 | | [tabs setTabViewType:NSNoTabsNoBorder]; |
| 105 | | [tabs setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 106 | | [tabs addTabViewItem:breakTab]; |
| 107 | | [breakTab release]; |
| 108 | | [tabs addTabViewItem:watchTab]; |
| 109 | | [watchTab release]; |
| 110 | | [[window contentView] addSubview:tabs]; |
| 111 | | [tabs release]; |
| 112 | | |
| 113 | | // set default state |
| 114 | | [subviewButton selectItemAtIndex:0]; |
| 115 | | [tabs selectFirstTabViewItem:self]; |
| 116 | | [window makeFirstResponder:subviewButton]; |
| 117 | | [window setTitle:[[subviewButton selectedItem] title]]; |
| 118 | | |
| 119 | | // calculate the optimal size for everything |
| 120 | | NSSize const breakDesired = [NSScrollView frameSizeForContentSize:[breakView maximumFrameSize] |
| 121 | | hasHorizontalScroller:YES |
| 122 | | hasVerticalScroller:YES |
| 123 | | borderType:[breakScroll borderType]]; |
| 124 | | NSSize const watchDesired = [NSScrollView frameSizeForContentSize:[watchView maximumFrameSize] |
| 125 | | hasHorizontalScroller:YES |
| 126 | | hasVerticalScroller:YES |
| 127 | | borderType:[watchScroll borderType]]; |
| 128 | | NSSize const desired = NSMakeSize(MAX(breakDesired.width, watchDesired.width), |
| 129 | | MAX(breakDesired.height, watchDesired.height)); |
| 130 | | [self cascadeWindowWithDesiredSize:desired forView:tabs]; |
| 131 | | |
| 132 | | // don't forget the result |
| 133 | | return self; |
| 134 | | } |
| 135 | | |
| 136 | | |
| 137 | | - (void)dealloc { |
| 138 | | [super dealloc]; |
| 139 | | } |
| 140 | | |
| 141 | | |
| 142 | | - (IBAction)changeSubview:(id)sender { |
| 143 | | [tabs selectTabViewItemAtIndex:[[sender selectedItem] tag]]; |
| 144 | | [window setTitle:[[sender selectedItem] title]]; |
| 145 | | } |
| 146 | | |
| 147 | | @end |
trunk/src/osd/modules/debugger/osx/debugview.m
| r0 | r243596 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:Vas Crabb |
| 3 | //============================================================ |
| 4 | // |
| 5 | // debugosxdebugview.h - MacOS X Cocoa debug window handling |
| 6 | // |
| 7 | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | // |
| 10 | //============================================================ |
| 11 | |
| 12 | #import "debugview.h" |
| 13 | |
| 14 | #include "debug/debugcpu.h" |
| 15 | |
| 16 | |
| 17 | static void debugwin_view_update(debug_view &view, void *osdprivate) |
| 18 | { |
| 19 | [(MAMEDebugView *)osdprivate update]; |
| 20 | } |
| 21 | |
| 22 | |
| 23 | @implementation MAMEDebugView |
| 24 | |
| 25 | - (NSColor *)foregroundForAttribute:(UINT8)attrib { |
| 26 | const CGFloat alpha = (attrib & DCA_DISABLED) ? 0.5 : 1.0; |
| 27 | if (attrib & DCA_COMMENT) |
| 28 | return [NSColor colorWithCalibratedRed:0.0 green:0.375 blue:0.0 alpha:1.0]; |
| 29 | else if (attrib & DCA_INVALID) |
| 30 | return [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:1.0 alpha:alpha]; |
| 31 | else if (attrib & DCA_CHANGED) |
| 32 | return [NSColor colorWithCalibratedRed:0.875 green:0.0 blue:0.0 alpha:alpha]; |
| 33 | else |
| 34 | return [NSColor colorWithCalibratedWhite:0.0 alpha:alpha]; |
| 35 | } |
| 36 | |
| 37 | |
| 38 | - (NSColor *)backgroundForAttribute:(UINT8)attrib { |
| 39 | if ((attrib & DCA_SELECTED) && (attrib & DCA_CURRENT)) { |
| 40 | if ([[self window] isKeyWindow] && ([[self window] firstResponder] == self)) |
| 41 | return [NSColor colorWithCalibratedRed:0.875 green:0.625 blue:0.875 alpha:1.0]; |
| 42 | else |
| 43 | return [NSColor colorWithCalibratedRed:0.875 green:0.5 blue:0.625 alpha:1.0]; |
| 44 | } else if (attrib & DCA_CURRENT) { |
| 45 | return [NSColor colorWithCalibratedRed:1.0 green:0.625 blue:0.625 alpha:1.0]; |
| 46 | } else if (attrib & DCA_SELECTED) { |
| 47 | if ([[self window] isKeyWindow] && ([[self window] firstResponder] == self)) |
| 48 | return [NSColor colorWithCalibratedRed:0.75 green:0.875 blue:1.0 alpha:1.0]; |
| 49 | else |
| 50 | return [NSColor colorWithCalibratedWhite:0.875 alpha:1.0]; |
| 51 | } else if (attrib & DCA_ANCILLARY) { |
| 52 | return [NSColor colorWithCalibratedWhite:0.75 alpha:1.0]; |
| 53 | } else { |
| 54 | return [NSColor colorWithCalibratedWhite:1.0 alpha:1.0]; |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | |
| 59 | - (debug_view_xy)convertLocation:(NSPoint)location { |
| 60 | debug_view_xy position; |
| 61 | |
| 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 | [text deleteCharactersInRange:NSMakeRange(0, length)]; |
| 114 | } |
| 115 | if (position.x < 0) |
| 116 | position.x = 0; |
| 117 | else if (position.x >= totalWidth) |
| 118 | position.x = totalWidth - 1; |
| 119 | |
| 120 | return position; |
| 121 | } |
| 122 | |
| 123 | |
| 124 | - (void)convertBounds:(NSRect)b toPosition:(debug_view_xy *)origin size:(debug_view_xy *)size { |
| 125 | origin->x = lround(floor(b.origin.x / fontWidth)); |
| 126 | origin->y = lround(floor(b.origin.y / fontHeight)); |
| 127 | |
| 128 | // FIXME: this is not using proper font metrics horizontally |
| 129 | size->x = lround(ceil((b.origin.x + b.size.width) / fontWidth)) - origin->x; |
| 130 | size->y = lround(ceil((b.origin.y + b.size.height) / fontHeight)) - origin->y; |
| 131 | } |
| 132 | |
| 133 | |
| 134 | - (void)recomputeVisible { |
| 135 | if ([self window] != nil) { |
| 136 | debug_view_xy origin, size; |
| 137 | |
| 138 | // this gets all the characters that are at least paritally visible |
| 139 | [self convertBounds:[self visibleRect] toPosition:&origin size:&size]; |
| 140 | |
| 141 | // need to render entire lines or we get screwed up characters when widening views |
| 142 | origin.x = 0; |
| 143 | size.x = totalWidth; |
| 144 | |
| 145 | // tell them what we think |
| 146 | view->set_visible_size(size); |
| 147 | view->set_visible_position(origin); |
| 148 | originLeft = origin.x; |
| 149 | originTop = origin.y; |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | |
| 154 | - (void)typeCharacterAndScrollToCursor:(char)ch { |
| 155 | if (view->cursor_supported()) { |
| 156 | debug_view_xy oldPos = view->cursor_position(); |
| 157 | view->process_char(ch); |
| 158 | { |
| 159 | debug_view_xy newPos = view->cursor_position(); |
| 160 | if ((newPos.x != oldPos.x) || (newPos.y != oldPos.y)) { |
| 161 | [self scrollRectToVisible:NSMakeRect(newPos.x * fontWidth, // FIXME - use proper metrics |
| 162 | newPos.y * fontHeight, |
| 163 | fontWidth, |
| 164 | fontHeight)]; |
| 165 | } |
| 166 | } |
| 167 | } else { |
| 168 | view->process_char(ch); |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | |
| 173 | + (NSFont *)defaultFont { |
| 174 | return [NSFont userFixedPitchFontOfSize:0]; |
| 175 | } |
| 176 | |
| 177 | |
| 178 | - (id)initWithFrame:(NSRect)f type:(debug_view_type)t machine:(running_machine &)m { |
| 179 | if (!(self = [super initWithFrame:f])) |
| 180 | return nil; |
| 181 | type = t; |
| 182 | machine = &m; |
| 183 | view = machine->debug_view().alloc_view((debug_view_type)type, debugwin_view_update, self); |
| 184 | if (view == nil) { |
| 185 | [self release]; |
| 186 | return nil; |
| 187 | } |
| 188 | totalWidth = totalHeight = 0; |
| 189 | originLeft = originTop = 0; |
| 190 | |
| 191 | text = [[NSTextStorage alloc] init]; |
| 192 | textContainer = [[NSTextContainer alloc] init]; |
| 193 | layoutManager = [[NSLayoutManager alloc] init]; |
| 194 | [layoutManager addTextContainer:textContainer]; |
| 195 | [textContainer release]; |
| 196 | [text addLayoutManager:layoutManager]; |
| 197 | [layoutManager release]; |
| 198 | |
| 199 | [self setFont:[[self class] defaultFont]]; |
| 200 | |
| 201 | return self; |
| 202 | } |
| 203 | |
| 204 | |
| 205 | - (void)dealloc { |
| 206 | [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 207 | if (font != nil) [font release]; |
| 208 | if (text != nil) [text release]; |
| 209 | [super dealloc]; |
| 210 | } |
| 211 | |
| 212 | |
| 213 | - (void)update { |
| 214 | debug_view_xy newSize, newOrigin; |
| 215 | |
| 216 | // resize our frame if the total size has changed |
| 217 | newSize = view->total_size(); |
| 218 | if ((newSize.x != totalWidth) || (newSize.y != totalHeight)) { |
| 219 | [self setFrameSize:NSMakeSize(fontWidth * newSize.x, fontHeight * newSize.y)]; // FIXME: metrics |
| 220 | totalWidth = newSize.x; |
| 221 | totalHeight = newSize.y; |
| 222 | } |
| 223 | |
| 224 | // scroll the view if we're being told to |
| 225 | newOrigin = view->visible_position(); |
| 226 | if (newOrigin.y != originTop) { |
| 227 | [self scrollPoint:NSMakePoint([self visibleRect].origin.x, newOrigin.y * fontHeight)]; |
| 228 | originTop = newOrigin.y; |
| 229 | } |
| 230 | |
| 231 | // recompute the visible area and mark as dirty |
| 232 | [self recomputeVisible]; |
| 233 | [self setNeedsDisplay:YES]; |
| 234 | } |
| 235 | |
| 236 | |
| 237 | - (NSSize)maximumFrameSize { |
| 238 | debug_view_xy max = view->total_size(); |
| 239 | return NSMakeSize(max.x * fontWidth, max.y * fontHeight); |
| 240 | } |
| 241 | |
| 242 | |
| 243 | - (NSFont *)font { |
| 244 | return [[font retain] autorelease]; |
| 245 | } |
| 246 | |
| 247 | |
| 248 | - (void)setFont:(NSFont *)f { |
| 249 | [font autorelease]; |
| 250 | font = [f retain]; |
| 251 | fontWidth = [font maximumAdvancement].width; |
| 252 | fontHeight = ceil([font ascender] - [font descender]); |
| 253 | fontAscent = [font ascender]; |
| 254 | [[self enclosingScrollView] setLineScroll:fontHeight]; |
| 255 | totalWidth = totalHeight = 0; |
| 256 | [self update]; |
| 257 | } |
| 258 | |
| 259 | |
| 260 | - (void)windowDidBecomeKey:(NSNotification *)notification { |
| 261 | NSWindow *win = [notification object]; |
| 262 | if ((win == [self window]) && ([win firstResponder] == self) && view->cursor_supported()) |
| 263 | [self setNeedsDisplay:YES]; |
| 264 | } |
| 265 | |
| 266 | |
| 267 | - (void)windowDidResignKey:(NSNotification *)notification { |
| 268 | NSWindow *win = [notification object]; |
| 269 | if ((win == [self window]) && ([win firstResponder] == self) && view->cursor_supported()) |
| 270 | [self setNeedsDisplay:YES]; |
| 271 | } |
| 272 | |
| 273 | |
| 274 | - (BOOL)acceptsFirstResponder { |
| 275 | return view->cursor_supported(); |
| 276 | } |
| 277 | |
| 278 | |
| 279 | - (BOOL)becomeFirstResponder { |
| 280 | if (view->cursor_supported()) { |
| 281 | debug_view_xy pos; |
| 282 | view->set_cursor_visible(true); |
| 283 | pos = view->cursor_position(); |
| 284 | [self scrollRectToVisible:NSMakeRect(pos.x * fontWidth, pos.y * fontHeight, fontWidth, fontHeight)]; // FIXME: metrics |
| 285 | [self setNeedsDisplay:YES]; |
| 286 | return [super becomeFirstResponder]; |
| 287 | } else { |
| 288 | return NO; |
| 289 | } |
| 290 | } |
| 291 | |
| 292 | |
| 293 | - (BOOL)resignFirstResponder { |
| 294 | if (view->cursor_supported()) |
| 295 | [self setNeedsDisplay:YES]; |
| 296 | return [super resignFirstResponder]; |
| 297 | } |
| 298 | |
| 299 | |
| 300 | - (void)viewDidMoveToSuperview { |
| 301 | [[self enclosingScrollView] setLineScroll:fontHeight]; |
| 302 | [super viewDidMoveToSuperview]; |
| 303 | } |
| 304 | |
| 305 | |
| 306 | - (void)viewDidMoveToWindow { |
| 307 | [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil]; |
| 308 | [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResignKeyNotification object:nil]; |
| 309 | if ([self window] != nil) { |
| 310 | [[NSNotificationCenter defaultCenter] addObserver:self |
| 311 | selector:@selector(windowDidBecomeKey:) |
| 312 | name:NSWindowDidBecomeKeyNotification |
| 313 | object:[self window]]; |
| 314 | [[NSNotificationCenter defaultCenter] addObserver:self |
| 315 | selector:@selector(windowDidResignKey:) |
| 316 | name:NSWindowDidResignKeyNotification |
| 317 | object:[self window]]; |
| 318 | [self recomputeVisible]; |
| 319 | } |
| 320 | } |
| 321 | |
| 322 | |
| 323 | - (BOOL)isFlipped { |
| 324 | return YES; |
| 325 | } |
| 326 | |
| 327 | |
| 328 | - (void)drawRect:(NSRect)dirtyRect { |
| 329 | debug_view_xy position, clip; |
| 330 | |
| 331 | // work out how much we need to draw |
| 332 | [self recomputeVisible]; |
| 333 | debug_view_xy const origin = view->visible_position(); |
| 334 | debug_view_xy const size = view->visible_size(); |
| 335 | [self convertBounds:dirtyRect toPosition:&position size:&clip]; |
| 336 | |
| 337 | // this gets the text for the whole visible area |
| 338 | debug_view_char const *data = view->viewdata(); |
| 339 | if (!data) |
| 340 | return; |
| 341 | |
| 342 | data += ((position.y - origin.y) * size.x); |
| 343 | for (UINT32 row = position.y; row < position.y + clip.y; row++, data += size.x) |
| 344 | { |
| 345 | if ((row < origin.y) || (row >= origin.y + size.y)) |
| 346 | continue; |
| 347 | |
| 348 | // render entire lines to get character alignment right |
| 349 | int attr = -1; |
| 350 | NSUInteger start = 0, length = 0; |
| 351 | for (UINT32 col = origin.x; col < origin.x + size.x; col++) |
| 352 | { |
| 353 | [[text mutableString] appendFormat:@"%c", data[col - origin.x].byte]; |
| 354 | if ((start < length) && (attr != data[col - origin.x].attrib)) |
| 355 | { |
| 356 | NSRange const run = NSMakeRange(start, length - start); |
| 357 | [text addAttribute:NSFontAttributeName |
| 358 | value:font |
| 359 | range:NSMakeRange(0, length)]; |
| 360 | [text addAttribute:NSForegroundColorAttributeName |
| 361 | value:[self foregroundForAttribute:attr] |
| 362 | range:run]; |
| 363 | NSRange const glyphs = [layoutManager glyphRangeForCharacterRange:run |
| 364 | actualCharacterRange:NULL]; |
| 365 | NSRect const box = [layoutManager boundingRectForGlyphRange:glyphs |
| 366 | inTextContainer:textContainer]; |
| 367 | [[self backgroundForAttribute:attr] set]; |
| 368 | [NSBezierPath fillRect:NSMakeRect(box.origin.x, |
| 369 | row * fontHeight, |
| 370 | box.size.width, |
| 371 | fontHeight)]; |
| 372 | start = length; |
| 373 | } |
| 374 | attr = data[col - origin.x].attrib; |
| 375 | length = [text length]; |
| 376 | } |
| 377 | if (start < length) |
| 378 | { |
| 379 | NSRange const run = NSMakeRange(start, length - start); |
| 380 | [text addAttribute:NSFontAttributeName |
| 381 | value:font |
| 382 | range:NSMakeRange(0, length)]; |
| 383 | [text addAttribute:NSForegroundColorAttributeName |
| 384 | value:[self foregroundForAttribute:attr] |
| 385 | range:run]; |
| 386 | NSRange const glyphs = [layoutManager glyphRangeForCharacterRange:run |
| 387 | actualCharacterRange:NULL]; |
| 388 | NSRect const box = [layoutManager boundingRectForGlyphRange:glyphs |
| 389 | inTextContainer:textContainer]; |
| 390 | [[self backgroundForAttribute:attr] set]; |
| 391 | [NSBezierPath fillRect:NSMakeRect(box.origin.x, |
| 392 | row * fontHeight, |
| 393 | box.size.width, |
| 394 | fontHeight)]; |
| 395 | } |
| 396 | [layoutManager drawGlyphsForGlyphRange:[layoutManager glyphRangeForTextContainer:textContainer] |
| 397 | atPoint:NSMakePoint(0, row * fontHeight)]; |
| 398 | [text deleteCharactersInRange:NSMakeRange(0, length)]; |
| 399 | } |
| 400 | } |
| 401 | |
| 402 | |
| 403 | - (void)mouseDown:(NSEvent *)event { |
| 404 | NSPoint const location = [self convertPoint:[event locationInWindow] fromView:nil]; |
| 405 | view->process_click(DCK_LEFT_CLICK, [self convertLocation:location]); |
| 406 | [self setNeedsDisplay:YES]; |
| 407 | } |
| 408 | |
| 409 | |
| 410 | - (void)rightMouseDown:(NSEvent *)event { |
| 411 | NSPoint const location = [self convertPoint:[event locationInWindow] fromView:nil]; |
| 412 | view->process_click(DCK_RIGHT_CLICK, [self convertLocation:location]); |
| 413 | [self setNeedsDisplay:YES]; |
| 414 | [super rightMouseDown:event]; |
| 415 | } |
| 416 | |
| 417 | |
| 418 | - (void)keyDown:(NSEvent *)event { |
| 419 | NSUInteger modifiers = [event modifierFlags]; |
| 420 | NSString *str = [event charactersIgnoringModifiers]; |
| 421 | |
| 422 | if ([str length] == 1) { |
| 423 | if (modifiers & NSNumericPadKeyMask) { |
| 424 | switch ([str characterAtIndex:0]) { |
| 425 | case NSUpArrowFunctionKey: |
| 426 | if (modifiers & NSCommandKeyMask) |
| 427 | view->process_char(DCH_CTRLHOME); |
| 428 | else |
| 429 | view->process_char(DCH_UP); |
| 430 | return; |
| 431 | case NSDownArrowFunctionKey: |
| 432 | if (modifiers & NSCommandKeyMask) |
| 433 | view->process_char(DCH_CTRLEND); |
| 434 | else |
| 435 | view->process_char(DCH_DOWN); |
| 436 | return; |
| 437 | case NSLeftArrowFunctionKey: |
| 438 | if (modifiers & NSCommandKeyMask) |
| 439 | [self typeCharacterAndScrollToCursor:DCH_HOME]; |
| 440 | else if (modifiers & NSAlternateKeyMask) |
| 441 | [self typeCharacterAndScrollToCursor:DCH_CTRLLEFT]; |
| 442 | else |
| 443 | [self typeCharacterAndScrollToCursor:DCH_LEFT]; |
| 444 | return; |
| 445 | case NSRightArrowFunctionKey: |
| 446 | if (modifiers & NSCommandKeyMask) |
| 447 | [self typeCharacterAndScrollToCursor:DCH_END]; |
| 448 | else if (modifiers & NSAlternateKeyMask) |
| 449 | [self typeCharacterAndScrollToCursor:DCH_CTRLRIGHT]; |
| 450 | else |
| 451 | [self typeCharacterAndScrollToCursor:DCH_RIGHT]; |
| 452 | return; |
| 453 | default: |
| 454 | [self interpretKeyEvents:[NSArray arrayWithObject:event]]; |
| 455 | return; |
| 456 | } |
| 457 | } else if (modifiers & NSFunctionKeyMask) { |
| 458 | switch ([str characterAtIndex:0]) { |
| 459 | case NSPageUpFunctionKey: |
| 460 | if (modifiers & NSAlternateKeyMask) { |
| 461 | view->process_char(DCH_PUP); |
| 462 | return; |
| 463 | } |
| 464 | case NSPageDownFunctionKey: |
| 465 | if (modifiers & NSAlternateKeyMask) { |
| 466 | view->process_char(DCH_PDOWN); |
| 467 | return; |
| 468 | } |
| 469 | default: |
| 470 | ; |
| 471 | } |
| 472 | [super keyDown:event]; |
| 473 | return; |
| 474 | } |
| 475 | } |
| 476 | [self interpretKeyEvents:[NSArray arrayWithObject:event]]; |
| 477 | } |
| 478 | |
| 479 | |
| 480 | - (void)insertTab:(id)sender { |
| 481 | if ([[self window] firstResponder] == self) |
| 482 | [[self window] selectNextKeyView:self]; |
| 483 | } |
| 484 | |
| 485 | |
| 486 | - (void)insertBacktab:(id)sender { |
| 487 | if ([[self window] firstResponder] == self) |
| 488 | [[self window] selectPreviousKeyView:self]; |
| 489 | } |
| 490 | |
| 491 | |
| 492 | - (void)insertNewline:(id)sender { |
| 493 | debug_cpu_get_visible_cpu(*machine)->debug()->single_step(); |
| 494 | } |
| 495 | |
| 496 | |
| 497 | - (void)insertText:(id)string { |
| 498 | NSUInteger len; |
| 499 | NSRange found; |
| 500 | if ([string isKindOfClass:[NSAttributedString class]]) |
| 501 | string = [string string]; |
| 502 | for (len = [string length], found = NSMakeRange(0, 0); |
| 503 | found.location < len; |
| 504 | found.location += found.length) { |
| 505 | found = [string rangeOfComposedCharacterSequenceAtIndex:found.location]; |
| 506 | if (found.length == 1) { |
| 507 | unichar ch = [string characterAtIndex:found.location]; |
| 508 | if ((ch >= 32) && (ch < 127)) |
| 509 | [self typeCharacterAndScrollToCursor:ch]; |
| 510 | } |
| 511 | } |
| 512 | } |
| 513 | |
| 514 | @end |
trunk/src/osd/modules/debugger/osx/debugwindowhandler.m
| r0 | r243596 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:Vas Crabb |
| 3 | //============================================================ |
| 4 | // |
| 5 | // debugosxdebugwindowhandler.m - MacOS X Cocoa debug window handling |
| 6 | // |
| 7 | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | // |
| 10 | //============================================================ |
| 11 | |
| 12 | #import "debugwindowhandler.h" |
| 13 | |
| 14 | #import "debugcommandhistory.h" |
| 15 | #import "debugview.h" |
| 16 | |
| 17 | #include "debug/debugcpu.h" |
| 18 | |
| 19 | |
| 20 | //============================================================ |
| 21 | // NOTIFICATIONS |
| 22 | //============================================================ |
| 23 | |
| 24 | NSString *const MAMEHideDebuggerNotification = @"MAMEHideDebuggerNotification"; |
| 25 | NSString *const MAMEShowDebuggerNotification = @"MAMEShowDebuggerNotification"; |
| 26 | NSString *const MAMEAuxiliaryDebugWindowWillCloseNotification = @"MAMEAuxiliaryDebugWindowWillCloseNotification"; |
| 27 | |
| 28 | |
| 29 | //============================================================ |
| 30 | // MAMEDebugWindowHandler class |
| 31 | //============================================================ |
| 32 | |
| 33 | @implementation MAMEDebugWindowHandler |
| 34 | |
| 35 | + (void)addCommonActionItems:(NSMenu *)menu { |
| 36 | { |
| 37 | NSMenuItem *runParentItem = [menu addItemWithTitle:@"Run" |
| 38 | action:@selector(debugRun:) |
| 39 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF5FunctionKey]]; |
| 40 | NSMenu *runMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Run"]; |
| 41 | [runParentItem setSubmenu:runMenu]; |
| 42 | [runMenu release]; |
| 43 | [runParentItem setKeyEquivalentModifierMask:0]; |
| 44 | [[runMenu addItemWithTitle:@"and Hide Debugger" |
| 45 | action:@selector(debugRunAndHide:) |
| 46 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF12FunctionKey]] |
| 47 | setKeyEquivalentModifierMask:0]; |
| 48 | [[runMenu addItemWithTitle:@"to Next CPU" |
| 49 | action:@selector(debugRunToNextCPU:) |
| 50 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF6FunctionKey]] |
| 51 | setKeyEquivalentModifierMask:0]; |
| 52 | [[runMenu addItemWithTitle:@"until Next Interrupt on Current CPU" |
| 53 | action:@selector(debugRunToNextInterrupt:) |
| 54 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF7FunctionKey]] |
| 55 | setKeyEquivalentModifierMask:0]; |
| 56 | [[runMenu addItemWithTitle:@"until Next VBLANK" |
| 57 | action:@selector(debugRunToNextVBLANK:) |
| 58 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF8FunctionKey]] |
| 59 | setKeyEquivalentModifierMask:0]; |
| 60 | } |
| 61 | { |
| 62 | NSMenuItem *stepParentItem = [menu addItemWithTitle:@"Step" action:NULL keyEquivalent:@""]; |
| 63 | NSMenu *stepMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Step"]; |
| 64 | [stepParentItem setSubmenu:stepMenu]; |
| 65 | [stepMenu release]; |
| 66 | [[stepMenu addItemWithTitle:@"Into" |
| 67 | action:@selector(debugStepInto:) |
| 68 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF11FunctionKey]] |
| 69 | setKeyEquivalentModifierMask:0]; |
| 70 | [[stepMenu addItemWithTitle:@"Over" |
| 71 | action:@selector(debugStepOver:) |
| 72 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF10FunctionKey]] |
| 73 | setKeyEquivalentModifierMask:0]; |
| 74 | [[stepMenu addItemWithTitle:@"Out" |
| 75 | action:@selector(debugStepOut:) |
| 76 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF10FunctionKey]] |
| 77 | setKeyEquivalentModifierMask:NSShiftKeyMask]; |
| 78 | } |
| 79 | { |
| 80 | NSMenuItem *resetParentItem = [menu addItemWithTitle:@"Reset" action:NULL keyEquivalent:@""]; |
| 81 | NSMenu *resetMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Reset"]; |
| 82 | [resetParentItem setSubmenu:resetMenu]; |
| 83 | [resetMenu release]; |
| 84 | [[resetMenu addItemWithTitle:@"Soft" |
| 85 | action:@selector(debugSoftReset:) |
| 86 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF3FunctionKey]] |
| 87 | setKeyEquivalentModifierMask:0]; |
| 88 | [[resetMenu addItemWithTitle:@"Hard" |
| 89 | action:@selector(debugHardReset:) |
| 90 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF3FunctionKey]] |
| 91 | setKeyEquivalentModifierMask:NSShiftKeyMask]; |
| 92 | } |
| 93 | [menu addItem:[NSMenuItem separatorItem]]; |
| 94 | { |
| 95 | NSMenuItem *newParentItem = [menu addItemWithTitle:@"New" action:NULL keyEquivalent:@""]; |
| 96 | NSMenu *newMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"New"]; |
| 97 | [newParentItem setSubmenu:newMenu]; |
| 98 | [newMenu release]; |
| 99 | [newMenu addItemWithTitle:@"Memory Window" |
| 100 | action:@selector(debugNewMemoryWindow:) |
| 101 | keyEquivalent:@"d"]; |
| 102 | [newMenu addItemWithTitle:@"Disassembly Window" |
| 103 | action:@selector(debugNewDisassemblyWindow:) |
| 104 | keyEquivalent:@"a"]; |
| 105 | [newMenu addItemWithTitle:@"Error Log Window" |
| 106 | action:@selector(debugNewErrorLogWindow:) |
| 107 | keyEquivalent:@"l"]; |
| 108 | [newMenu addItemWithTitle:@"(Break|Watch)points Window" |
| 109 | action:@selector(debugNewPointsWindow:) |
| 110 | keyEquivalent:@"b"]; |
| 111 | } |
| 112 | [menu addItem:[NSMenuItem separatorItem]]; |
| 113 | [menu addItemWithTitle:@"Close Window" action:@selector(performClose:) keyEquivalent:@"w"]; |
| 114 | [menu addItemWithTitle:@"Exit" action:@selector(debugExit:) keyEquivalent:@""]; |
| 115 | } |
| 116 | |
| 117 | |
| 118 | + (NSPopUpButton *)newActionButtonWithFrame:(NSRect)frame { |
| 119 | NSPopUpButton *actionButton = [[NSPopUpButton alloc] initWithFrame:frame pullsDown:YES]; |
| 120 | [actionButton setTitle:@""]; |
| 121 | [actionButton addItemWithTitle:@""]; |
| 122 | [actionButton setBezelStyle:NSShadowlessSquareBezelStyle]; |
| 123 | [actionButton setFocusRingType:NSFocusRingTypeNone]; |
| 124 | [[actionButton cell] setArrowPosition:NSPopUpArrowAtCenter]; |
| 125 | [[self class] addCommonActionItems:[actionButton menu]]; |
| 126 | return actionButton; |
| 127 | } |
| 128 | |
| 129 | |
| 130 | - (id)initWithMachine:(running_machine &)m title:(NSString *)t { |
| 131 | if (!(self = [super init])) |
| 132 | return nil; |
| 133 | |
| 134 | window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 320, 240) |
| 135 | styleMask:(NSTitledWindowMask | |
| 136 | NSClosableWindowMask | |
| 137 | NSMiniaturizableWindowMask | |
| 138 | NSResizableWindowMask) |
| 139 | backing:NSBackingStoreBuffered |
| 140 | defer:YES]; |
| 141 | [window setReleasedWhenClosed:NO]; |
| 142 | [window setDelegate:self]; |
| 143 | [window setTitle:t]; |
| 144 | [window setContentMinSize:NSMakeSize(320, 240)]; |
| 145 | |
| 146 | [[NSNotificationCenter defaultCenter] addObserver:self |
| 147 | selector:@selector(showDebugger:) |
| 148 | name:MAMEShowDebuggerNotification |
| 149 | object:nil]; |
| 150 | [[NSNotificationCenter defaultCenter] addObserver:self |
| 151 | selector:@selector(hideDebugger:) |
| 152 | name:MAMEHideDebuggerNotification |
| 153 | object:nil]; |
| 154 | |
| 155 | machine = &m; |
| 156 | |
| 157 | return self; |
| 158 | } |
| 159 | |
| 160 | |
| 161 | - (void)dealloc { |
| 162 | [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 163 | |
| 164 | if (window != nil) |
| 165 | [window release]; |
| 166 | |
| 167 | [super dealloc]; |
| 168 | } |
| 169 | |
| 170 | |
| 171 | - (void)activate { |
| 172 | [window makeKeyAndOrderFront:self]; |
| 173 | } |
| 174 | |
| 175 | |
| 176 | - (IBAction)debugRun:(id)sender { |
| 177 | debug_cpu_get_visible_cpu(*machine)->debug()->go(); |
| 178 | } |
| 179 | |
| 180 | |
| 181 | - (IBAction)debugRunAndHide:(id)sender { |
| 182 | [[NSNotificationCenter defaultCenter] postNotificationName:MAMEHideDebuggerNotification object:self]; |
| 183 | debug_cpu_get_visible_cpu(*machine)->debug()->go(); |
| 184 | } |
| 185 | |
| 186 | |
| 187 | - (IBAction)debugRunToNextCPU:(id)sender { |
| 188 | debug_cpu_get_visible_cpu(*machine)->debug()->go_next_device(); |
| 189 | } |
| 190 | |
| 191 | |
| 192 | - (IBAction)debugRunToNextInterrupt:(id)sender { |
| 193 | debug_cpu_get_visible_cpu(*machine)->debug()->go_interrupt(); |
| 194 | } |
| 195 | |
| 196 | |
| 197 | - (IBAction)debugRunToNextVBLANK:(id)sender { |
| 198 | debug_cpu_get_visible_cpu(*machine)->debug()->go_vblank(); |
| 199 | } |
| 200 | |
| 201 | |
| 202 | - (IBAction)debugStepInto:(id)sender { |
| 203 | debug_cpu_get_visible_cpu(*machine)->debug()->single_step(); |
| 204 | } |
| 205 | |
| 206 | |
| 207 | - (IBAction)debugStepOver:(id)sender { |
| 208 | debug_cpu_get_visible_cpu(*machine)->debug()->single_step_over(); |
| 209 | } |
| 210 | |
| 211 | |
| 212 | - (IBAction)debugStepOut:(id)sender { |
| 213 | debug_cpu_get_visible_cpu(*machine)->debug()->single_step_out(); |
| 214 | } |
| 215 | |
| 216 | |
| 217 | - (IBAction)debugSoftReset:(id)sender { |
| 218 | machine->schedule_soft_reset(); |
| 219 | debug_cpu_get_visible_cpu(*machine)->debug()->go(); |
| 220 | } |
| 221 | |
| 222 | |
| 223 | - (IBAction)debugHardReset:(id)sender { |
| 224 | machine->schedule_hard_reset(); |
| 225 | } |
| 226 | |
| 227 | |
| 228 | - (IBAction)debugExit:(id)sender { |
| 229 | machine->schedule_exit(); |
| 230 | } |
| 231 | |
| 232 | |
| 233 | - (void)showDebugger:(NSNotification *)notification { |
| 234 | device_t *device = (device_t *) [[[notification userInfo] objectForKey:@"MAMEDebugDevice"] pointerValue]; |
| 235 | if (&device->machine() == machine) { |
| 236 | if (![window isVisible] && ![window isMiniaturized]) |
| 237 | [window orderFront:self]; |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | |
| 242 | - (void)hideDebugger:(NSNotification *)notification { |
| 243 | [window orderOut:self]; |
| 244 | } |
| 245 | |
| 246 | @end |
| 247 | |
| 248 | |
| 249 | //============================================================ |
| 250 | // MAMEAuxiliaryDebugWindowHandler class |
| 251 | //============================================================ |
| 252 | |
| 253 | @implementation MAMEAuxiliaryDebugWindowHandler |
| 254 | |
| 255 | + (void)cascadeWindow:(NSWindow *)window { |
| 256 | static NSPoint lastPosition = { 0, 0 }; |
| 257 | if (NSEqualPoints(lastPosition, NSZeroPoint)) { |
| 258 | NSRect available = [[NSScreen mainScreen] visibleFrame]; |
| 259 | lastPosition = NSMakePoint(available.origin.x + 12, available.origin.y + available.size.height - 8); |
| 260 | } |
| 261 | lastPosition = [window cascadeTopLeftFromPoint:lastPosition]; |
| 262 | } |
| 263 | |
| 264 | |
| 265 | - (id)initWithMachine:(running_machine &)m title:(NSString *)t console:(MAMEDebugConsole *)c { |
| 266 | if (!(self = [super initWithMachine:m title:t])) |
| 267 | return nil; |
| 268 | console = c; |
| 269 | return self; |
| 270 | } |
| 271 | |
| 272 | |
| 273 | - (void)dealloc { |
| 274 | [super dealloc]; |
| 275 | } |
| 276 | |
| 277 | |
| 278 | - (IBAction)debugNewMemoryWindow:(id)sender { |
| 279 | [console debugNewMemoryWindow:sender]; |
| 280 | } |
| 281 | |
| 282 | |
| 283 | - (IBAction)debugNewDisassemblyWindow:(id)sender { |
| 284 | [console debugNewDisassemblyWindow:sender]; |
| 285 | } |
| 286 | |
| 287 | |
| 288 | - (IBAction)debugNewErrorLogWindow:(id)sender { |
| 289 | [console debugNewErrorLogWindow:sender]; |
| 290 | } |
| 291 | |
| 292 | |
| 293 | - (IBAction)debugNewPointsWindow:(id)sender { |
| 294 | [console debugNewPointsWindow:sender]; |
| 295 | } |
| 296 | |
| 297 | |
| 298 | - (void)windowWillClose:(NSNotification *)notification { |
| 299 | [[NSNotificationCenter defaultCenter] postNotificationName:MAMEAuxiliaryDebugWindowWillCloseNotification |
| 300 | object:self]; |
| 301 | } |
| 302 | |
| 303 | - (void)cascadeWindowWithDesiredSize:(NSSize)desired forView:(NSView *)view { |
| 304 | NSRect available = [[NSScreen mainScreen] visibleFrame]; |
| 305 | NSRect windowFrame = [window frame]; |
| 306 | NSSize current = [view frame].size; |
| 307 | |
| 308 | desired.width -= current.width; |
| 309 | desired.height -= current.height; |
| 310 | |
| 311 | windowFrame.size.width += desired.width; |
| 312 | windowFrame.size.height += desired.height; |
| 313 | windowFrame.size.height = MIN(MIN(windowFrame.size.height, 240), available.size.height); |
| 314 | windowFrame.size.width = MIN(windowFrame.size.width, available.size.width); |
| 315 | windowFrame.origin.x = available.origin.x + available.size.width - windowFrame.size.width; |
| 316 | windowFrame.origin.y = available.origin.y; |
| 317 | [window setFrame:windowFrame display:YES]; |
| 318 | [[self class] cascadeWindow:window]; |
| 319 | |
| 320 | windowFrame = [[window contentView] frame]; |
| 321 | desired = [window contentMinSize]; |
| 322 | [window setContentMinSize:NSMakeSize(MIN(windowFrame.size.width, desired.width), |
| 323 | MIN(windowFrame.size.height, desired.height))]; |
| 324 | } |
| 325 | |
| 326 | @end |
| 327 | |
| 328 | |
| 329 | //============================================================ |
| 330 | // MAMEExpreesionAuxiliaryDebugWindowHandler class |
| 331 | //============================================================ |
| 332 | |
| 333 | @implementation MAMEExpressionAuxiliaryDebugWindowHandler |
| 334 | |
| 335 | - (id)initWithMachine:(running_machine &)m title:(NSString *)t console:(MAMEDebugConsole *)c { |
| 336 | if (!(self = [super initWithMachine:m title:t console:c])) |
| 337 | return nil; |
| 338 | history = [[MAMEDebugCommandHistory alloc] init]; |
| 339 | return self; |
| 340 | } |
| 341 | |
| 342 | |
| 343 | - (void)dealloc { |
| 344 | if (history != nil) |
| 345 | [history release]; |
| 346 | [super dealloc]; |
| 347 | } |
| 348 | |
| 349 | |
| 350 | - (id <MAMEDebugViewExpressionSupport>)documentView { |
| 351 | return nil; |
| 352 | } |
| 353 | |
| 354 | |
| 355 | - (IBAction)doExpression:(id)sender { |
| 356 | NSString *expr = [sender stringValue]; |
| 357 | if ([expr length] > 0) { |
| 358 | [history add:expr]; |
| 359 | [[self documentView] setExpression:expr]; |
| 360 | } else { |
| 361 | [sender setStringValue:[[self documentView] expression]]; |
| 362 | [history reset]; |
| 363 | } |
| 364 | [sender selectText:self]; |
| 365 | } |
| 366 | |
| 367 | |
| 368 | - (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor |
| 369 | { |
| 370 | if (control == expressionField) |
| 371 | [history edit]; |
| 372 | |
| 373 | return YES; |
| 374 | } |
| 375 | |
| 376 | |
| 377 | - (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command { |
| 378 | if (control == expressionField) { |
| 379 | if (command == @selector(cancelOperation:)) { |
| 380 | [history reset]; |
| 381 | [expressionField setStringValue:[[self documentView] expression]]; |
| 382 | [expressionField selectText:self]; |
| 383 | return YES; |
| 384 | } else if (command == @selector(moveUp:)) { |
| 385 | NSString *hist = [history previous:[expressionField stringValue]]; |
| 386 | if (hist != nil) { |
| 387 | [expressionField setStringValue:hist]; |
| 388 | [expressionField selectText:self]; |
| 389 | } |
| 390 | return YES; |
| 391 | } else if (command == @selector(moveDown:)) { |
| 392 | NSString *hist = [history next:[expressionField stringValue]]; |
| 393 | if (hist != nil) { |
| 394 | [expressionField setStringValue:hist]; |
| 395 | [expressionField selectText:self]; |
| 396 | } |
| 397 | return YES; |
| 398 | } |
| 399 | } |
| 400 | return NO; |
| 401 | } |
| 402 | |
| 403 | @end |
| | No newline at end of file |
trunk/src/osd/modules/debugger/osx/disassemblyview.m
| r0 | r243596 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:Vas Crabb |
| 3 | //============================================================ |
| 4 | // |
| 5 | // debugosxdisassemblyview.m - MacOS X Cocoa debug window handling |
| 6 | // |
| 7 | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | // |
| 10 | //============================================================ |
| 11 | |
| 12 | #import "disassemblyview.h" |
| 13 | |
| 14 | #include "debug/debugcon.h" |
| 15 | #include "debug/debugcpu.h" |
| 16 | #include "debug/debugvw.h" |
| 17 | #include "debug/dvdisasm.h" |
| 18 | |
| 19 | |
| 20 | @implementation MAMEDisassemblyView |
| 21 | |
| 22 | - (device_debug::breakpoint *)findBreakpointAtAddress:(offs_t)address inAddressSpace:(address_space &)space { |
| 23 | device_debug *cpuinfo = space.device().debug(); |
| 24 | device_debug::breakpoint *bp; |
| 25 | for (bp = cpuinfo->breakpoint_first(); (bp != NULL) && (address != bp->address()); bp = bp->next()) {} |
| 26 | return bp; |
| 27 | } |
| 28 | |
| 29 | - (void)createContextMenu { |
| 30 | NSMenu *contextMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Disassembly"]; |
| 31 | NSMenuItem *item; |
| 32 | |
| 33 | item = [contextMenu addItemWithTitle:@"Toggle Breakpoint" |
| 34 | action:@selector(debugToggleBreakpoint:) |
| 35 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey]]; |
| 36 | [item setKeyEquivalentModifierMask:0]; |
| 37 | [item setTarget:self]; |
| 38 | |
| 39 | item = [contextMenu addItemWithTitle:@"Disable Breakpoint" |
| 40 | action:@selector(debugToggleBreakpointEnable:) |
| 41 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey]]; |
| 42 | [item setKeyEquivalentModifierMask:NSShiftKeyMask]; |
| 43 | [item setTarget:self]; |
| 44 | |
| 45 | [contextMenu addItem:[NSMenuItem separatorItem]]; |
| 46 | |
| 47 | item = [contextMenu addItemWithTitle:@"Run to Cursor" |
| 48 | action:@selector(debugRunToCursor:) |
| 49 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF4FunctionKey]]; |
| 50 | [item setKeyEquivalentModifierMask:0]; |
| 51 | [item setTarget:self]; |
| 52 | |
| 53 | [contextMenu addItem:[NSMenuItem separatorItem]]; |
| 54 | |
| 55 | item = [contextMenu addItemWithTitle:@"Raw Opcodes" |
| 56 | action:@selector(showRightColumn:) |
| 57 | keyEquivalent:@"r"]; |
| 58 | [item setTarget:self]; |
| 59 | [item setTag:DASM_RIGHTCOL_RAW]; |
| 60 | |
| 61 | item = [contextMenu addItemWithTitle:@"Encrypted Opcodes" |
| 62 | action:@selector(showRightColumn:) |
| 63 | keyEquivalent:@"e"]; |
| 64 | [item setTarget:self]; |
| 65 | [item setTag:DASM_RIGHTCOL_ENCRYPTED]; |
| 66 | |
| 67 | item = [contextMenu addItemWithTitle:@"Comments" |
| 68 | action:@selector(showRightColumn:) |
| 69 | keyEquivalent:@"n"]; |
| 70 | [item setTarget:self]; |
| 71 | [item setTag:DASM_RIGHTCOL_COMMENTS]; |
| 72 | |
| 73 | [self setMenu:contextMenu]; |
| 74 | [contextMenu release]; |
| 75 | } |
| 76 | |
| 77 | |
| 78 | - (id)initWithFrame:(NSRect)f machine:(running_machine &)m useConsole:(BOOL)uc { |
| 79 | if (!(self = [super initWithFrame:f type:DVT_DISASSEMBLY machine:m])) |
| 80 | return nil; |
| 81 | useConsole = uc; |
| 82 | [self createContextMenu]; |
| 83 | return self; |
| 84 | } |
| 85 | |
| 86 | |
| 87 | - (void)dealloc { |
| 88 | [super dealloc]; |
| 89 | } |
| 90 | |
| 91 | |
| 92 | - (BOOL)validateMenuItem:(NSMenuItem *)item { |
| 93 | SEL action = [item action]; |
| 94 | BOOL inContextMenu = ([item menu] == [self menu]); |
| 95 | BOOL haveCursor = NO, isCurrent = NO; |
| 96 | device_debug::breakpoint *breakpoint = NULL; |
| 97 | |
| 98 | if (view->cursor_visible()) { |
| 99 | if (debug_cpu_get_visible_cpu(*machine) == view->source()->device()) { |
| 100 | isCurrent = YES; |
| 101 | if (!useConsole || isCurrent) { |
| 102 | offs_t address = downcast<debug_view_disasm *>(view)->selected_address(); |
| 103 | haveCursor = YES; |
| 104 | breakpoint = [self findBreakpointAtAddress:address inAddressSpace:downcast<const debug_view_disasm_source *>(view->source())->space()]; |
| 105 | } |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | if (action == @selector(debugToggleBreakpoint:)) { |
| 110 | if (haveCursor) { |
| 111 | if (breakpoint != NULL) { |
| 112 | if (inContextMenu) |
| 113 | [item setTitle:@"Clear Breakpoint"]; |
| 114 | else |
| 115 | [item setTitle:@"Clear Breakpoint at Cursor"]; |
| 116 | } else { |
| 117 | if (inContextMenu) |
| 118 | [item setTitle:@"Set Breakpoint"]; |
| 119 | else |
| 120 | [item setTitle:@"Set Breakpoint at Cursor"]; |
| 121 | } |
| 122 | } else { |
| 123 | if (inContextMenu) |
| 124 | [item setTitle:@"Toggle Breakpoint"]; |
| 125 | else |
| 126 | [item setTitle:@"Toggle Breakpoint at Cursor"]; |
| 127 | } |
| 128 | return haveCursor; |
| 129 | } else if (action == @selector(debugToggleBreakpointEnable:)) { |
| 130 | if ((breakpoint != NULL) && !breakpoint->enabled()) { |
| 131 | if (inContextMenu) |
| 132 | [item setTitle:@"Enable Breakpoint"]; |
| 133 | else |
| 134 | [item setTitle:@"Enable Breakpoint at Cursor"]; |
| 135 | } else { |
| 136 | if (inContextMenu) |
| 137 | [item setTitle:@"Disable Breakpoint"]; |
| 138 | else |
| 139 | [item setTitle:@"Disable Breakpoint at Cursor"]; |
| 140 | } |
| 141 | return (breakpoint != NULL); |
| 142 | } else if (action == @selector(debugRunToCursor:)) { |
| 143 | return isCurrent; |
| 144 | } else if (action == @selector(showRightColumn:)) { |
| 145 | [item setState:((downcast<debug_view_disasm *>(view)->right_column() == [item tag]) ? NSOnState : NSOffState)]; |
| 146 | return YES; |
| 147 | } else { |
| 148 | return YES; |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | |
| 153 | - (NSSize)maximumFrameSize { |
| 154 | debug_view_xy max; |
| 155 | device_t *curcpu = debug_cpu_get_visible_cpu(*machine); |
| 156 | const debug_view_source *source = view->source_for_device(curcpu); |
| 157 | |
| 158 | max.x = max.y = 0; |
| 159 | for (const debug_view_source *source = view->source_list().first(); source != NULL; source = source->next()) |
| 160 | { |
| 161 | debug_view_xy current; |
| 162 | view->set_source(*source); |
| 163 | current = view->total_size(); |
| 164 | if (current.x > max.x) |
| 165 | max.x = current.x; |
| 166 | if (current.y > max.y) |
| 167 | max.y = current.y; |
| 168 | } |
| 169 | view->set_source(*source); |
| 170 | return NSMakeSize(max.x * fontWidth, max.y * fontHeight); |
| 171 | } |
| 172 | |
| 173 | |
| 174 | - (NSString *)selectedSubviewName { |
| 175 | const debug_view_source *source = view->source(); |
| 176 | if (source != NULL) |
| 177 | return [NSString stringWithUTF8String:source->name()]; |
| 178 | else |
| 179 | return @""; |
| 180 | } |
| 181 | |
| 182 | |
| 183 | - (int)selectedSubviewIndex { |
| 184 | const debug_view_source *source = view->source(); |
| 185 | if (source != NULL) |
| 186 | return view->source_list().indexof(*source); |
| 187 | else |
| 188 | return -1; |
| 189 | } |
| 190 | |
| 191 | |
| 192 | - (void)selectSubviewAtIndex:(int)index { |
| 193 | const int selected = view->source_list().indexof(*view->source()); |
| 194 | if (selected != index) { |
| 195 | view->set_source(*view->source_list().find(index)); |
| 196 | if ([[self window] firstResponder] != self) |
| 197 | view->set_cursor_visible(false); |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | |
| 202 | - (void)selectSubviewForCPU:(device_t *)device { |
| 203 | const debug_view_source *selected = view->source(); |
| 204 | const debug_view_source *source = view->source_for_device(device); |
| 205 | if ( selected != source ) { |
| 206 | view->set_source(*source); |
| 207 | if ([[self window] firstResponder] != self) |
| 208 | view->set_cursor_visible(false); |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | |
| 213 | - (NSString *)expression { |
| 214 | return [NSString stringWithUTF8String:downcast<debug_view_disasm *>(view)->expression()]; |
| 215 | } |
| 216 | |
| 217 | |
| 218 | - (void)setExpression:(NSString *)exp { |
| 219 | downcast<debug_view_disasm *>(view)->set_expression([exp UTF8String]); |
| 220 | } |
| 221 | |
| 222 | |
| 223 | - (IBAction)debugToggleBreakpoint:(id)sender { |
| 224 | if (view->cursor_visible()) { |
| 225 | address_space &space = downcast<const debug_view_disasm_source *>(view->source())->space(); |
| 226 | if (!useConsole || (debug_cpu_get_visible_cpu(*machine) == &space.device())) { |
| 227 | offs_t address = downcast<debug_view_disasm *>(view)->selected_address(); |
| 228 | device_debug::breakpoint *bp = [self findBreakpointAtAddress:address inAddressSpace:space]; |
| 229 | |
| 230 | // if it doesn't exist, add a new one |
| 231 | if (useConsole) { |
| 232 | NSString *command; |
| 233 | if (bp == NULL) |
| 234 | command = [NSString stringWithFormat:@"bpset %lX", (unsigned long)address]; |
| 235 | else |
| 236 | command = [NSString stringWithFormat:@"bpclear %X", (unsigned)bp->index()]; |
| 237 | debug_console_execute_command(*machine, [command UTF8String], 1); |
| 238 | } else { |
| 239 | if (bp == NULL) |
| 240 | space.device().debug()->breakpoint_set(address, NULL, NULL); |
| 241 | else |
| 242 | space.device().debug()->breakpoint_clear(bp->index()); |
| 243 | } |
| 244 | } |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | |
| 249 | - (IBAction)debugToggleBreakpointEnable:(id)sender { |
| 250 | if (view->cursor_visible()) { |
| 251 | address_space &space = downcast<const debug_view_disasm_source *>(view->source())->space(); |
| 252 | if (!useConsole || (debug_cpu_get_visible_cpu(*machine) == &space.device())) { |
| 253 | offs_t address = downcast<debug_view_disasm *>(view)->selected_address(); |
| 254 | device_debug::breakpoint *bp = [self findBreakpointAtAddress:address inAddressSpace:space]; |
| 255 | |
| 256 | if (bp != NULL) { |
| 257 | NSString *command; |
| 258 | if (useConsole) { |
| 259 | if (bp->enabled()) |
| 260 | command = [NSString stringWithFormat:@"bpdisable %X", (unsigned)bp->index()]; |
| 261 | else |
| 262 | command = [NSString stringWithFormat:@"bpenable %X", (unsigned)bp->index()]; |
| 263 | debug_console_execute_command(*machine, [command UTF8String], 1); |
| 264 | } else { |
| 265 | space.device().debug()->breakpoint_enable(bp->index(), !bp->enabled()); |
| 266 | } |
| 267 | } |
| 268 | } |
| 269 | } |
| 270 | } |
| 271 | |
| 272 | |
| 273 | - (IBAction)debugRunToCursor:(id)sender { |
| 274 | if (view->cursor_visible()) { |
| 275 | address_space &space = downcast<const debug_view_disasm_source *>(view->source())->space(); |
| 276 | if (debug_cpu_get_visible_cpu(*machine) == &space.device()) { |
| 277 | offs_t address = downcast<debug_view_disasm *>(view)->selected_address(); |
| 278 | if (useConsole) { |
| 279 | NSString *command = [NSString stringWithFormat:@"go 0x%lX", (unsigned long)address]; |
| 280 | debug_console_execute_command(*machine, [command UTF8String], 1); |
| 281 | } else { |
| 282 | debug_cpu_get_visible_cpu(*machine)->debug()->go(address); |
| 283 | } |
| 284 | } |
| 285 | } |
| 286 | } |
| 287 | |
| 288 | |
| 289 | - (IBAction)showRightColumn:(id)sender { |
| 290 | downcast<debug_view_disasm *>(view)->set_right_column((disasm_right_column) [sender tag]); |
| 291 | } |
| 292 | |
| 293 | |
| 294 | - (void)insertActionItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index { |
| 295 | { |
| 296 | NSMenuItem *breakItem = [menu insertItemWithTitle:@"Toggle Breakpoint at Cursor" |
| 297 | action:@selector(debugToggleBreakpoint:) |
| 298 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey] |
| 299 | atIndex:index++]; |
| 300 | [breakItem setKeyEquivalentModifierMask:0]; |
| 301 | [breakItem setTarget:self]; |
| 302 | } |
| 303 | { |
| 304 | NSMenuItem *disableItem = [menu insertItemWithTitle:@"Disable Breakpoint at Cursor" |
| 305 | action:@selector(debugToggleBreakpointEnable:) |
| 306 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey] |
| 307 | atIndex:index++]; |
| 308 | [disableItem setKeyEquivalentModifierMask:NSShiftKeyMask]; |
| 309 | [disableItem setAlternate:YES]; |
| 310 | [disableItem setTarget:self]; |
| 311 | } |
| 312 | { |
| 313 | NSMenu *runMenu = [[menu itemWithTitle:@"Run"] submenu]; |
| 314 | NSMenuItem *runItem; |
| 315 | if (runMenu != nil) { |
| 316 | runItem = [runMenu addItemWithTitle:@"to Cursor" |
| 317 | action:@selector(debugRunToCursor:) |
| 318 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF4FunctionKey]]; |
| 319 | } else { |
| 320 | runItem = [menu insertItemWithTitle:@"Run to Cursor" |
| 321 | action:@selector(debugRunToCursor:) |
| 322 | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF4FunctionKey] |
| 323 | atIndex:index++]; |
| 324 | } |
| 325 | [runItem setKeyEquivalentModifierMask:0]; |
| 326 | [runItem setTarget:self]; |
| 327 | } |
| 328 | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 329 | { |
| 330 | NSMenuItem *rawItem = [menu insertItemWithTitle:@"Show Raw Opcodes" |
| 331 | action:@selector(showRightColumn:) |
| 332 | keyEquivalent:@"r" |
| 333 | atIndex:index++]; |
| 334 | [rawItem setTarget:self]; |
| 335 | [rawItem setTag:DASM_RIGHTCOL_RAW]; |
| 336 | } |
| 337 | { |
| 338 | NSMenuItem *encItem = [menu insertItemWithTitle:@"Show Encrypted Opcodes" |
| 339 | action:@selector(showRightColumn:) |
| 340 | keyEquivalent:@"e" |
| 341 | atIndex:index++]; |
| 342 | [encItem setTarget:self]; |
| 343 | [encItem setTag:DASM_RIGHTCOL_ENCRYPTED]; |
| 344 | } |
| 345 | { |
| 346 | NSMenuItem *commentsItem = [menu insertItemWithTitle:@"Show Comments" |
| 347 | action:@selector(showRightColumn:) |
| 348 | keyEquivalent:@"n" |
| 349 | atIndex:index++]; |
| 350 | [commentsItem setTarget:self]; |
| 351 | [commentsItem setTag:DASM_RIGHTCOL_COMMENTS]; |
| 352 | } |
| 353 | if (index < [menu numberOfItems]) |
| 354 | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 355 | } |
| 356 | |
| 357 | |
| 358 | - (void)insertSubviewItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index { |
| 359 | for (const debug_view_source *source = view->source_list().first(); source != NULL; source = source->next()) |
| 360 | { |
| 361 | [[menu insertItemWithTitle:[NSString stringWithUTF8String:source->name()] |
| 362 | action:NULL |
| 363 | keyEquivalent:@"" |
| 364 | atIndex:index++] setTag:view->source_list().indexof(*source)]; |
| 365 | } |
| 366 | if (index < [menu numberOfItems]) |
| 367 | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 368 | } |
| 369 | |
| 370 | @end |
trunk/src/osd/modules/debugger/osx/disassemblyviewer.m
| r0 | r243596 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:Vas Crabb |
| 3 | //============================================================ |
| 4 | // |
| 5 | // debugosxdisassemblyviewer.m - MacOS X Cocoa debug window handling |
| 6 | // |
| 7 | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | // |
| 10 | //============================================================ |
| 11 | |
| 12 | #import "disassemblyviewer.h" |
| 13 | |
| 14 | #import "debugview.h" |
| 15 | #import "disassemblyview.h" |
| 16 | |
| 17 | #include "debug/debugcpu.h" |
| 18 | |
| 19 | |
| 20 | @implementation MAMEDisassemblyViewer |
| 21 | |
| 22 | - (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c { |
| 23 | NSScrollView *dasmScroll; |
| 24 | NSView *expressionContainer; |
| 25 | NSPopUpButton *actionButton, *subviewButton; |
| 26 | NSRect contentBounds, expressionFrame; |
| 27 | |
| 28 | if (!(self = [super initWithMachine:m title:@"Disassembly" console:c])) |
| 29 | return nil; |
| 30 | contentBounds = [[window contentView] bounds]; |
| 31 | |
| 32 | // create the expression field |
| 33 | expressionField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)]; |
| 34 | [expressionField setAutoresizingMask:(NSViewWidthSizable | NSViewMaxXMargin | NSViewMinYMargin)]; |
| 35 | [expressionField setFont:[[MAMEDebugView class] defaultFont]]; |
| 36 | [expressionField setFocusRingType:NSFocusRingTypeNone]; |
| 37 | [expressionField setTarget:self]; |
| 38 | [expressionField setAction:@selector(doExpression:)]; |
| 39 | [expressionField setDelegate:self]; |
| 40 | expressionFrame = [expressionField frame]; |
| 41 | expressionFrame.size.width = (contentBounds.size.width - expressionFrame.size.height) / 2; |
| 42 | [expressionField setFrameSize:expressionFrame.size]; |
| 43 | |
| 44 | // create the subview popup |
| 45 | subviewButton = [[NSPopUpButton alloc] initWithFrame:NSOffsetRect(expressionFrame, |
| 46 | expressionFrame.size.width, |
| 47 | 0)]; |
| 48 | [subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinXMargin | NSViewMinYMargin)]; |
| 49 | [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle]; |
| 50 | [subviewButton setFocusRingType:NSFocusRingTypeNone]; |
| 51 | [subviewButton setFont:[[MAMEDebugView class] defaultFont]]; |
| 52 | [subviewButton setTarget:self]; |
| 53 | [subviewButton setAction:@selector(changeSubview:)]; |
| 54 | [[subviewButton cell] setArrowPosition:NSPopUpArrowAtBottom]; |
| 55 | |
| 56 | // create a container for the expression field and subview popup |
| 57 | expressionFrame = NSMakeRect(expressionFrame.size.height, |
| 58 | contentBounds.size.height - expressionFrame.size.height, |
| 59 | contentBounds.size.width - expressionFrame.size.height, |
| 60 | expressionFrame.size.height); |
| 61 | expressionContainer = [[NSView alloc] initWithFrame:expressionFrame]; |
| 62 | [expressionContainer setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)]; |
| 63 | [expressionContainer addSubview:expressionField]; |
| 64 | [expressionField release]; |
| 65 | [expressionContainer addSubview:subviewButton]; |
| 66 | [subviewButton release]; |
| 67 | [[window contentView] addSubview:expressionContainer]; |
| 68 | [expressionContainer release]; |
| 69 | |
| 70 | // create the disassembly view |
| 71 | dasmView = [[MAMEDisassemblyView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) |
| 72 | machine:*machine |
| 73 | useConsole:NO]; |
| 74 | [dasmView insertSubviewItemsInMenu:[subviewButton menu] atIndex:0]; |
| 75 | dasmScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, |
| 76 | 0, |
| 77 | contentBounds.size.width, |
| 78 | expressionFrame.origin.y)]; |
| 79 | [dasmScroll setDrawsBackground:YES]; |
| 80 | [dasmScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 81 | [dasmScroll setHasHorizontalScroller:YES]; |
| 82 | [dasmScroll setHasVerticalScroller:YES]; |
| 83 | [dasmScroll setAutohidesScrollers:YES]; |
| 84 | [dasmScroll setBorderType:NSNoBorder]; |
| 85 | [dasmScroll setDocumentView:dasmView]; |
| 86 | [dasmView release]; |
| 87 | [[window contentView] addSubview:dasmScroll]; |
| 88 | [dasmScroll release]; |
| 89 | |
| 90 | // create the action popup |
| 91 | actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0, |
| 92 | expressionFrame.origin.y, |
| 93 | expressionFrame.size.height, |
| 94 | expressionFrame.size.height)]; |
| 95 | [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)]; |
| 96 | [dasmView insertActionItemsInMenu:[actionButton menu] atIndex:1]; |
| 97 | [[window contentView] addSubview:actionButton]; |
| 98 | [actionButton release]; |
| 99 | |
| 100 | // set default state |
| 101 | [dasmView selectSubviewForCPU:debug_cpu_get_visible_cpu(*machine)]; |
| 102 | [dasmView setExpression:@"curpc"]; |
| 103 | [expressionField setStringValue:@"curpc"]; |
| 104 | [expressionField selectText:self]; |
| 105 | [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[dasmView selectedSubviewIndex]]]; |
| 106 | [window makeFirstResponder:expressionField]; |
| 107 | [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]]; |
| 108 | |
| 109 | // calculate the optimal size for everything |
| 110 | { |
| 111 | NSSize desired = [NSScrollView frameSizeForContentSize:[dasmView maximumFrameSize] |
| 112 | hasHorizontalScroller:YES |
| 113 | hasVerticalScroller:YES |
| 114 | borderType:[dasmScroll borderType]]; |
| 115 | [self cascadeWindowWithDesiredSize:desired forView:dasmScroll]; |
| 116 | } |
| 117 | |
| 118 | // don't forget the result |
| 119 | return self; |
| 120 | } |
| 121 | |
| 122 | |
| 123 | - (void)dealloc { |
| 124 | [super dealloc]; |
| 125 | } |
| 126 | |
| 127 | |
| 128 | - (id <MAMEDebugViewExpressionSupport>)documentView { |
| 129 | return dasmView; |
| 130 | } |
| 131 | |
| 132 | |
| 133 | - (IBAction)changeSubview:(id)sender { |
| 134 | [dasmView selectSubviewAtIndex:[[sender selectedItem] tag]]; |
| 135 | [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]]; |
| 136 | } |
| 137 | |
| 138 | @end |
trunk/src/osd/modules/debugger/osx/memoryview.m
| r0 | r243596 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:Vas Crabb |
| 3 | //============================================================ |
| 4 | // |
| 5 | // debugosxmemoryview.m - MacOS X Cocoa debug window handling |
| 6 | // |
| 7 | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | // |
| 10 | //============================================================ |
| 11 | |
| 12 | #import "memoryview.h" |
| 13 | |
| 14 | #include "debug/debugcpu.h" |
| 15 | #include "debug/debugvw.h" |
| 16 | #include "debug/dvmemory.h" |
| 17 | |
| 18 | |
| 19 | @implementation MAMEMemoryView |
| 20 | |
| 21 | - (id)initWithFrame:(NSRect)f machine:(running_machine &)m { |
| 22 | NSMenu *contextMenu; |
| 23 | |
| 24 | if (!(self = [super initWithFrame:f type:DVT_MEMORY machine:m])) |
| 25 | return nil; |
| 26 | |
| 27 | contextMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Memory"]; |
| 28 | [self insertActionItemsInMenu:contextMenu atIndex:0]; |
| 29 | [self setMenu:contextMenu]; |
| 30 | [contextMenu release]; |
| 31 | |
| 32 | return self; |
| 33 | } |
| 34 | |
| 35 | |
| 36 | - (void)dealloc { |
| 37 | [super dealloc]; |
| 38 | } |
| 39 | |
| 40 | |
| 41 | - (BOOL)validateMenuItem:(NSMenuItem *)item { |
| 42 | SEL action = [item action]; |
| 43 | NSInteger tag = [item tag]; |
| 44 | debug_view_memory *memview = downcast<debug_view_memory *>(view); |
| 45 | |
| 46 | if (action == @selector(showChunkSize:)) { |
| 47 | [item setState:((tag == memview->bytes_per_chunk()) ? NSOnState : NSOffState)]; |
| 48 | } else if (action == @selector(showPhysicalAddresses:)) { |
| 49 | [item setState:((tag == memview->physical()) ? NSOnState : NSOffState)]; |
| 50 | } else if (action == @selector(showReverseView:)) { |
| 51 | [item setState:((tag == memview->reverse()) ? NSOnState : NSOffState)]; |
| 52 | } else if (action == @selector(showReverseViewToggle:)) { |
| 53 | [item setState:(memview->reverse() ? NSOnState : NSOffState)]; |
| 54 | } |
| 55 | return YES; |
| 56 | } |
| 57 | |
| 58 | |
| 59 | - (NSSize)maximumFrameSize { |
| 60 | debug_view_xy max; |
| 61 | device_t *curcpu = debug_cpu_get_visible_cpu(*machine); |
| 62 | debug_view_source const *source = view->source_for_device(curcpu); |
| 63 | |
| 64 | max.x = max.y = 0; |
| 65 | for (const debug_view_source *source = view->source_list().first(); |
| 66 | source != NULL; |
| 67 | source = source->next()) |
| 68 | { |
| 69 | debug_view_xy current; |
| 70 | view->set_source(*source); |
| 71 | current = view->total_size(); |
| 72 | if (current.x > max.x) |
| 73 | max.x = current.x; |
| 74 | if (current.y > max.y) |
| 75 | max.y = current.y; |
| 76 | } |
| 77 | view->set_source(*source); |
| 78 | return NSMakeSize(max.x * fontWidth, max.y * fontHeight); |
| 79 | } |
| 80 | |
| 81 | |
| 82 | - (NSString *)selectedSubviewName { |
| 83 | debug_view_source const *source = view->source(); |
| 84 | if (source != NULL) |
| 85 | return [NSString stringWithUTF8String:source->name()]; |
| 86 | else |
| 87 | return @""; |
| 88 | } |
| 89 | |
| 90 | |
| 91 | - (int)selectedSubviewIndex { |
| 92 | debug_view_source const *source = view->source(); |
| 93 | if (source != NULL) |
| 94 | return view->source_list().indexof(*source); |
| 95 | else |
| 96 | return -1; |
| 97 | } |
| 98 | |
| 99 | |
| 100 | - (void)selectSubviewAtIndex:(int)index { |
| 101 | int const selected = view->source_list().indexof(*view->source()); |
| 102 | if (selected != index) { |
| 103 | view->set_source(*view->source_list().find(index)); |
| 104 | if ([[self window] firstResponder] != self) |
| 105 | view->set_cursor_visible(false); |
| 106 | } |
| 107 | } |
| 108 | |
| 109 | |
| 110 | - (void)selectSubviewForCPU:(device_t *)device { |
| 111 | debug_view_source const *selected = view->source(); |
| 112 | debug_view_source const *source = view->source_for_device(device); |
| 113 | if ( selected != source ) { |
| 114 | view->set_source(*source); |
| 115 | if ([[self window] firstResponder] != self) |
| 116 | view->set_cursor_visible(false); |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | |
| 121 | - (NSString *)expression { |
| 122 | return [NSString stringWithUTF8String:downcast<debug_view_memory *>(view)->expression()]; |
| 123 | } |
| 124 | |
| 125 | |
| 126 | - (void)setExpression:(NSString *)exp { |
| 127 | downcast<debug_view_memory *>(view)->set_expression([exp UTF8String]); |
| 128 | } |
| 129 | |
| 130 | |
| 131 | - (IBAction)showChunkSize:(id)sender { |
| 132 | downcast<debug_view_memory *>(view)->set_bytes_per_chunk([sender tag]); |
| 133 | } |
| 134 | |
| 135 | |
| 136 | - (IBAction)showPhysicalAddresses:(id)sender { |
| 137 | downcast<debug_view_memory *>(view)->set_physical([sender tag]); |
| 138 | } |
| 139 | |
| 140 | |
| 141 | - (IBAction)showReverseView:(id)sender { |
| 142 | downcast<debug_view_memory *>(view)->set_reverse([sender tag]); |
| 143 | } |
| 144 | |
| 145 | |
| 146 | - (IBAction)showReverseViewToggle:(id)sender { |
| 147 | downcast<debug_view_memory *>(view)->set_reverse(!downcast<debug_view_memory *>(view)->reverse()); |
| 148 | } |
| 149 | |
| 150 | |
| 151 | - (IBAction)changeBytesPerLine:(id)sender { |
| 152 | debug_view_memory *const memView = downcast<debug_view_memory *>(view); |
| 153 | memView->set_chunks_per_row(memView->chunks_per_row() + [sender tag]); |
| 154 | } |
| 155 | |
| 156 | |
| 157 | - (void)insertActionItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index { |
| 158 | NSInteger tag; |
| 159 | for (tag = 1; tag <= 8; tag <<= 1) { |
| 160 | NSString *title = [NSString stringWithFormat:@"%ld-byte Chunks", (long)tag]; |
| 161 | NSMenuItem *chunkItem = [menu insertItemWithTitle:title |
| 162 | action:@selector(showChunkSize:) |
| 163 | keyEquivalent:[NSString stringWithFormat:@"%ld", (long)tag] |
| 164 | atIndex:index++]; |
| 165 | [chunkItem setTarget:self]; |
| 166 | [chunkItem setTag:tag]; |
| 167 | } |
| 168 | |
| 169 | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 170 | |
| 171 | NSMenuItem *logicalItem = [menu insertItemWithTitle:@"Logical Addresses" |
| 172 | action:@selector(showPhysicalAddresses:) |
| 173 | keyEquivalent:@"v" |
| 174 | atIndex:index++]; |
| 175 | [logicalItem setTarget:self]; |
| 176 | [logicalItem setTag:FALSE]; |
| 177 | |
| 178 | NSMenuItem *physicalItem = [menu insertItemWithTitle:@"Physical Addresses" |
| 179 | action:@selector(showPhysicalAddresses:) |
| 180 | keyEquivalent:@"y" |
| 181 | atIndex:index++]; |
| 182 | [physicalItem setTarget:self]; |
| 183 | [physicalItem setTag:TRUE]; |
| 184 | |
| 185 | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 186 | |
| 187 | NSMenuItem *reverseItem = [menu insertItemWithTitle:@"Reverse View" |
| 188 | action:@selector(showReverseViewToggle:) |
| 189 | keyEquivalent:@"r" |
| 190 | atIndex:index++]; |
| 191 | [reverseItem setTarget:self]; |
| 192 | |
| 193 | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 194 | |
| 195 | NSMenuItem *increaseItem = [menu insertItemWithTitle:@"Increase Bytes Per Line" |
| 196 | action:@selector(changeBytesPerLine:) |
| 197 | keyEquivalent:@"p" |
| 198 | atIndex:index++]; |
| 199 | [increaseItem setTarget:self]; |
| 200 | [increaseItem setTag:1]; |
| 201 | |
| 202 | NSMenuItem *decreaseItem = [menu insertItemWithTitle:@"Decrease Bytes Per Line" |
| 203 | action:@selector(changeBytesPerLine:) |
| 204 | keyEquivalent:@"o" |
| 205 | atIndex:index++]; |
| 206 | [decreaseItem setTarget:self]; |
| 207 | [decreaseItem setTag:-1]; |
| 208 | |
| 209 | if (index < [menu numberOfItems]) |
| 210 | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 211 | } |
| 212 | |
| 213 | |
| 214 | - (void)insertSubviewItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index { |
| 215 | for (const debug_view_source *source = view->source_list().first(); source != NULL; source = source->next()) |
| 216 | { |
| 217 | [[menu insertItemWithTitle:[NSString stringWithUTF8String:source->name()] |
| 218 | action:NULL |
| 219 | keyEquivalent:@"" |
| 220 | atIndex:index++] setTag:view->source_list().indexof(*source)]; |
| 221 | } |
| 222 | if (index < [menu numberOfItems]) |
| 223 | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 224 | } |
| 225 | |
| 226 | @end |
trunk/src/osd/modules/debugger/osx/memoryviewer.m
| r0 | r243596 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:Vas Crabb |
| 3 | //============================================================ |
| 4 | // |
| 5 | // debugosxmemoryviewer.m - MacOS X Cocoa debug window handling |
| 6 | // |
| 7 | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | // |
| 10 | //============================================================ |
| 11 | |
| 12 | #import "memoryviewer.h" |
| 13 | |
| 14 | #import "debugview.h" |
| 15 | #import "memoryview.h" |
| 16 | |
| 17 | #include "debug/debugcpu.h" |
| 18 | |
| 19 | |
| 20 | @implementation MAMEMemoryViewer |
| 21 | |
| 22 | - (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c { |
| 23 | NSScrollView *memoryScroll; |
| 24 | NSView *expressionContainer; |
| 25 | NSPopUpButton *actionButton, *subviewButton; |
| 26 | NSRect contentBounds, expressionFrame; |
| 27 | |
| 28 | if (!(self = [super initWithMachine:m title:@"Memory" console:c])) |
| 29 | return nil; |
| 30 | contentBounds = [[window contentView] bounds]; |
| 31 | |
| 32 | // create the expression field |
| 33 | expressionField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)]; |
| 34 | [expressionField setAutoresizingMask:(NSViewWidthSizable | NSViewMaxXMargin | NSViewMinYMargin)]; |
| 35 | [expressionField setFont:[[MAMEDebugView class] defaultFont]]; |
| 36 | [expressionField setFocusRingType:NSFocusRingTypeNone]; |
| 37 | [expressionField setTarget:self]; |
| 38 | [expressionField setAction:@selector(doExpression:)]; |
| 39 | [expressionField setDelegate:self]; |
| 40 | expressionFrame = [expressionField frame]; |
| 41 | expressionFrame.size.width = (contentBounds.size.width - expressionFrame.size.height) / 2; |
| 42 | [expressionField setFrameSize:expressionFrame.size]; |
| 43 | |
| 44 | // create the subview popup |
| 45 | subviewButton = [[NSPopUpButton alloc] initWithFrame:NSOffsetRect(expressionFrame, |
| 46 | expressionFrame.size.width, |
| 47 | 0)]; |
| 48 | [subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinXMargin | NSViewMinYMargin)]; |
| 49 | [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle]; |
| 50 | [subviewButton setFocusRingType:NSFocusRingTypeNone]; |
| 51 | [subviewButton setFont:[[MAMEDebugView class] defaultFont]]; |
| 52 | [subviewButton setTarget:self]; |
| 53 | [subviewButton setAction:@selector(changeSubview:)]; |
| 54 | [[subviewButton cell] setArrowPosition:NSPopUpArrowAtBottom]; |
| 55 | |
| 56 | // create a container for the expression field and subview popup |
| 57 | expressionFrame = NSMakeRect(expressionFrame.size.height, |
| 58 | contentBounds.size.height - expressionFrame.size.height, |
| 59 | contentBounds.size.width - expressionFrame.size.height, |
| 60 | expressionFrame.size.height); |
| 61 | expressionContainer = [[NSView alloc] initWithFrame:expressionFrame]; |
| 62 | [expressionContainer setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)]; |
| 63 | [expressionContainer addSubview:expressionField]; |
| 64 | [expressionField release]; |
| 65 | [expressionContainer addSubview:subviewButton]; |
| 66 | [subviewButton release]; |
| 67 | [[window contentView] addSubview:expressionContainer]; |
| 68 | [expressionContainer release]; |
| 69 | |
| 70 | // create the memory view |
| 71 | memoryView = [[MAMEMemoryView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) |
| 72 | machine:*machine]; |
| 73 | [memoryView insertSubviewItemsInMenu:[subviewButton menu] atIndex:0]; |
| 74 | memoryScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, |
| 75 | 0, |
| 76 | contentBounds.size.width, |
| 77 | expressionFrame.origin.y)]; |
| 78 | [memoryScroll setDrawsBackground:YES]; |
| 79 | [memoryScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 80 | [memoryScroll setHasHorizontalScroller:YES]; |
| 81 | [memoryScroll setHasVerticalScroller:YES]; |
| 82 | [memoryScroll setAutohidesScrollers:YES]; |
| 83 | [memoryScroll setBorderType:NSNoBorder]; |
| 84 | [memoryScroll setDocumentView:memoryView]; |
| 85 | [memoryView release]; |
| 86 | [[window contentView] addSubview:memoryScroll]; |
| 87 | [memoryScroll release]; |
| 88 | |
| 89 | // create the action popup |
| 90 | actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0, |
| 91 | expressionFrame.origin.y, |
| 92 | expressionFrame.size.height, |
| 93 | expressionFrame.size.height)]; |
| 94 | [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)]; |
| 95 | [memoryView insertActionItemsInMenu:[actionButton menu] atIndex:1]; |
| 96 | [[window contentView] addSubview:actionButton]; |
| 97 | [actionButton release]; |
| 98 | |
| 99 | // set default state |
| 100 | [memoryView selectSubviewForCPU:debug_cpu_get_visible_cpu(*machine)]; |
| 101 | [memoryView setExpression:@"0"]; |
| 102 | [expressionField setStringValue:@"0"]; |
| 103 | [expressionField selectText:self]; |
| 104 | [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[memoryView selectedSubviewIndex]]]; |
| 105 | [window makeFirstResponder:expressionField]; |
| 106 | [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]]; |
| 107 | |
| 108 | // calculate the optimal size for everything |
| 109 | NSSize const desired = [NSScrollView frameSizeForContentSize:[memoryView maximumFrameSize] |
| 110 | hasHorizontalScroller:YES |
| 111 | hasVerticalScroller:YES |
| 112 | borderType:[memoryScroll borderType]]; |
| 113 | [self cascadeWindowWithDesiredSize:desired forView:memoryScroll]; |
| 114 | |
| 115 | // don't forget the result |
| 116 | return self; |
| 117 | } |
| 118 | |
| 119 | |
| 120 | - (void)dealloc { |
| 121 | [super dealloc]; |
| 122 | } |
| 123 | |
| 124 | |
| 125 | - (id <MAMEDebugViewExpressionSupport>)documentView { |
| 126 | return memoryView; |
| 127 | } |
| 128 | |
| 129 | |
| 130 | - (IBAction)changeSubview:(id)sender { |
| 131 | [memoryView selectSubviewAtIndex:[[sender selectedItem] tag]]; |
| 132 | [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]]; |
| 133 | } |
| 134 | |
| 135 | @end |
trunk/src/osd/modules/debugger/osx/pointsviewer.m
| r0 | r243596 | |
| 1 | // license:BSD-3-Clause |
| 2 | // copyright-holders:Vas Crabb |
| 3 | //============================================================ |
| 4 | // |
| 5 | // debugosxpointsviewer.m - MacOS X Cocoa debug window handling |
| 6 | // |
| 7 | // Copyright (c) 1996-2015, Nicola Salmoria and the MAME Team. |
| 8 | // Visit http://mamedev.org for licensing and usage restrictions. |
| 9 | // |
| 10 | //============================================================ |
| 11 | |
| 12 | #import "pointsviewer.h" |
| 13 | |
| 14 | #import "breakpointsview.h" |
| 15 | #import "watchpointsview.h" |
| 16 | |
| 17 | |
| 18 | @implementation MAMEPointsViewer |
| 19 | |
| 20 | - (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c { |
| 21 | MAMEDebugView *breakView, *watchView; |
| 22 | NSScrollView *breakScroll, *watchScroll; |
| 23 | NSTabViewItem *breakTab, *watchTab; |
| 24 | NSPopUpButton *actionButton, *subviewButton; |
| 25 | NSRect contentBounds; |
| 26 | |
| 27 | if (!(self = [super initWithMachine:m title:@"(Break|Watch)points" console:c])) |
| 28 | return nil; |
| 29 | contentBounds = [[window contentView] bounds]; |
| 30 | |
| 31 | // create the subview popup |
| 32 | subviewButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(19, |
| 33 | contentBounds.size.height - 19, |
| 34 | contentBounds.size.width - 19, |
| 35 | 19)]; |
| 36 | [subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)]; |
| 37 | [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle]; |
| 38 | [subviewButton setFocusRingType:NSFocusRingTypeNone]; |
| 39 | [subviewButton setFont:[[MAMEDebugView class] defaultFont]]; |
| 40 | [subviewButton setTarget:self]; |
| 41 | [subviewButton setAction:@selector(changeSubview:)]; |
| 42 | [[subviewButton cell] setArrowPosition:NSPopUpArrowAtBottom]; |
| 43 | [[[subviewButton menu] addItemWithTitle:@"All Breakpoints" |
| 44 | action:NULL |
| 45 | keyEquivalent:@""] setTag:0]; |
| 46 | [[[subviewButton menu] addItemWithTitle:@"All Watchpoints" |
| 47 | action:NULL |
| 48 | keyEquivalent:@""] setTag:1]; |
| 49 | [[window contentView] addSubview:subviewButton]; |
| 50 | [subviewButton release]; |
| 51 | |
| 52 | // create the action popup |
| 53 | actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0, |
| 54 | contentBounds.size.height - 19, |
| 55 | 19, |
| 56 | 19)]; |
| 57 | [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)]; |
| 58 | [[window contentView] addSubview:actionButton]; |
| 59 | [actionButton release]; |
| 60 | |
| 61 | // create the breakpoints view |
| 62 | breakView = [[MAMEBreakpointsView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) |
| 63 | machine:*machine]; |
| 64 | breakScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, |
| 65 | 0, |
| 66 | contentBounds.size.width, |
| 67 | contentBounds.size.height - 19)]; |
| 68 | [breakScroll setDrawsBackground:YES]; |
| 69 | [breakScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 70 | [breakScroll setHasHorizontalScroller:YES]; |
| 71 | [breakScroll setHasVerticalScroller:YES]; |
| 72 | [breakScroll setAutohidesScrollers:YES]; |
| 73 | [breakScroll setBorderType:NSNoBorder]; |
| 74 | [breakScroll setDocumentView:breakView]; |
| 75 | [breakView release]; |
| 76 | breakTab = [[NSTabViewItem alloc] initWithIdentifier:nil]; |
| 77 | [breakTab setView:breakScroll]; |
| 78 | [breakScroll release]; |
| 79 | |
| 80 | // create the breakpoints view |
| 81 | watchView = [[MAMEWatchpointsView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) |
| 82 | machine:*machine]; |
| 83 | watchScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, |
| 84 | 0, |
| 85 | contentBounds.size.width, |
| 86 | contentBounds.size.height - 19)]; |
| 87 | [watchScroll setDrawsBackground:YES]; |
| 88 | [watchScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 89 | [watchScroll setHasHorizontalScroller:YES]; |
| 90 | [watchScroll setHasVerticalScroller:YES]; |
| 91 | [watchScroll setAutohidesScrollers:YES]; |
| 92 | [watchScroll setBorderType:NSNoBorder]; |
| 93 | [watchScroll setDocumentView:watchView]; |
| 94 | [watchView release]; |
| 95 | watchTab = [[NSTabViewItem alloc] initWithIdentifier:nil]; |
| 96 | [watchTab setView:watchScroll]; |
| 97 | [watchScroll release]; |
| 98 | |
| 99 | // create a tabless tabview for the two subviews |
| 100 | tabs = [[NSTabView alloc] initWithFrame:NSMakeRect(0, |
| 101 | 0, |
| 102 | contentBounds.size.width, |
| 103 | contentBounds.size.height - 19)]; |
| 104 | [tabs setTabViewType:NSNoTabsNoBorder]; |
| 105 | [tabs setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 106 | [tabs addTabViewItem:breakTab]; |
| 107 | [breakTab release]; |
| 108 | [tabs addTabViewItem:watchTab]; |
| 109 | [watchTab release]; |
| 110 | [[window contentView] addSubview:tabs]; |
| 111 | [tabs release]; |
| 112 | |
| 113 | // set default state |
| 114 | [subviewButton selectItemAtIndex:0]; |
| 115 | [tabs selectFirstTabViewItem:self]; |
| 116 | [window makeFirstResponder:subviewButton]; |
| 117 | [window setTitle:[[subviewButton selectedItem] title]]; |
| 118 | |
| 119 | // calculate the optimal size for everything |
| 120 | NSSize const breakDesired = [NSScrollView frameSizeForContentSize:[breakView maximumFrameSize] |
| 121 | hasHorizontalScroller:YES |
| 122 | hasVerticalScroller:YES |
| 123 | borderType:[breakScroll borderType]]; |
| 124 | NSSize const watchDesired = [NSScrollView frameSizeForContentSize:[watchView maximumFrameSize] |
| 125 | hasHorizontalScroller:YES |
| 126 | hasVerticalScroller:YES |
| 127 | borderType:[watchScroll borderType]]; |
| 128 | NSSize const desired = NSMakeSize(MAX(breakDesired.width, watchDesired.width), |
| 129 | MAX(breakDesired.height, watchDesired.height)); |
| 130 | [self cascadeWindowWithDesiredSize:desired forView:tabs]; |
| 131 | |
| 132 | // don't forget the result |
| 133 | return self; |
| 134 | } |
| 135 | |
| 136 | |
| 137 | - (void)dealloc { |
| 138 | [super dealloc]; |
| 139 | } |
| 140 | |
| 141 | |
| 142 | - (IBAction)changeSubview:(id)sender { |
| 143 | [tabs selectTabViewItemAtIndex:[[sender selectedItem] tag]]; |
| 144 | [window setTitle:[[sender selectedItem] title]]; |
| 145 | } |
| 146 | |
| 147 | @end |