trunk/src/osd/modules/debugger/osx/debugconsole.m
| r243601 | r243602 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // debugconsole.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 "devicesviewer.h" |
| 18 | | #import "disassemblyview.h" |
| 19 | | #import "disassemblyviewer.h" |
| 20 | | #import "errorlogviewer.h" |
| 21 | | #import "memoryviewer.h" |
| 22 | | #import "pointsviewer.h" |
| 23 | | #import "registersview.h" |
| 24 | | |
| 25 | | #include "debug/debugcon.h" |
| 26 | | #include "debug/debugcpu.h" |
| 27 | | |
| 28 | | |
| 29 | | @implementation MAMEDebugConsole |
| 30 | | |
| 31 | | - (id)initWithMachine:(running_machine &)m { |
| 32 | | NSSplitView *regSplit, *dasmSplit; |
| 33 | | NSScrollView *regScroll, *dasmScroll, *consoleScroll; |
| 34 | | NSView *consoleContainer; |
| 35 | | NSPopUpButton *actionButton; |
| 36 | | NSRect rct; |
| 37 | | |
| 38 | | // initialise superclass |
| 39 | | if (!(self = [super initWithMachine:m title:@"Debug"])) |
| 40 | | return nil; |
| 41 | | history = [[MAMEDebugCommandHistory alloc] init]; |
| 42 | | auxiliaryWindows = [[NSMutableArray alloc] init]; |
| 43 | | |
| 44 | | // create the register view |
| 45 | | regView = [[MAMERegistersView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine]; |
| 46 | | regScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 47 | | [regScroll setDrawsBackground:YES]; |
| 48 | | [regScroll setHasHorizontalScroller:YES]; |
| 49 | | [regScroll setHasVerticalScroller:YES]; |
| 50 | | [regScroll setAutohidesScrollers:YES]; |
| 51 | | [regScroll setBorderType:NSBezelBorder]; |
| 52 | | [regScroll setDocumentView:regView]; |
| 53 | | [regView release]; |
| 54 | | |
| 55 | | // create the disassembly view |
| 56 | | dasmView = [[MAMEDisassemblyView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) |
| 57 | | machine:*machine |
| 58 | | useConsole:YES]; |
| 59 | | [dasmView setExpression:@"curpc"]; |
| 60 | | dasmScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 61 | | [dasmScroll setDrawsBackground:YES]; |
| 62 | | [dasmScroll setHasHorizontalScroller:YES]; |
| 63 | | [dasmScroll setHasVerticalScroller:YES]; |
| 64 | | [dasmScroll setAutohidesScrollers:YES]; |
| 65 | | [dasmScroll setBorderType:NSBezelBorder]; |
| 66 | | [dasmScroll setDocumentView:dasmView]; |
| 67 | | [dasmView release]; |
| 68 | | |
| 69 | | // create the console view |
| 70 | | consoleView = [[MAMEConsoleView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) machine:*machine]; |
| 71 | | consoleScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 72 | | [consoleScroll setDrawsBackground:YES]; |
| 73 | | [consoleScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 74 | | [consoleScroll setHasHorizontalScroller:YES]; |
| 75 | | [consoleScroll setHasVerticalScroller:YES]; |
| 76 | | [consoleScroll setAutohidesScrollers:YES]; |
| 77 | | [consoleScroll setBorderType:NSBezelBorder]; |
| 78 | | [consoleScroll setDocumentView:consoleView]; |
| 79 | | [consoleView release]; |
| 80 | | |
| 81 | | // create the command field |
| 82 | | commandField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)]; |
| 83 | | [commandField setAutoresizingMask:(NSViewWidthSizable | NSViewMaxYMargin)]; |
| 84 | | [commandField setFont:[[MAMEDebugView class] defaultFont]]; |
| 85 | | [commandField setFocusRingType:NSFocusRingTypeNone]; |
| 86 | | [commandField setTarget:self]; |
| 87 | | [commandField setAction:@selector(doCommand:)]; |
| 88 | | [commandField setDelegate:self]; |
| 89 | | rct = [commandField frame]; |
| 90 | | [commandField setFrame:NSMakeRect(rct.size.height, 0, rct.size.width - rct.size.height, rct.size.height)]; |
| 91 | | |
| 92 | | // create the action pull-down button |
| 93 | | actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0, 0, rct.size.height, rct.size.height)]; |
| 94 | | [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMaxYMargin)]; |
| 95 | | [dasmView insertActionItemsInMenu:[actionButton menu] atIndex:1]; |
| 96 | | |
| 97 | | // create the container for the console and command input field |
| 98 | | consoleContainer = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 99 | | [consoleScroll setFrame:NSMakeRect(0, |
| 100 | | rct.size.height, |
| 101 | | 100, |
| 102 | | [consoleContainer bounds].size.height - rct.size.height)]; |
| 103 | | [consoleContainer addSubview:consoleScroll]; |
| 104 | | [consoleContainer addSubview:commandField]; |
| 105 | | [consoleContainer addSubview:actionButton]; |
| 106 | | [consoleScroll release]; |
| 107 | | [commandField release]; |
| 108 | | [actionButton release]; |
| 109 | | |
| 110 | | // create the split between the disassembly and the console |
| 111 | | dasmSplit = [[NSSplitView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 112 | | [dasmSplit setDelegate:self]; |
| 113 | | [dasmSplit setVertical:NO]; |
| 114 | | [dasmSplit addSubview:dasmScroll]; |
| 115 | | [dasmSplit addSubview:consoleContainer]; |
| 116 | | [dasmScroll release]; |
| 117 | | [consoleContainer release]; |
| 118 | | |
| 119 | | // create the split between the registers and the console |
| 120 | | regSplit = [[NSSplitView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 121 | | [regSplit setDelegate:self]; |
| 122 | | [regSplit setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 123 | | [regSplit setVertical:YES]; |
| 124 | | [regSplit addSubview:regScroll]; |
| 125 | | [regSplit addSubview:dasmSplit]; |
| 126 | | [regScroll release]; |
| 127 | | [dasmSplit release]; |
| 128 | | |
| 129 | | // put the split views in the window and get them into a half-reasonable state |
| 130 | | [window setContentView:regSplit]; |
| 131 | | [regSplit release]; |
| 132 | | [regSplit adjustSubviews]; |
| 133 | | [dasmSplit adjustSubviews]; |
| 134 | | |
| 135 | | // keyboard focus should start on the command field |
| 136 | | [window makeFirstResponder:commandField]; |
| 137 | | |
| 138 | | // calculate the optimal size for everything |
| 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 | | |
| 158 | | consoleSize.width += consoleCurrent.width - [consoleScroll frame].size.width; |
| 159 | | consoleSize.height += consoleCurrent.height - [consoleScroll frame].size.height; |
| 160 | | adjustment.width = regSize.width - regCurrent.width; |
| 161 | | adjustment.height = regSize.height - regCurrent.height; |
| 162 | | adjustment.width += MAX(dasmSize.width - dasmCurrent.width, consoleSize.width - consoleCurrent.width); |
| 163 | | |
| 164 | | windowFrame.size.width += adjustment.width; |
| 165 | | windowFrame.size.height += adjustment.height; // not used - better to go for fixed height |
| 166 | | windowFrame.size.height = MIN(512.0, available.size.height); |
| 167 | | windowFrame.size.width = MIN(windowFrame.size.width, available.size.width); |
| 168 | | windowFrame.origin.x = available.origin.x + available.size.width - windowFrame.size.width; |
| 169 | | windowFrame.origin.y = available.origin.y; |
| 170 | | [window setFrame:windowFrame display:YES]; |
| 171 | | |
| 172 | | NSRect lhsFrame = [regScroll frame]; |
| 173 | | NSRect rhsFrame = [dasmSplit frame]; |
| 174 | | adjustment.width = MIN(regSize.width, ([regSplit frame].size.width - [regSplit dividerThickness]) / 2); |
| 175 | | rhsFrame.origin.x -= lhsFrame.size.width - adjustment.width; |
| 176 | | rhsFrame.size.width += lhsFrame.size.width - adjustment.width; |
| 177 | | lhsFrame.size.width = adjustment.width; |
| 178 | | [regScroll setFrame:lhsFrame]; |
| 179 | | [dasmSplit setFrame:rhsFrame]; |
| 180 | | |
| 181 | | // select the current processor |
| 182 | | [self setCPU:machine->firstcpu]; |
| 183 | | |
| 184 | | [[NSNotificationCenter defaultCenter] addObserver:self |
| 185 | | selector:@selector(auxiliaryWindowWillClose:) |
| 186 | | name:MAMEAuxiliaryDebugWindowWillCloseNotification |
| 187 | | object:nil]; |
| 188 | | |
| 189 | | // don't forget the return value |
| 190 | | return self; |
| 191 | | } |
| 192 | | |
| 193 | | |
| 194 | | - (void)dealloc { |
| 195 | | [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 196 | | |
| 197 | | if (history != nil) |
| 198 | | [history release]; |
| 199 | | if (auxiliaryWindows != nil) |
| 200 | | [auxiliaryWindows release]; |
| 201 | | |
| 202 | | [super dealloc]; |
| 203 | | } |
| 204 | | |
| 205 | | |
| 206 | | - (void)setCPU:(device_t *)device { |
| 207 | | [regView selectSubviewForDevice:device]; |
| 208 | | [dasmView selectSubviewForDevice:device]; |
| 209 | | [window setTitle:[NSString stringWithFormat:@"Debug: %s - %s '%s'", |
| 210 | | device->machine().system().name, |
| 211 | | device->name(), |
| 212 | | device->tag()]]; |
| 213 | | } |
| 214 | | |
| 215 | | |
| 216 | | - (IBAction)doCommand:(id)sender { |
| 217 | | NSString *command = [sender stringValue]; |
| 218 | | if ([command length] == 0) { |
| 219 | | debug_cpu_get_visible_cpu(*machine)->debug()->single_step(); |
| 220 | | [history reset]; |
| 221 | | } else { |
| 222 | | debug_console_execute_command(*machine, [command UTF8String], 1); |
| 223 | | [history add:command]; |
| 224 | | [history edit]; |
| 225 | | } |
| 226 | | [sender setStringValue:@""]; |
| 227 | | } |
| 228 | | |
| 229 | | |
| 230 | | - (IBAction)debugNewMemoryWindow:(id)sender { |
| 231 | | MAMEMemoryViewer *win = [[MAMEMemoryViewer alloc] initWithMachine:*machine console:self]; |
| 232 | | [auxiliaryWindows addObject:win]; |
| 233 | | [win release]; |
| 234 | | [win activate]; |
| 235 | | } |
| 236 | | |
| 237 | | |
| 238 | | - (IBAction)debugNewDisassemblyWindow:(id)sender { |
| 239 | | MAMEDisassemblyViewer *win = [[MAMEDisassemblyViewer alloc] initWithMachine:*machine console:self]; |
| 240 | | [auxiliaryWindows addObject:win]; |
| 241 | | [win release]; |
| 242 | | [win activate]; |
| 243 | | } |
| 244 | | |
| 245 | | |
| 246 | | - (IBAction)debugNewErrorLogWindow:(id)sender { |
| 247 | | MAMEErrorLogViewer *win = [[MAMEErrorLogViewer alloc] initWithMachine:*machine console:self]; |
| 248 | | [auxiliaryWindows addObject:win]; |
| 249 | | [win release]; |
| 250 | | [win activate]; |
| 251 | | } |
| 252 | | |
| 253 | | |
| 254 | | - (IBAction)debugNewPointsWindow:(id)sender{ |
| 255 | | MAMEPointsViewer *win = [[MAMEPointsViewer alloc] initWithMachine:*machine console:self]; |
| 256 | | [auxiliaryWindows addObject:win]; |
| 257 | | [win release]; |
| 258 | | [win activate]; |
| 259 | | } |
| 260 | | |
| 261 | | |
| 262 | | - (IBAction)debugNewDevicesWindow:(id)sender { |
| 263 | | MAMEDevicesViewer *win = [[MAMEDevicesViewer alloc] initWithMachine:*machine console:self]; |
| 264 | | [auxiliaryWindows addObject:win]; |
| 265 | | [win release]; |
| 266 | | [win activate]; |
| 267 | | } |
| 268 | | |
| 269 | | |
| 270 | | - (void)debugNewMemoryWindowForSpace:(address_space *)space device:(device_t *)device expression:(NSString *)expression { |
| 271 | | MAMEMemoryViewer *win = [[MAMEMemoryViewer alloc] initWithMachine:*machine console:self]; |
| 272 | | [auxiliaryWindows addObject:win]; |
| 273 | | [win release]; |
| 274 | | if ([win selectSubviewForSpace:space]) |
| 275 | | { |
| 276 | | if (expression != nil) |
| 277 | | [win setExpression:expression]; |
| 278 | | } |
| 279 | | else |
| 280 | | { |
| 281 | | [win selectSubviewForDevice:device]; |
| 282 | | } |
| 283 | | [win activate]; |
| 284 | | } |
| 285 | | |
| 286 | | |
| 287 | | - (void)debugNewDisassemblyWindowForSpace:(address_space *)space device:(device_t *)device expression:(NSString *)expression { |
| 288 | | MAMEDisassemblyViewer *win = [[MAMEDisassemblyViewer alloc] initWithMachine:*machine console:self]; |
| 289 | | [auxiliaryWindows addObject:win]; |
| 290 | | [win release]; |
| 291 | | if ([win selectSubviewForSpace:space]) |
| 292 | | { |
| 293 | | if (expression != nil) |
| 294 | | [win setExpression:expression]; |
| 295 | | } |
| 296 | | else |
| 297 | | { |
| 298 | | [win selectSubviewForDevice:device]; |
| 299 | | } |
| 300 | | [win activate]; |
| 301 | | } |
| 302 | | |
| 303 | | |
| 304 | | - (void)showDebugger:(NSNotification *)notification { |
| 305 | | device_t *device = (device_t * )[[[notification userInfo] objectForKey:@"MAMEDebugDevice"] pointerValue]; |
| 306 | | if (&device->machine() == machine) |
| 307 | | { |
| 308 | | [self setCPU:device]; |
| 309 | | [window makeKeyAndOrderFront:self]; |
| 310 | | } |
| 311 | | } |
| 312 | | |
| 313 | | |
| 314 | | - (void)auxiliaryWindowWillClose:(NSNotification *)notification { |
| 315 | | [auxiliaryWindows removeObjectIdenticalTo:[notification object]]; |
| 316 | | } |
| 317 | | |
| 318 | | |
| 319 | | - (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor { |
| 320 | | if (control == commandField) |
| 321 | | [history edit]; |
| 322 | | |
| 323 | | return YES; |
| 324 | | } |
| 325 | | |
| 326 | | |
| 327 | | - (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command { |
| 328 | | if (control == commandField) { |
| 329 | | if (command == @selector(cancelOperation:)) { |
| 330 | | [commandField setStringValue:@""]; |
| 331 | | [history reset]; |
| 332 | | return YES; |
| 333 | | } else if (command == @selector(moveUp:)) { |
| 334 | | NSString *hist = [history previous:[commandField stringValue]]; |
| 335 | | if (hist != nil) { |
| 336 | | [commandField setStringValue:hist]; |
| 337 | | [commandField selectText:self]; |
| 338 | | [(NSText *)[window firstResponder] setSelectedRange:NSMakeRange([hist length], 0)]; |
| 339 | | } |
| 340 | | return YES; |
| 341 | | } else if (command == @selector(moveDown:)) { |
| 342 | | NSString *hist = [history next:[commandField stringValue]]; |
| 343 | | if (hist != nil) { |
| 344 | | [commandField setStringValue:hist]; |
| 345 | | [commandField selectText:self]; |
| 346 | | [(NSText *)[window firstResponder] setSelectedRange:NSMakeRange([hist length], 0)]; |
| 347 | | } |
| 348 | | return YES; |
| 349 | | } |
| 350 | | } |
| 351 | | return NO; |
| 352 | | } |
| 353 | | |
| 354 | | |
| 355 | | - (void)windowWillClose:(NSNotification *)notification { |
| 356 | | if ([notification object] == window) |
| 357 | | { |
| 358 | | NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithPointer:machine], |
| 359 | | @"MAMEDebugMachine", |
| 360 | | nil]; |
| 361 | | [[NSNotificationCenter defaultCenter] postNotificationName:MAMEHideDebuggerNotification |
| 362 | | object:self |
| 363 | | userInfo:info]; |
| 364 | | debug_cpu_get_visible_cpu(*machine)->debug()->go(); |
| 365 | | } |
| 366 | | } |
| 367 | | |
| 368 | | |
| 369 | | - (CGFloat)splitView:(NSSplitView *)sender constrainMinCoordinate:(CGFloat)min ofSubviewAt:(NSInteger)offs { |
| 370 | | return (min < 100) ? 100 : min; |
| 371 | | } |
| 372 | | |
| 373 | | |
| 374 | | - (CGFloat)splitView:(NSSplitView *)sender constrainMaxCoordinate:(CGFloat)max ofSubviewAt:(NSInteger)offs { |
| 375 | | NSSize sz = [sender bounds].size; |
| 376 | | CGFloat allowed = ([sender isVertical] ? sz.width : sz.height) - 100 - [sender dividerThickness]; |
| 377 | | return (max > allowed) ? allowed : max; |
| 378 | | } |
| 379 | | |
| 380 | | |
| 381 | | - (BOOL)splitView:(NSSplitView *)sender canCollapseSubview:(NSView *)subview { |
| 382 | | // allow registers or disassembly to be collapsed, but not console |
| 383 | | return [[sender subviews] indexOfObjectIdenticalTo:subview] == 0; |
| 384 | | } |
| 385 | | |
| 386 | | |
| 387 | | - (void)splitView:(NSSplitView *)sender resizeSubviewsWithOldSize:(NSSize)oldSize { |
| 388 | | // This can only deal with a single split, but that's all we use, anyway |
| 389 | | NSRect first, second; |
| 390 | | [sender adjustSubviews]; |
| 391 | | first = [[[sender subviews] objectAtIndex:0] frame]; |
| 392 | | second = [[[sender subviews] objectAtIndex:1] frame]; |
| 393 | | if ([sender isVertical]) { |
| 394 | | if (first.size.width < 100) { |
| 395 | | CGFloat diff = 100 - first.size.width; |
| 396 | | first.size.width = 100; |
| 397 | | second.origin.x += diff; |
| 398 | | second.size.width -= diff; |
| 399 | | } else if (second.size.width < 100) { |
| 400 | | CGFloat diff = 100 - second.size.width; |
| 401 | | second.size.width = 100; |
| 402 | | second.origin.x -= diff; |
| 403 | | first.size.width -= diff; |
| 404 | | } |
| 405 | | } else { |
| 406 | | if (first.size.height < 100) { |
| 407 | | CGFloat diff = 100 - first.size.height; |
| 408 | | first.size.height = 100; |
| 409 | | second.origin.y += diff; |
| 410 | | second.size.height -= diff; |
| 411 | | } else if (second.size.height < 100) { |
| 412 | | CGFloat diff = 100 - second.size.height; |
| 413 | | second.size.height = 100; |
| 414 | | second.origin.y -= diff; |
| 415 | | first.size.height -= diff; |
| 416 | | } |
| 417 | | } |
| 418 | | [[[sender subviews] objectAtIndex:0] setFrame:first]; |
| 419 | | [[[sender subviews] objectAtIndex:1] setFrame:second]; |
| 420 | | } |
| 421 | | |
| 422 | | @end |
trunk/src/osd/modules/debugger/osx/debugosxdebugconsole.m
| r0 | r243602 | |
| 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
| r0 | r243602 | |
| 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
| r0 | r243602 | |
| 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
| r0 | r243602 | |
| 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
| r0 | r243602 | |
| 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
| r0 | r243602 | |
| 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
| r0 | r243602 | |
| 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
| r0 | r243602 | |
| 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
| r243601 | r243602 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // debugview.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 "debugview.h" |
| 13 | | |
| 14 | | #include "debug/debugcpu.h" |
| 15 | | |
| 16 | | |
| 17 | | static NSColor *DefaultForeground; |
| 18 | | static NSColor *ChangedForeground; |
| 19 | | static NSColor *InvalidForeground; |
| 20 | | static NSColor *CommentForeground; |
| 21 | | static NSColor *DisabledChangedForeground; |
| 22 | | static NSColor *DisabledInvalidForeground; |
| 23 | | static NSColor *DisabledCommentForeground; |
| 24 | | |
| 25 | | static NSColor *DefaultBackground; |
| 26 | | static NSColor *VisitedBackground; |
| 27 | | static NSColor *AncillaryBackground; |
| 28 | | static NSColor *SelectedBackground; |
| 29 | | static NSColor *CurrentBackground; |
| 30 | | static NSColor *SelectedCurrentBackground; |
| 31 | | static NSColor *InactiveSelectedBackground; |
| 32 | | static NSColor *InactiveSelectedCurrentBackground; |
| 33 | | |
| 34 | | |
| 35 | | static void debugwin_view_update(debug_view &view, void *osdprivate) |
| 36 | | { |
| 37 | | [(MAMEDebugView *)osdprivate update]; |
| 38 | | } |
| 39 | | |
| 40 | | |
| 41 | | @implementation MAMEDebugView |
| 42 | | |
| 43 | | + (void)initialize { |
| 44 | | DefaultForeground = [[NSColor colorWithCalibratedWhite:0.0 alpha:1.0] retain]; |
| 45 | | ChangedForeground = [[NSColor colorWithCalibratedRed:0.875 green:0.0 blue:0.0 alpha:1.0] retain]; |
| 46 | | InvalidForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:1.0 alpha:1.0] retain]; |
| 47 | | CommentForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.375 blue:0.0 alpha:1.0] retain]; |
| 48 | | DisabledChangedForeground = [[NSColor colorWithCalibratedRed:0.5 green:0.125 blue:0.125 alpha:1.0] retain]; |
| 49 | | DisabledInvalidForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.5 alpha:1.0] retain]; |
| 50 | | DisabledCommentForeground = [[NSColor colorWithCalibratedRed:0.0 green:0.25 blue:0.0 alpha:1.0] retain]; |
| 51 | | |
| 52 | | DefaultBackground = [[NSColor colorWithCalibratedWhite:1.0 alpha:1.0] retain]; |
| 53 | | VisitedBackground = [[NSColor colorWithCalibratedRed:0.75 green:1.0 blue:0.75 alpha:1.0] retain]; |
| 54 | | AncillaryBackground = [[NSColor colorWithCalibratedWhite:0.75 alpha:1.0] retain]; |
| 55 | | SelectedBackground = [[NSColor colorWithCalibratedRed:0.75 green:0.875 blue:1.0 alpha:1.0] retain]; |
| 56 | | CurrentBackground = [[NSColor colorWithCalibratedRed:1.0 green:0.75 blue:0.75 alpha:1.0] retain]; |
| 57 | | SelectedCurrentBackground = [[NSColor colorWithCalibratedRed:0.875 green:0.625 blue:0.875 alpha:1.0] retain]; |
| 58 | | InactiveSelectedBackground = [[NSColor colorWithCalibratedWhite:0.875 alpha:1.0] retain]; |
| 59 | | InactiveSelectedCurrentBackground = [[NSColor colorWithCalibratedRed:0.875 green:0.5 blue:0.625 alpha:1.0] retain]; |
| 60 | | } |
| 61 | | |
| 62 | | |
| 63 | | - (NSColor *)foregroundForAttribute:(UINT8)attrib { |
| 64 | | if (attrib & DCA_COMMENT) |
| 65 | | return (attrib & DCA_DISABLED) ? DisabledCommentForeground : CommentForeground; |
| 66 | | else if (attrib & DCA_INVALID) |
| 67 | | return (attrib & DCA_DISABLED) ? DisabledInvalidForeground : InvalidForeground; |
| 68 | | else if (attrib & DCA_CHANGED) |
| 69 | | return (attrib & DCA_DISABLED) ? DisabledChangedForeground : ChangedForeground; |
| 70 | | else |
| 71 | | return DefaultForeground; |
| 72 | | } |
| 73 | | |
| 74 | | |
| 75 | | - (NSColor *)backgroundForAttribute:(UINT8)attrib { |
| 76 | | BOOL const active = [[self window] isKeyWindow] && ([[self window] firstResponder] == self); |
| 77 | | if ((attrib & DCA_SELECTED) && (attrib & DCA_CURRENT)) |
| 78 | | return active ? SelectedCurrentBackground : InactiveSelectedCurrentBackground; |
| 79 | | else if (attrib & DCA_CURRENT) |
| 80 | | return CurrentBackground; |
| 81 | | else if (attrib & DCA_SELECTED) |
| 82 | | return active ? SelectedBackground : InactiveSelectedBackground; |
| 83 | | else if (attrib & DCA_ANCILLARY) |
| 84 | | return AncillaryBackground; |
| 85 | | else if (attrib & DCA_VISITED) |
| 86 | | return VisitedBackground; |
| 87 | | else |
| 88 | | return DefaultBackground; |
| 89 | | } |
| 90 | | |
| 91 | | |
| 92 | | - (debug_view_xy)convertLocation:(NSPoint)location { |
| 93 | | debug_view_xy position; |
| 94 | | |
| 95 | | position.y = lround(floor(location.y / fontHeight)); |
| 96 | | if (position.y < 0) |
| 97 | | position.y = 0; |
| 98 | | else if (position.y >= totalHeight) |
| 99 | | position.y = totalHeight - 1; |
| 100 | | |
| 101 | | debug_view_xy const origin = view->visible_position(); |
| 102 | | debug_view_xy const size = view->visible_size(); |
| 103 | | debug_view_char const *data = view->viewdata(); |
| 104 | | if (!data || (position.y < origin.y) || (position.y >= origin.y + size.y)) |
| 105 | | { |
| 106 | | // y coordinate outside visible area, x will be a guess |
| 107 | | position.x = lround(floor((location.x - [textContainer lineFragmentPadding]) / fontWidth)); |
| 108 | | } |
| 109 | | else |
| 110 | | { |
| 111 | | data += ((position.y - view->visible_position().y) * view->visible_size().x); |
| 112 | | int attr = -1; |
| 113 | | NSUInteger start = 0, length = 0; |
| 114 | | for (UINT32 col = origin.x; col < origin.x + size.x; col++) |
| 115 | | { |
| 116 | | [[text mutableString] appendFormat:@"%c", data[col - origin.x].byte]; |
| 117 | | if ((start < length) && (attr != data[col - origin.x].attrib)) |
| 118 | | { |
| 119 | | NSRange const run = NSMakeRange(start, length - start); |
| 120 | | [text addAttribute:NSFontAttributeName |
| 121 | | value:font |
| 122 | | range:NSMakeRange(0, length)]; |
| 123 | | [text addAttribute:NSForegroundColorAttributeName |
| 124 | | value:[self foregroundForAttribute:attr] |
| 125 | | range:run]; |
| 126 | | start = length; |
| 127 | | } |
| 128 | | attr = data[col - origin.x].attrib; |
| 129 | | length = [text length]; |
| 130 | | } |
| 131 | | if (start < length) |
| 132 | | { |
| 133 | | NSRange const run = NSMakeRange(start, length - start); |
| 134 | | [text addAttribute:NSFontAttributeName |
| 135 | | value:font |
| 136 | | range:NSMakeRange(0, length)]; |
| 137 | | [text addAttribute:NSForegroundColorAttributeName |
| 138 | | value:[self foregroundForAttribute:attr] |
| 139 | | range:run]; |
| 140 | | } |
| 141 | | CGFloat fraction; |
| 142 | | NSUInteger const glyph = [layoutManager glyphIndexForPoint:NSMakePoint(location.x, fontHeight / 2) |
| 143 | | inTextContainer:textContainer |
| 144 | | fractionOfDistanceThroughGlyph:&fraction]; |
| 145 | | position.x = [layoutManager characterIndexForGlyphAtIndex:glyph]; // FIXME: assumes 1:1 character mapping |
| 146 | | [text deleteCharactersInRange:NSMakeRange(0, length)]; |
| 147 | | } |
| 148 | | if (position.x < 0) |
| 149 | | position.x = 0; |
| 150 | | else if (position.x >= totalWidth) |
| 151 | | position.x = totalWidth - 1; |
| 152 | | |
| 153 | | return position; |
| 154 | | } |
| 155 | | |
| 156 | | |
| 157 | | - (void)convertBounds:(NSRect)b toFirstAffectedLine:(INT32 *)f count:(INT32 *)c { |
| 158 | | *f = lround(floor(b.origin.y / fontHeight)); |
| 159 | | *c = lround(ceil((b.origin.y + b.size.height) / fontHeight)) - *f; |
| 160 | | } |
| 161 | | |
| 162 | | |
| 163 | | - (void)recomputeVisible { |
| 164 | | if ([self window] != nil) |
| 165 | | { |
| 166 | | // this gets all the lines that are at least partially visible |
| 167 | | debug_view_xy origin(0, 0), size(totalWidth, totalHeight); |
| 168 | | [self convertBounds:[self visibleRect] toFirstAffectedLine:&origin.y count:&size.y]; |
| 169 | | |
| 170 | | // tell them what we think |
| 171 | | view->set_visible_size(size); |
| 172 | | view->set_visible_position(origin); |
| 173 | | originLeft = origin.x; |
| 174 | | originTop = origin.y; |
| 175 | | } |
| 176 | | } |
| 177 | | |
| 178 | | |
| 179 | | - (void)typeCharacterAndScrollToCursor:(char)ch { |
| 180 | | if (view->cursor_supported()) |
| 181 | | { |
| 182 | | debug_view_xy const oldPos = view->cursor_position(); |
| 183 | | view->process_char(ch); |
| 184 | | debug_view_xy const newPos = view->cursor_position(); |
| 185 | | if ((newPos.x != oldPos.x) || (newPos.y != oldPos.y)) |
| 186 | | { |
| 187 | | // FIXME - use proper font metrics |
| 188 | | [self scrollRectToVisible:NSMakeRect((newPos.x * fontWidth) + [textContainer lineFragmentPadding], |
| 189 | | newPos.y * fontHeight, |
| 190 | | fontWidth, |
| 191 | | fontHeight)]; |
| 192 | | } |
| 193 | | } else { |
| 194 | | view->process_char(ch); |
| 195 | | } |
| 196 | | } |
| 197 | | |
| 198 | | |
| 199 | | + (NSFont *)defaultFont { |
| 200 | | return [NSFont userFixedPitchFontOfSize:0]; |
| 201 | | } |
| 202 | | |
| 203 | | |
| 204 | | - (id)initWithFrame:(NSRect)f type:(debug_view_type)t machine:(running_machine &)m { |
| 205 | | if (!(self = [super initWithFrame:f])) |
| 206 | | return nil; |
| 207 | | type = t; |
| 208 | | machine = &m; |
| 209 | | view = machine->debug_view().alloc_view((debug_view_type)type, debugwin_view_update, self); |
| 210 | | if (view == nil) { |
| 211 | | [self release]; |
| 212 | | return nil; |
| 213 | | } |
| 214 | | totalWidth = totalHeight = 0; |
| 215 | | originLeft = originTop = 0; |
| 216 | | |
| 217 | | text = [[NSTextStorage alloc] init]; |
| 218 | | textContainer = [[NSTextContainer alloc] init]; |
| 219 | | layoutManager = [[NSLayoutManager alloc] init]; |
| 220 | | [layoutManager addTextContainer:textContainer]; |
| 221 | | [textContainer release]; |
| 222 | | [text addLayoutManager:layoutManager]; |
| 223 | | [layoutManager release]; |
| 224 | | |
| 225 | | [self setFont:[[self class] defaultFont]]; |
| 226 | | |
| 227 | | return self; |
| 228 | | } |
| 229 | | |
| 230 | | |
| 231 | | - (void)dealloc { |
| 232 | | [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 233 | | if (font != nil) [font release]; |
| 234 | | if (text != nil) [text release]; |
| 235 | | [super dealloc]; |
| 236 | | } |
| 237 | | |
| 238 | | |
| 239 | | - (void)update { |
| 240 | | // resize our frame if the total size has changed |
| 241 | | debug_view_xy const newSize = view->total_size(); |
| 242 | | BOOL const resized = (newSize.x != totalWidth) || (newSize.y != totalHeight); |
| 243 | | if (resized) |
| 244 | | { |
| 245 | | [self setFrameSize:NSMakeSize((fontWidth * newSize.x) + (2 * [textContainer lineFragmentPadding]), |
| 246 | | fontHeight * newSize.y)]; |
| 247 | | totalWidth = newSize.x; |
| 248 | | totalHeight = newSize.y; |
| 249 | | } |
| 250 | | |
| 251 | | // scroll the view if we're being told to |
| 252 | | debug_view_xy const newOrigin = view->visible_position(); |
| 253 | | if (newOrigin.y != originTop) |
| 254 | | { |
| 255 | | [self scrollPoint:NSMakePoint([self visibleRect].origin.x, newOrigin.y * fontHeight)]; |
| 256 | | originTop = newOrigin.y; |
| 257 | | } |
| 258 | | |
| 259 | | // recompute the visible area and mark as dirty |
| 260 | | [self recomputeVisible]; |
| 261 | | [self setNeedsDisplay:YES]; |
| 262 | | } |
| 263 | | |
| 264 | | |
| 265 | | - (NSSize)maximumFrameSize { |
| 266 | | debug_view_xy const max = view->total_size(); |
| 267 | | return NSMakeSize((max.x * fontWidth) + (2 * [textContainer lineFragmentPadding]), |
| 268 | | max.y * fontHeight); |
| 269 | | } |
| 270 | | |
| 271 | | |
| 272 | | - (NSFont *)font { |
| 273 | | return [[font retain] autorelease]; |
| 274 | | } |
| 275 | | |
| 276 | | |
| 277 | | - (void)setFont:(NSFont *)f { |
| 278 | | [font autorelease]; |
| 279 | | font = [f retain]; |
| 280 | | fontWidth = [font maximumAdvancement].width; |
| 281 | | fontHeight = ceil([font ascender] - [font descender]); |
| 282 | | fontAscent = [font ascender]; |
| 283 | | [[self enclosingScrollView] setLineScroll:fontHeight]; |
| 284 | | totalWidth = totalHeight = 0; |
| 285 | | [self update]; |
| 286 | | } |
| 287 | | |
| 288 | | |
| 289 | | - (void)windowDidBecomeKey:(NSNotification *)notification { |
| 290 | | NSWindow *win = [notification object]; |
| 291 | | if ((win == [self window]) && ([win firstResponder] == self) && view->cursor_supported()) |
| 292 | | [self setNeedsDisplay:YES]; |
| 293 | | } |
| 294 | | |
| 295 | | |
| 296 | | - (void)windowDidResignKey:(NSNotification *)notification { |
| 297 | | NSWindow *win = [notification object]; |
| 298 | | if ((win == [self window]) && ([win firstResponder] == self) && view->cursor_supported()) |
| 299 | | [self setNeedsDisplay:YES]; |
| 300 | | } |
| 301 | | |
| 302 | | |
| 303 | | - (BOOL)acceptsFirstResponder { |
| 304 | | return view->cursor_supported(); |
| 305 | | } |
| 306 | | |
| 307 | | |
| 308 | | - (BOOL)becomeFirstResponder { |
| 309 | | if (view->cursor_supported()) { |
| 310 | | debug_view_xy pos; |
| 311 | | view->set_cursor_visible(true); |
| 312 | | pos = view->cursor_position(); |
| 313 | | [self scrollRectToVisible:NSMakeRect((pos.x * fontWidth) + [textContainer lineFragmentPadding], pos.y * fontHeight, fontWidth, fontHeight)]; // FIXME: metrics |
| 314 | | [self setNeedsDisplay:YES]; |
| 315 | | return [super becomeFirstResponder]; |
| 316 | | } else { |
| 317 | | return NO; |
| 318 | | } |
| 319 | | } |
| 320 | | |
| 321 | | |
| 322 | | - (BOOL)resignFirstResponder { |
| 323 | | if (view->cursor_supported()) |
| 324 | | [self setNeedsDisplay:YES]; |
| 325 | | return [super resignFirstResponder]; |
| 326 | | } |
| 327 | | |
| 328 | | |
| 329 | | - (void)viewDidMoveToSuperview { |
| 330 | | [[self enclosingScrollView] setLineScroll:fontHeight]; |
| 331 | | [super viewDidMoveToSuperview]; |
| 332 | | } |
| 333 | | |
| 334 | | |
| 335 | | - (void)viewDidMoveToWindow { |
| 336 | | [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil]; |
| 337 | | [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResignKeyNotification object:nil]; |
| 338 | | if ([self window] != nil) { |
| 339 | | [[NSNotificationCenter defaultCenter] addObserver:self |
| 340 | | selector:@selector(windowDidBecomeKey:) |
| 341 | | name:NSWindowDidBecomeKeyNotification |
| 342 | | object:[self window]]; |
| 343 | | [[NSNotificationCenter defaultCenter] addObserver:self |
| 344 | | selector:@selector(windowDidResignKey:) |
| 345 | | name:NSWindowDidResignKeyNotification |
| 346 | | object:[self window]]; |
| 347 | | [self recomputeVisible]; |
| 348 | | } |
| 349 | | } |
| 350 | | |
| 351 | | |
| 352 | | - (BOOL)isFlipped { |
| 353 | | return YES; |
| 354 | | } |
| 355 | | |
| 356 | | |
| 357 | | - (void)drawRect:(NSRect)dirtyRect { |
| 358 | | INT32 position, clip; |
| 359 | | |
| 360 | | // work out how much we need to draw |
| 361 | | [self recomputeVisible]; |
| 362 | | debug_view_xy const origin = view->visible_position(); |
| 363 | | debug_view_xy const size = view->visible_size(); |
| 364 | | [self convertBounds:dirtyRect toFirstAffectedLine:&position count:&clip]; |
| 365 | | |
| 366 | | // this gets the text for the whole visible area |
| 367 | | debug_view_char const *data = view->viewdata(); |
| 368 | | if (!data) |
| 369 | | return; |
| 370 | | |
| 371 | | data += ((position - origin.y) * size.x); |
| 372 | | for (UINT32 row = position; row < position + clip; row++, data += size.x) |
| 373 | | { |
| 374 | | if ((row < origin.y) || (row >= origin.y + size.y)) |
| 375 | | continue; |
| 376 | | |
| 377 | | // render entire lines to get character alignment right |
| 378 | | int attr = -1; |
| 379 | | NSUInteger start = 0, length = 0; |
| 380 | | for (UINT32 col = origin.x; col < origin.x + size.x; col++) |
| 381 | | { |
| 382 | | [[text mutableString] appendFormat:@"%c", data[col - origin.x].byte]; |
| 383 | | if ((start < length) && (attr != data[col - origin.x].attrib)) |
| 384 | | { |
| 385 | | NSRange const run = NSMakeRange(start, length - start); |
| 386 | | [text addAttribute:NSFontAttributeName |
| 387 | | value:font |
| 388 | | range:NSMakeRange(0, length)]; |
| 389 | | [text addAttribute:NSForegroundColorAttributeName |
| 390 | | value:[self foregroundForAttribute:attr] |
| 391 | | range:run]; |
| 392 | | NSRange const glyphs = [layoutManager glyphRangeForCharacterRange:run |
| 393 | | actualCharacterRange:NULL]; |
| 394 | | NSRect const box = [layoutManager boundingRectForGlyphRange:glyphs |
| 395 | | inTextContainer:textContainer]; |
| 396 | | [[self backgroundForAttribute:attr] set]; |
| 397 | | [NSBezierPath fillRect:NSMakeRect(box.origin.x, |
| 398 | | row * fontHeight, |
| 399 | | box.size.width, |
| 400 | | fontHeight)]; |
| 401 | | start = length; |
| 402 | | } |
| 403 | | attr = data[col - origin.x].attrib; |
| 404 | | length = [text length]; |
| 405 | | } |
| 406 | | if (start < length) |
| 407 | | { |
| 408 | | NSRange const run = NSMakeRange(start, length - start); |
| 409 | | [text addAttribute:NSFontAttributeName |
| 410 | | value:font |
| 411 | | range:NSMakeRange(0, length)]; |
| 412 | | [text addAttribute:NSForegroundColorAttributeName |
| 413 | | value:[self foregroundForAttribute:attr] |
| 414 | | range:run]; |
| 415 | | NSRange const glyphs = [layoutManager glyphRangeForCharacterRange:run |
| 416 | | actualCharacterRange:NULL]; |
| 417 | | NSRect const box = [layoutManager boundingRectForGlyphRange:glyphs |
| 418 | | inTextContainer:textContainer]; |
| 419 | | [[self backgroundForAttribute:attr] set]; |
| 420 | | [NSBezierPath fillRect:NSMakeRect(box.origin.x, |
| 421 | | row * fontHeight, |
| 422 | | box.size.width, |
| 423 | | fontHeight)]; |
| 424 | | } |
| 425 | | [layoutManager drawGlyphsForGlyphRange:[layoutManager glyphRangeForTextContainer:textContainer] |
| 426 | | atPoint:NSMakePoint(0, row * fontHeight)]; |
| 427 | | [text deleteCharactersInRange:NSMakeRange(0, length)]; |
| 428 | | } |
| 429 | | } |
| 430 | | |
| 431 | | |
| 432 | | - (void)mouseDown:(NSEvent *)event { |
| 433 | | NSPoint const location = [self convertPoint:[event locationInWindow] fromView:nil]; |
| 434 | | NSUInteger const modifiers = [event modifierFlags]; |
| 435 | | view->process_click((modifiers & NSCommandKeyMask) ? DCK_RIGHT_CLICK |
| 436 | | : (modifiers & NSAlternateKeyMask) ? DCK_MIDDLE_CLICK |
| 437 | | : DCK_LEFT_CLICK, |
| 438 | | [self convertLocation:location]); |
| 439 | | [self setNeedsDisplay:YES]; |
| 440 | | } |
| 441 | | |
| 442 | | |
| 443 | | - (void)rightMouseDown:(NSEvent *)event { |
| 444 | | NSPoint const location = [self convertPoint:[event locationInWindow] fromView:nil]; |
| 445 | | if (view->cursor_supported()) |
| 446 | | { |
| 447 | | view->set_cursor_position([self convertLocation:location]); |
| 448 | | view->set_cursor_visible(true); |
| 449 | | [self setNeedsDisplay:YES]; |
| 450 | | } |
| 451 | | [super rightMouseDown:event]; |
| 452 | | } |
| 453 | | |
| 454 | | |
| 455 | | - (void)keyDown:(NSEvent *)event { |
| 456 | | NSUInteger modifiers = [event modifierFlags]; |
| 457 | | NSString *str = [event charactersIgnoringModifiers]; |
| 458 | | |
| 459 | | if ([str length] == 1) |
| 460 | | { |
| 461 | | if (modifiers & NSNumericPadKeyMask) |
| 462 | | { |
| 463 | | switch ([str characterAtIndex:0]) |
| 464 | | { |
| 465 | | case NSUpArrowFunctionKey: |
| 466 | | if (modifiers & NSCommandKeyMask) |
| 467 | | view->process_char(DCH_CTRLHOME); |
| 468 | | else |
| 469 | | view->process_char(DCH_UP); |
| 470 | | return; |
| 471 | | case NSDownArrowFunctionKey: |
| 472 | | if (modifiers & NSCommandKeyMask) |
| 473 | | view->process_char(DCH_CTRLEND); |
| 474 | | else |
| 475 | | view->process_char(DCH_DOWN); |
| 476 | | return; |
| 477 | | case NSLeftArrowFunctionKey: |
| 478 | | if (modifiers & NSCommandKeyMask) |
| 479 | | [self typeCharacterAndScrollToCursor:DCH_HOME]; |
| 480 | | else if (modifiers & NSAlternateKeyMask) |
| 481 | | [self typeCharacterAndScrollToCursor:DCH_CTRLLEFT]; |
| 482 | | else |
| 483 | | [self typeCharacterAndScrollToCursor:DCH_LEFT]; |
| 484 | | return; |
| 485 | | case NSRightArrowFunctionKey: |
| 486 | | if (modifiers & NSCommandKeyMask) |
| 487 | | [self typeCharacterAndScrollToCursor:DCH_END]; |
| 488 | | else if (modifiers & NSAlternateKeyMask) |
| 489 | | [self typeCharacterAndScrollToCursor:DCH_CTRLRIGHT]; |
| 490 | | else |
| 491 | | [self typeCharacterAndScrollToCursor:DCH_RIGHT]; |
| 492 | | return; |
| 493 | | default: |
| 494 | | [self interpretKeyEvents:[NSArray arrayWithObject:event]]; |
| 495 | | return; |
| 496 | | } |
| 497 | | } |
| 498 | | else if (modifiers & NSFunctionKeyMask) |
| 499 | | { |
| 500 | | switch ([str characterAtIndex:0]) |
| 501 | | { |
| 502 | | case NSPageUpFunctionKey: |
| 503 | | if (modifiers & NSAlternateKeyMask) |
| 504 | | { |
| 505 | | view->process_char(DCH_PUP); |
| 506 | | return; |
| 507 | | } |
| 508 | | case NSPageDownFunctionKey: |
| 509 | | if (modifiers & NSAlternateKeyMask) |
| 510 | | { |
| 511 | | view->process_char(DCH_PDOWN); |
| 512 | | return; |
| 513 | | } |
| 514 | | default: |
| 515 | | ; |
| 516 | | } |
| 517 | | [super keyDown:event]; |
| 518 | | return; |
| 519 | | } |
| 520 | | } |
| 521 | | [self interpretKeyEvents:[NSArray arrayWithObject:event]]; |
| 522 | | } |
| 523 | | |
| 524 | | |
| 525 | | - (void)insertTab:(id)sender { |
| 526 | | if ([[self window] firstResponder] == self) |
| 527 | | [[self window] selectNextKeyView:self]; |
| 528 | | } |
| 529 | | |
| 530 | | |
| 531 | | - (void)insertBacktab:(id)sender { |
| 532 | | if ([[self window] firstResponder] == self) |
| 533 | | [[self window] selectPreviousKeyView:self]; |
| 534 | | } |
| 535 | | |
| 536 | | |
| 537 | | - (void)insertNewline:(id)sender { |
| 538 | | debug_cpu_get_visible_cpu(*machine)->debug()->single_step(); |
| 539 | | } |
| 540 | | |
| 541 | | |
| 542 | | - (void)insertText:(id)string { |
| 543 | | NSUInteger len; |
| 544 | | NSRange found; |
| 545 | | if ([string isKindOfClass:[NSAttributedString class]]) |
| 546 | | string = [string string]; |
| 547 | | for (len = [string length], found = NSMakeRange(0, 0); |
| 548 | | found.location < len; |
| 549 | | found.location += found.length) { |
| 550 | | found = [string rangeOfComposedCharacterSequenceAtIndex:found.location]; |
| 551 | | if (found.length == 1) { |
| 552 | | unichar ch = [string characterAtIndex:found.location]; |
| 553 | | if ((ch >= 32) && (ch < 127)) |
| 554 | | [self typeCharacterAndScrollToCursor:ch]; |
| 555 | | } |
| 556 | | } |
| 557 | | } |
| 558 | | |
| 559 | | @end |
trunk/src/osd/modules/debugger/osx/debugwindowhandler.m
| r243601 | r243602 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // debugwindowhandler.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 | | NSMenuItem *runParentItem = [menu addItemWithTitle:@"Run" |
| 37 | | action:@selector(debugRun:) |
| 38 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF5FunctionKey]]; |
| 39 | | NSMenu *runMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Run"]; |
| 40 | | [runParentItem setSubmenu:runMenu]; |
| 41 | | [runMenu release]; |
| 42 | | [runParentItem setKeyEquivalentModifierMask:0]; |
| 43 | | [[runMenu addItemWithTitle:@"and Hide Debugger" |
| 44 | | action:@selector(debugRunAndHide:) |
| 45 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF12FunctionKey]] |
| 46 | | setKeyEquivalentModifierMask:0]; |
| 47 | | [[runMenu addItemWithTitle:@"to Next CPU" |
| 48 | | action:@selector(debugRunToNextCPU:) |
| 49 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF6FunctionKey]] |
| 50 | | setKeyEquivalentModifierMask:0]; |
| 51 | | [[runMenu addItemWithTitle:@"until Next Interrupt on Current CPU" |
| 52 | | action:@selector(debugRunToNextInterrupt:) |
| 53 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF7FunctionKey]] |
| 54 | | setKeyEquivalentModifierMask:0]; |
| 55 | | [[runMenu addItemWithTitle:@"until Next VBLANK" |
| 56 | | action:@selector(debugRunToNextVBLANK:) |
| 57 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF8FunctionKey]] |
| 58 | | setKeyEquivalentModifierMask:0]; |
| 59 | | |
| 60 | | NSMenuItem *stepParentItem = [menu addItemWithTitle:@"Step" action:NULL keyEquivalent:@""]; |
| 61 | | NSMenu *stepMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Step"]; |
| 62 | | [stepParentItem setSubmenu:stepMenu]; |
| 63 | | [stepMenu release]; |
| 64 | | [[stepMenu addItemWithTitle:@"Into" |
| 65 | | action:@selector(debugStepInto:) |
| 66 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF11FunctionKey]] |
| 67 | | setKeyEquivalentModifierMask:0]; |
| 68 | | [[stepMenu addItemWithTitle:@"Over" |
| 69 | | action:@selector(debugStepOver:) |
| 70 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF10FunctionKey]] |
| 71 | | setKeyEquivalentModifierMask:0]; |
| 72 | | [[stepMenu addItemWithTitle:@"Out" |
| 73 | | action:@selector(debugStepOut:) |
| 74 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF10FunctionKey]] |
| 75 | | setKeyEquivalentModifierMask:NSShiftKeyMask]; |
| 76 | | |
| 77 | | NSMenuItem *resetParentItem = [menu addItemWithTitle:@"Reset" action:NULL keyEquivalent:@""]; |
| 78 | | NSMenu *resetMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Reset"]; |
| 79 | | [resetParentItem setSubmenu:resetMenu]; |
| 80 | | [resetMenu release]; |
| 81 | | [[resetMenu addItemWithTitle:@"Soft" |
| 82 | | action:@selector(debugSoftReset:) |
| 83 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF3FunctionKey]] |
| 84 | | setKeyEquivalentModifierMask:0]; |
| 85 | | [[resetMenu addItemWithTitle:@"Hard" |
| 86 | | action:@selector(debugHardReset:) |
| 87 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF3FunctionKey]] |
| 88 | | setKeyEquivalentModifierMask:NSShiftKeyMask]; |
| 89 | | |
| 90 | | [menu addItem:[NSMenuItem separatorItem]]; |
| 91 | | |
| 92 | | NSMenuItem *newParentItem = [menu addItemWithTitle:@"New" action:NULL keyEquivalent:@""]; |
| 93 | | NSMenu *newMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"New"]; |
| 94 | | [newParentItem setSubmenu:newMenu]; |
| 95 | | [newMenu release]; |
| 96 | | [newMenu addItemWithTitle:@"Memory Window" |
| 97 | | action:@selector(debugNewMemoryWindow:) |
| 98 | | keyEquivalent:@"d"]; |
| 99 | | [newMenu addItemWithTitle:@"Disassembly Window" |
| 100 | | action:@selector(debugNewDisassemblyWindow:) |
| 101 | | keyEquivalent:@"a"]; |
| 102 | | [newMenu addItemWithTitle:@"Error Log Window" |
| 103 | | action:@selector(debugNewErrorLogWindow:) |
| 104 | | keyEquivalent:@"l"]; |
| 105 | | [newMenu addItemWithTitle:@"(Break|Watch)points Window" |
| 106 | | action:@selector(debugNewPointsWindow:) |
| 107 | | keyEquivalent:@"b"]; |
| 108 | | [newMenu addItemWithTitle:@"Devices Window" |
| 109 | | action:@selector(debugNewDevicesWindow:) |
| 110 | | keyEquivalent:@"D"]; |
| 111 | | |
| 112 | | [menu addItem:[NSMenuItem separatorItem]]; |
| 113 | | |
| 114 | | [menu addItemWithTitle:@"Close Window" action:@selector(performClose:) keyEquivalent:@"w"]; |
| 115 | | [menu addItemWithTitle:@"Quit" action:@selector(debugExit:) keyEquivalent:@"q"]; |
| 116 | | } |
| 117 | | |
| 118 | | |
| 119 | | + (NSPopUpButton *)newActionButtonWithFrame:(NSRect)frame { |
| 120 | | NSPopUpButton *actionButton = [[NSPopUpButton alloc] initWithFrame:frame pullsDown:YES]; |
| 121 | | [actionButton setTitle:@""]; |
| 122 | | [actionButton addItemWithTitle:@""]; |
| 123 | | [actionButton setBezelStyle:NSShadowlessSquareBezelStyle]; |
| 124 | | [actionButton setFocusRingType:NSFocusRingTypeNone]; |
| 125 | | [[actionButton cell] setArrowPosition:NSPopUpArrowAtCenter]; |
| 126 | | [[self class] addCommonActionItems:[actionButton menu]]; |
| 127 | | return actionButton; |
| 128 | | } |
| 129 | | |
| 130 | | |
| 131 | | - (id)initWithMachine:(running_machine &)m title:(NSString *)t { |
| 132 | | if (!(self = [super init])) |
| 133 | | return nil; |
| 134 | | |
| 135 | | window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 320, 240) |
| 136 | | styleMask:(NSTitledWindowMask | |
| 137 | | NSClosableWindowMask | |
| 138 | | NSMiniaturizableWindowMask | |
| 139 | | NSResizableWindowMask) |
| 140 | | backing:NSBackingStoreBuffered |
| 141 | | defer:YES]; |
| 142 | | [window setReleasedWhenClosed:NO]; |
| 143 | | [window setDelegate:self]; |
| 144 | | [window setTitle:t]; |
| 145 | | [window setContentMinSize:NSMakeSize(320, 240)]; |
| 146 | | |
| 147 | | [[NSNotificationCenter defaultCenter] addObserver:self |
| 148 | | selector:@selector(showDebugger:) |
| 149 | | name:MAMEShowDebuggerNotification |
| 150 | | object:nil]; |
| 151 | | [[NSNotificationCenter defaultCenter] addObserver:self |
| 152 | | selector:@selector(hideDebugger:) |
| 153 | | name:MAMEHideDebuggerNotification |
| 154 | | object:nil]; |
| 155 | | |
| 156 | | machine = &m; |
| 157 | | |
| 158 | | return self; |
| 159 | | } |
| 160 | | |
| 161 | | |
| 162 | | - (void)dealloc { |
| 163 | | [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 164 | | |
| 165 | | if (window != nil) |
| 166 | | [window release]; |
| 167 | | |
| 168 | | [super dealloc]; |
| 169 | | } |
| 170 | | |
| 171 | | |
| 172 | | - (void)activate { |
| 173 | | [window makeKeyAndOrderFront:self]; |
| 174 | | } |
| 175 | | |
| 176 | | |
| 177 | | - (IBAction)debugRun:(id)sender { |
| 178 | | debug_cpu_get_visible_cpu(*machine)->debug()->go(); |
| 179 | | } |
| 180 | | |
| 181 | | |
| 182 | | - (IBAction)debugRunAndHide:(id)sender { |
| 183 | | [[NSNotificationCenter defaultCenter] postNotificationName:MAMEHideDebuggerNotification object:self]; |
| 184 | | debug_cpu_get_visible_cpu(*machine)->debug()->go(); |
| 185 | | } |
| 186 | | |
| 187 | | |
| 188 | | - (IBAction)debugRunToNextCPU:(id)sender { |
| 189 | | debug_cpu_get_visible_cpu(*machine)->debug()->go_next_device(); |
| 190 | | } |
| 191 | | |
| 192 | | |
| 193 | | - (IBAction)debugRunToNextInterrupt:(id)sender { |
| 194 | | debug_cpu_get_visible_cpu(*machine)->debug()->go_interrupt(); |
| 195 | | } |
| 196 | | |
| 197 | | |
| 198 | | - (IBAction)debugRunToNextVBLANK:(id)sender { |
| 199 | | debug_cpu_get_visible_cpu(*machine)->debug()->go_vblank(); |
| 200 | | } |
| 201 | | |
| 202 | | |
| 203 | | - (IBAction)debugStepInto:(id)sender { |
| 204 | | debug_cpu_get_visible_cpu(*machine)->debug()->single_step(); |
| 205 | | } |
| 206 | | |
| 207 | | |
| 208 | | - (IBAction)debugStepOver:(id)sender { |
| 209 | | debug_cpu_get_visible_cpu(*machine)->debug()->single_step_over(); |
| 210 | | } |
| 211 | | |
| 212 | | |
| 213 | | - (IBAction)debugStepOut:(id)sender { |
| 214 | | debug_cpu_get_visible_cpu(*machine)->debug()->single_step_out(); |
| 215 | | } |
| 216 | | |
| 217 | | |
| 218 | | - (IBAction)debugSoftReset:(id)sender { |
| 219 | | machine->schedule_soft_reset(); |
| 220 | | debug_cpu_get_visible_cpu(*machine)->debug()->go(); |
| 221 | | } |
| 222 | | |
| 223 | | |
| 224 | | - (IBAction)debugHardReset:(id)sender { |
| 225 | | machine->schedule_hard_reset(); |
| 226 | | } |
| 227 | | |
| 228 | | |
| 229 | | - (IBAction)debugExit:(id)sender { |
| 230 | | machine->schedule_exit(); |
| 231 | | } |
| 232 | | |
| 233 | | |
| 234 | | - (void)showDebugger:(NSNotification *)notification { |
| 235 | | running_machine *m = (running_machine *)[[[notification userInfo] objectForKey:@"MAMEDebugMachine"] pointerValue]; |
| 236 | | if (m == machine) |
| 237 | | { |
| 238 | | if (![window isVisible] && ![window isMiniaturized]) |
| 239 | | [window orderFront:self]; |
| 240 | | } |
| 241 | | } |
| 242 | | |
| 243 | | |
| 244 | | - (void)hideDebugger:(NSNotification *)notification { |
| 245 | | running_machine *m = (running_machine *)[[[notification userInfo] objectForKey:@"MAMEDebugMachine"] pointerValue]; |
| 246 | | if (m == machine) |
| 247 | | [window orderOut:self]; |
| 248 | | } |
| 249 | | |
| 250 | | @end |
| 251 | | |
| 252 | | |
| 253 | | //============================================================ |
| 254 | | // MAMEAuxiliaryDebugWindowHandler class |
| 255 | | //============================================================ |
| 256 | | |
| 257 | | @implementation MAMEAuxiliaryDebugWindowHandler |
| 258 | | |
| 259 | | + (void)cascadeWindow:(NSWindow *)window { |
| 260 | | static NSPoint lastPosition = { 0, 0 }; |
| 261 | | if (NSEqualPoints(lastPosition, NSZeroPoint)) { |
| 262 | | NSRect available = [[NSScreen mainScreen] visibleFrame]; |
| 263 | | lastPosition = NSMakePoint(available.origin.x + 12, available.origin.y + available.size.height - 8); |
| 264 | | } |
| 265 | | lastPosition = [window cascadeTopLeftFromPoint:lastPosition]; |
| 266 | | } |
| 267 | | |
| 268 | | |
| 269 | | - (id)initWithMachine:(running_machine &)m title:(NSString *)t console:(MAMEDebugConsole *)c { |
| 270 | | if (!(self = [super initWithMachine:m title:t])) |
| 271 | | return nil; |
| 272 | | console = c; |
| 273 | | return self; |
| 274 | | } |
| 275 | | |
| 276 | | |
| 277 | | - (void)dealloc { |
| 278 | | [super dealloc]; |
| 279 | | } |
| 280 | | |
| 281 | | |
| 282 | | - (IBAction)debugNewMemoryWindow:(id)sender { |
| 283 | | [console debugNewMemoryWindow:sender]; |
| 284 | | } |
| 285 | | |
| 286 | | |
| 287 | | - (IBAction)debugNewDisassemblyWindow:(id)sender { |
| 288 | | [console debugNewDisassemblyWindow:sender]; |
| 289 | | } |
| 290 | | |
| 291 | | |
| 292 | | - (IBAction)debugNewErrorLogWindow:(id)sender { |
| 293 | | [console debugNewErrorLogWindow:sender]; |
| 294 | | } |
| 295 | | |
| 296 | | |
| 297 | | - (IBAction)debugNewPointsWindow:(id)sender { |
| 298 | | [console debugNewPointsWindow:sender]; |
| 299 | | } |
| 300 | | |
| 301 | | |
| 302 | | - (IBAction)debugNewDevicesWindow:(id)sender { |
| 303 | | [console debugNewDevicesWindow:sender]; |
| 304 | | } |
| 305 | | |
| 306 | | |
| 307 | | - (void)windowWillClose:(NSNotification *)notification { |
| 308 | | [[NSNotificationCenter defaultCenter] postNotificationName:MAMEAuxiliaryDebugWindowWillCloseNotification |
| 309 | | object:self]; |
| 310 | | } |
| 311 | | |
| 312 | | - (void)cascadeWindowWithDesiredSize:(NSSize)desired forView:(NSView *)view { |
| 313 | | NSRect available = [[NSScreen mainScreen] visibleFrame]; |
| 314 | | NSRect windowFrame = [window frame]; |
| 315 | | NSSize current = [view frame].size; |
| 316 | | |
| 317 | | desired.width -= current.width; |
| 318 | | desired.height -= current.height; |
| 319 | | |
| 320 | | windowFrame.size.width += desired.width; |
| 321 | | windowFrame.size.width = MIN(windowFrame.size.width, available.size.width); |
| 322 | | windowFrame.size.height += desired.height; |
| 323 | | windowFrame.size.height = MIN(MIN(windowFrame.size.height, 320), available.size.height); |
| 324 | | windowFrame.origin.x = available.origin.x + available.size.width - windowFrame.size.width; |
| 325 | | windowFrame.origin.y = available.origin.y; |
| 326 | | [window setFrame:windowFrame display:YES]; |
| 327 | | [[self class] cascadeWindow:window]; |
| 328 | | |
| 329 | | windowFrame = [[window contentView] frame]; |
| 330 | | desired = [window contentMinSize]; |
| 331 | | [window setContentMinSize:NSMakeSize(MIN(windowFrame.size.width, desired.width), |
| 332 | | MIN(windowFrame.size.height, desired.height))]; |
| 333 | | } |
| 334 | | |
| 335 | | @end |
| 336 | | |
| 337 | | |
| 338 | | //============================================================ |
| 339 | | // MAMEExpreesionAuxiliaryDebugWindowHandler class |
| 340 | | //============================================================ |
| 341 | | |
| 342 | | @implementation MAMEExpressionAuxiliaryDebugWindowHandler |
| 343 | | |
| 344 | | - (id)initWithMachine:(running_machine &)m title:(NSString *)t console:(MAMEDebugConsole *)c { |
| 345 | | if (!(self = [super initWithMachine:m title:t console:c])) |
| 346 | | return nil; |
| 347 | | history = [[MAMEDebugCommandHistory alloc] init]; |
| 348 | | return self; |
| 349 | | } |
| 350 | | |
| 351 | | |
| 352 | | - (void)dealloc { |
| 353 | | if (history != nil) |
| 354 | | [history release]; |
| 355 | | [super dealloc]; |
| 356 | | } |
| 357 | | |
| 358 | | |
| 359 | | - (id <MAMEDebugViewExpressionSupport>)documentView { |
| 360 | | return nil; |
| 361 | | } |
| 362 | | |
| 363 | | |
| 364 | | - (NSString *)expression { |
| 365 | | return [[self documentView] expression]; |
| 366 | | } |
| 367 | | |
| 368 | | - (void)setExpression:(NSString *)expression { |
| 369 | | [history add:expression]; |
| 370 | | [[self documentView] setExpression:expression]; |
| 371 | | [expressionField setStringValue:expression]; |
| 372 | | [expressionField selectText:self]; |
| 373 | | } |
| 374 | | |
| 375 | | |
| 376 | | - (IBAction)doExpression:(id)sender { |
| 377 | | NSString *expr = [sender stringValue]; |
| 378 | | if ([expr length] > 0) { |
| 379 | | [history add:expr]; |
| 380 | | [[self documentView] setExpression:expr]; |
| 381 | | } else { |
| 382 | | [sender setStringValue:[[self documentView] expression]]; |
| 383 | | [history reset]; |
| 384 | | } |
| 385 | | [sender selectText:self]; |
| 386 | | } |
| 387 | | |
| 388 | | |
| 389 | | - (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor |
| 390 | | { |
| 391 | | if (control == expressionField) |
| 392 | | [history edit]; |
| 393 | | |
| 394 | | return YES; |
| 395 | | } |
| 396 | | |
| 397 | | |
| 398 | | - (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command { |
| 399 | | if (control == expressionField) { |
| 400 | | if (command == @selector(cancelOperation:)) { |
| 401 | | [history reset]; |
| 402 | | [expressionField setStringValue:[[self documentView] expression]]; |
| 403 | | [expressionField selectText:self]; |
| 404 | | return YES; |
| 405 | | } else if (command == @selector(moveUp:)) { |
| 406 | | NSString *hist = [history previous:[expressionField stringValue]]; |
| 407 | | if (hist != nil) { |
| 408 | | [expressionField setStringValue:hist]; |
| 409 | | [expressionField selectText:self]; |
| 410 | | } |
| 411 | | return YES; |
| 412 | | } else if (command == @selector(moveDown:)) { |
| 413 | | NSString *hist = [history next:[expressionField stringValue]]; |
| 414 | | if (hist != nil) { |
| 415 | | [expressionField setStringValue:hist]; |
| 416 | | [expressionField selectText:self]; |
| 417 | | } |
| 418 | | return YES; |
| 419 | | } |
| 420 | | } |
| 421 | | return NO; |
| 422 | | } |
| 423 | | |
| 424 | | @end |
| | No newline at end of file |
trunk/src/osd/modules/debugger/osx/devicesviewer.m
| r243601 | r243602 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // devicesviewer.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 "devicesviewer.h" |
| 13 | | |
| 14 | | |
| 15 | | @interface MAMEDeviceWrapper : NSObject |
| 16 | | { |
| 17 | | running_machine *machine; |
| 18 | | device_t *device; |
| 19 | | NSArray *children; |
| 20 | | } |
| 21 | | |
| 22 | | - (id)initWithMachine:(running_machine &)m device:(device_t &)d; |
| 23 | | |
| 24 | | - (running_machine &)machine; |
| 25 | | - (device_t &)device; |
| 26 | | - (NSString *)tag; |
| 27 | | - (NSString *)name; |
| 28 | | - (NSUInteger)children; |
| 29 | | - (MAMEDeviceWrapper *)childAtIndex:(NSUInteger)index; |
| 30 | | |
| 31 | | @end |
| 32 | | |
| 33 | | |
| 34 | | @implementation MAMEDeviceWrapper |
| 35 | | |
| 36 | | - (void)wrapChildren { |
| 37 | | NSMutableArray *const tmp = [[NSMutableArray alloc] init]; |
| 38 | | for (device_t *child = device->first_subdevice(); child != NULL; child = child->next()) |
| 39 | | { |
| 40 | | MAMEDeviceWrapper *const wrap = [[MAMEDeviceWrapper alloc] initWithMachine:*machine |
| 41 | | device:*child]; |
| 42 | | [tmp addObject:wrap]; |
| 43 | | [wrap release]; |
| 44 | | } |
| 45 | | children = [[NSArray alloc] initWithArray:tmp]; |
| 46 | | [tmp release]; |
| 47 | | } |
| 48 | | |
| 49 | | |
| 50 | | - (id)initWithMachine:(running_machine &)m device:(device_t &)d { |
| 51 | | if (!(self = [super init])) |
| 52 | | return nil; |
| 53 | | machine = &m; |
| 54 | | device = &d; |
| 55 | | children = nil; |
| 56 | | return self; |
| 57 | | } |
| 58 | | |
| 59 | | |
| 60 | | - (void)dealloc { |
| 61 | | if (children != nil) |
| 62 | | [children release]; |
| 63 | | [super dealloc]; |
| 64 | | } |
| 65 | | |
| 66 | | |
| 67 | | - (running_machine &)machine { |
| 68 | | return *machine; |
| 69 | | } |
| 70 | | |
| 71 | | |
| 72 | | - (device_t &)device { |
| 73 | | return *device; |
| 74 | | } |
| 75 | | |
| 76 | | |
| 77 | | - (NSString *)tag { |
| 78 | | return (device == &machine->root_device()) ? @"<root>" |
| 79 | | : [NSString stringWithUTF8String:device->basetag()]; |
| 80 | | } |
| 81 | | |
| 82 | | |
| 83 | | - (NSString *)name { |
| 84 | | return [NSString stringWithUTF8String:device->name()]; |
| 85 | | } |
| 86 | | |
| 87 | | |
| 88 | | - (NSUInteger)children { |
| 89 | | if (children == nil) |
| 90 | | [self wrapChildren]; |
| 91 | | return [children count]; |
| 92 | | } |
| 93 | | |
| 94 | | |
| 95 | | - (MAMEDeviceWrapper *)childAtIndex:(NSUInteger)index { |
| 96 | | if (children == nil) |
| 97 | | [self wrapChildren]; |
| 98 | | return (index < [children count]) ? [children objectAtIndex:index] : nil; |
| 99 | | } |
| 100 | | |
| 101 | | @end |
| 102 | | |
| 103 | | |
| 104 | | @implementation MAMEDevicesViewer |
| 105 | | |
| 106 | | - (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c { |
| 107 | | NSScrollView *devicesScroll; |
| 108 | | NSTableColumn *tagColumn, *nameColumn; |
| 109 | | |
| 110 | | if (!(self = [super initWithMachine:m title:@"All Devices" console:c])) |
| 111 | | return nil; |
| 112 | | root = [[MAMEDeviceWrapper alloc] initWithMachine:m device:m.root_device()]; |
| 113 | | |
| 114 | | // create the devices view |
| 115 | | devicesView = [[NSOutlineView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100)]; |
| 116 | | [devicesView setUsesAlternatingRowBackgroundColors:YES]; |
| 117 | | [devicesView setAllowsColumnReordering:YES]; |
| 118 | | [devicesView setAllowsColumnResizing:YES]; |
| 119 | | [devicesView setColumnAutoresizingStyle:NSTableViewUniformColumnAutoresizingStyle]; |
| 120 | | [devicesView setAllowsEmptySelection:YES]; |
| 121 | | [devicesView setAllowsMultipleSelection:NO]; |
| 122 | | [devicesView setAllowsColumnSelection:NO]; |
| 123 | | tagColumn = [[NSTableColumn alloc] initWithIdentifier:@"tag"]; |
| 124 | | [[tagColumn headerCell] setStringValue:@"Tag"]; |
| 125 | | [tagColumn setEditable:NO]; |
| 126 | | [tagColumn setMinWidth:100]; |
| 127 | | [tagColumn setWidth:120]; |
| 128 | | [tagColumn setResizingMask:(NSTableColumnAutoresizingMask | NSTableColumnUserResizingMask)]; |
| 129 | | [devicesView addTableColumn:tagColumn]; |
| 130 | | [tagColumn release]; |
| 131 | | nameColumn = [[NSTableColumn alloc] initWithIdentifier:@"name"]; |
| 132 | | [[nameColumn headerCell] setStringValue:@"Name"]; |
| 133 | | [nameColumn setEditable:NO]; |
| 134 | | [nameColumn setMinWidth:100]; |
| 135 | | [nameColumn setMinWidth:360]; |
| 136 | | [nameColumn setResizingMask:(NSTableColumnAutoresizingMask | NSTableColumnUserResizingMask)]; |
| 137 | | [devicesView addTableColumn:nameColumn]; |
| 138 | | [nameColumn release]; |
| 139 | | [devicesView setOutlineTableColumn:tagColumn]; |
| 140 | | [devicesView setAutoresizesOutlineColumn:YES]; |
| 141 | | [devicesView setDataSource:self]; |
| 142 | | devicesScroll = [[NSScrollView alloc] initWithFrame:[[window contentView] bounds]]; |
| 143 | | [devicesScroll setDrawsBackground:YES]; |
| 144 | | [devicesScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 145 | | [devicesScroll setHasHorizontalScroller:YES]; |
| 146 | | [devicesScroll setHasVerticalScroller:YES]; |
| 147 | | [devicesScroll setAutohidesScrollers:YES]; |
| 148 | | [devicesScroll setBorderType:NSNoBorder]; |
| 149 | | [devicesScroll setDocumentView:devicesView]; |
| 150 | | [devicesView release]; |
| 151 | | [[window contentView] addSubview:devicesScroll]; |
| 152 | | [devicesScroll release]; |
| 153 | | |
| 154 | | // set default state |
| 155 | | [devicesView expandItem:root expandChildren:YES]; |
| 156 | | [window makeFirstResponder:devicesView]; |
| 157 | | [window setTitle:[NSString stringWithFormat:@"All Devices"]]; |
| 158 | | |
| 159 | | // calculate the optimal size for everything |
| 160 | | NSSize const desired = [NSScrollView frameSizeForContentSize:NSMakeSize(480, 320) |
| 161 | | hasHorizontalScroller:YES |
| 162 | | hasVerticalScroller:YES |
| 163 | | borderType:[devicesScroll borderType]]; |
| 164 | | [self cascadeWindowWithDesiredSize:desired forView:devicesScroll]; |
| 165 | | |
| 166 | | // don't forget the result |
| 167 | | return self; |
| 168 | | } |
| 169 | | |
| 170 | | |
| 171 | | - (void)dealloc { |
| 172 | | if (root != nil) |
| 173 | | [root release]; |
| 174 | | [super dealloc]; |
| 175 | | } |
| 176 | | |
| 177 | | |
| 178 | | - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item { |
| 179 | | return [(MAMEDeviceWrapper *)item children] > 0; |
| 180 | | } |
| 181 | | |
| 182 | | |
| 183 | | - (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item { |
| 184 | | if (item != nil) |
| 185 | | return [(MAMEDeviceWrapper *)item children]; |
| 186 | | else |
| 187 | | return 1; |
| 188 | | } |
| 189 | | |
| 190 | | |
| 191 | | - (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item { |
| 192 | | if (item != nil) |
| 193 | | return [(MAMEDeviceWrapper *)item childAtIndex:index]; |
| 194 | | else if (index == 0) |
| 195 | | return root; |
| 196 | | else |
| 197 | | return nil; |
| 198 | | } |
| 199 | | |
| 200 | | |
| 201 | | - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { |
| 202 | | if ([[tableColumn identifier] isEqualToString:@"tag"]) |
| 203 | | return [(MAMEDeviceWrapper *)item tag]; |
| 204 | | else if ([[tableColumn identifier] isEqualToString:@"name"]) |
| 205 | | return [(MAMEDeviceWrapper *)item name]; |
| 206 | | else |
| 207 | | return nil; |
| 208 | | } |
| 209 | | |
| 210 | | @end |
trunk/src/osd/modules/debugger/osx/disassemblyview.m
| r243601 | r243602 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // disassemblyview.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 "debugger.h" |
| 15 | | #include "debug/debugcon.h" |
| 16 | | #include "debug/debugcpu.h" |
| 17 | | #include "debug/debugvw.h" |
| 18 | | |
| 19 | | |
| 20 | | @implementation MAMEDisassemblyView |
| 21 | | |
| 22 | | - (device_debug::breakpoint *)findBreakpointAtAddress:(offs_t)address forDevice:(device_t &)device { |
| 23 | | device_debug *cpuinfo = 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 const action = [item action]; |
| 94 | | BOOL const inContextMenu = ([item menu] == [self menu]); |
| 95 | | BOOL haveCursor = view->cursor_visible(); |
| 96 | | BOOL const isCurrent = (debug_cpu_get_visible_cpu(*machine) == view->source()->device()); |
| 97 | | |
| 98 | | device_debug::breakpoint *breakpoint = NULL; |
| 99 | | if (haveCursor) |
| 100 | | { |
| 101 | | offs_t const address = downcast<debug_view_disasm *>(view)->selected_address(); |
| 102 | | breakpoint = [self findBreakpointAtAddress:address forDevice:[self source]->device()]; |
| 103 | | } |
| 104 | | |
| 105 | | if (action == @selector(debugToggleBreakpoint:)) |
| 106 | | { |
| 107 | | if (haveCursor) |
| 108 | | { |
| 109 | | if (breakpoint != NULL) |
| 110 | | { |
| 111 | | if (inContextMenu) |
| 112 | | [item setTitle:@"Clear Breakpoint"]; |
| 113 | | else |
| 114 | | [item setTitle:@"Clear Breakpoint at Cursor"]; |
| 115 | | } |
| 116 | | else |
| 117 | | { |
| 118 | | if (inContextMenu) |
| 119 | | [item setTitle:@"Set Breakpoint"]; |
| 120 | | else |
| 121 | | [item setTitle:@"Set Breakpoint at Cursor"]; |
| 122 | | } |
| 123 | | } |
| 124 | | else |
| 125 | | { |
| 126 | | if (inContextMenu) |
| 127 | | [item setTitle:@"Toggle Breakpoint"]; |
| 128 | | else |
| 129 | | [item setTitle:@"Toggle Breakpoint at Cursor"]; |
| 130 | | } |
| 131 | | return haveCursor && (!useConsole || isCurrent); |
| 132 | | } |
| 133 | | else if (action == @selector(debugToggleBreakpointEnable:)) |
| 134 | | { |
| 135 | | if ((breakpoint != NULL) && !breakpoint->enabled()) |
| 136 | | { |
| 137 | | if (inContextMenu) |
| 138 | | [item setTitle:@"Enable Breakpoint"]; |
| 139 | | else |
| 140 | | [item setTitle:@"Enable Breakpoint at Cursor"]; |
| 141 | | } |
| 142 | | else |
| 143 | | { |
| 144 | | if (inContextMenu) |
| 145 | | [item setTitle:@"Disable Breakpoint"]; |
| 146 | | else |
| 147 | | [item setTitle:@"Disable Breakpoint at Cursor"]; |
| 148 | | } |
| 149 | | return (breakpoint != NULL) && (!useConsole || isCurrent); |
| 150 | | } |
| 151 | | else if (action == @selector(debugRunToCursor:)) |
| 152 | | { |
| 153 | | return !useConsole || isCurrent; |
| 154 | | } |
| 155 | | else if (action == @selector(showRightColumn:)) |
| 156 | | { |
| 157 | | [item setState:((downcast<debug_view_disasm *>(view)->right_column() == [item tag]) ? NSOnState : NSOffState)]; |
| 158 | | return YES; |
| 159 | | } |
| 160 | | else |
| 161 | | { |
| 162 | | return YES; |
| 163 | | } |
| 164 | | } |
| 165 | | |
| 166 | | |
| 167 | | - (NSSize)maximumFrameSize { |
| 168 | | debug_view_xy max(0, 0); |
| 169 | | const debug_view_source *source = view->source(); |
| 170 | | |
| 171 | | for (const debug_view_source *source = view->source_list().first(); source != NULL; source = source->next()) |
| 172 | | { |
| 173 | | debug_view_xy current; |
| 174 | | view->set_source(*source); |
| 175 | | current = view->total_size(); |
| 176 | | if (current.x > max.x) |
| 177 | | max.x = current.x; |
| 178 | | if (current.y > max.y) |
| 179 | | max.y = current.y; |
| 180 | | } |
| 181 | | view->set_source(*source); |
| 182 | | return NSMakeSize(max.x * fontWidth, max.y * fontHeight); |
| 183 | | } |
| 184 | | |
| 185 | | |
| 186 | | - (NSString *)selectedSubviewName { |
| 187 | | const debug_view_source *source = view->source(); |
| 188 | | if (source != NULL) |
| 189 | | return [NSString stringWithUTF8String:source->name()]; |
| 190 | | else |
| 191 | | return @""; |
| 192 | | } |
| 193 | | |
| 194 | | |
| 195 | | - (int)selectedSubviewIndex { |
| 196 | | const debug_view_source *source = view->source(); |
| 197 | | if (source != NULL) |
| 198 | | return view->source_list().indexof(*source); |
| 199 | | else |
| 200 | | return -1; |
| 201 | | } |
| 202 | | |
| 203 | | |
| 204 | | - (void)selectSubviewAtIndex:(int)index { |
| 205 | | const int selected = view->source_list().indexof(*view->source()); |
| 206 | | if (selected != index) { |
| 207 | | view->set_source(*view->source_list().find(index)); |
| 208 | | if ([[self window] firstResponder] != self) |
| 209 | | view->set_cursor_visible(false); |
| 210 | | } |
| 211 | | } |
| 212 | | |
| 213 | | |
| 214 | | - (BOOL)selectSubviewForDevice:(device_t *)device { |
| 215 | | debug_view_source const *const source = view->source_for_device(device); |
| 216 | | if (source != NULL) |
| 217 | | { |
| 218 | | if (view->source() != source) |
| 219 | | { |
| 220 | | view->set_source(*source); |
| 221 | | if ([[self window] firstResponder] != self) |
| 222 | | view->set_cursor_visible(false); |
| 223 | | } |
| 224 | | return YES; |
| 225 | | } |
| 226 | | else |
| 227 | | { |
| 228 | | return NO; |
| 229 | | } |
| 230 | | } |
| 231 | | |
| 232 | | |
| 233 | | - (BOOL)selectSubviewForSpace:(address_space *)space { |
| 234 | | if (space == NULL) return NO; |
| 235 | | debug_view_disasm_source const *source = downcast<debug_view_disasm_source const *>(view->first_source()); |
| 236 | | while ((source != NULL) && (&source->space() != space)) |
| 237 | | source = downcast<debug_view_disasm_source *>(source->next()); |
| 238 | | if (source != NULL) |
| 239 | | { |
| 240 | | if (view->source() != source) |
| 241 | | { |
| 242 | | view->set_source(*source); |
| 243 | | if ([[self window] firstResponder] != self) |
| 244 | | view->set_cursor_visible(false); |
| 245 | | } |
| 246 | | return YES; |
| 247 | | } |
| 248 | | else |
| 249 | | { |
| 250 | | return NO; |
| 251 | | } |
| 252 | | } |
| 253 | | |
| 254 | | |
| 255 | | - (NSString *)expression { |
| 256 | | return [NSString stringWithUTF8String:downcast<debug_view_disasm *>(view)->expression()]; |
| 257 | | } |
| 258 | | |
| 259 | | |
| 260 | | - (void)setExpression:(NSString *)exp { |
| 261 | | downcast<debug_view_disasm *>(view)->set_expression([exp UTF8String]); |
| 262 | | } |
| 263 | | |
| 264 | | |
| 265 | | - (debug_view_disasm_source const *)source { |
| 266 | | return downcast<debug_view_disasm_source const *>(view->source()); |
| 267 | | } |
| 268 | | |
| 269 | | |
| 270 | | - (IBAction)debugToggleBreakpoint:(id)sender { |
| 271 | | if (view->cursor_visible()) |
| 272 | | { |
| 273 | | device_t &device = [self source]->device(); |
| 274 | | if (!useConsole || (debug_cpu_get_visible_cpu(*machine) == &device)) |
| 275 | | { |
| 276 | | offs_t const address = downcast<debug_view_disasm *>(view)->selected_address(); |
| 277 | | device_debug::breakpoint *bp = [self findBreakpointAtAddress:address forDevice:device]; |
| 278 | | |
| 279 | | // if it doesn't exist, add a new one |
| 280 | | if (useConsole) |
| 281 | | { |
| 282 | | NSString *command; |
| 283 | | if (bp == NULL) |
| 284 | | command = [NSString stringWithFormat:@"bpset %lX", (unsigned long)address]; |
| 285 | | else |
| 286 | | command = [NSString stringWithFormat:@"bpclear %X", (unsigned)bp->index()]; |
| 287 | | debug_console_execute_command(*machine, [command UTF8String], 1); |
| 288 | | } |
| 289 | | else |
| 290 | | { |
| 291 | | if (bp == NULL) |
| 292 | | { |
| 293 | | UINT32 const bpnum = device.debug()->breakpoint_set(address, NULL, NULL); |
| 294 | | debug_console_printf(*machine, "Breakpoint %X set\n", bpnum); |
| 295 | | } |
| 296 | | else |
| 297 | | { |
| 298 | | int const bpnum = bp->index(); |
| 299 | | device.debug()->breakpoint_clear(bpnum); |
| 300 | | debug_console_printf(*machine, "Breakpoint %X cleared\n", (UINT32)bpnum); |
| 301 | | } |
| 302 | | } |
| 303 | | |
| 304 | | // fail to do this and the display doesn't update |
| 305 | | machine->debug_view().update_all(); |
| 306 | | debugger_refresh_display(*machine); |
| 307 | | } |
| 308 | | } |
| 309 | | } |
| 310 | | |
| 311 | | |
| 312 | | - (IBAction)debugToggleBreakpointEnable:(id)sender { |
| 313 | | if (view->cursor_visible()) |
| 314 | | { |
| 315 | | device_t &device = [self source]->device(); |
| 316 | | if (!useConsole || (debug_cpu_get_visible_cpu(*machine) == &device)) |
| 317 | | { |
| 318 | | offs_t const address = downcast<debug_view_disasm *>(view)->selected_address(); |
| 319 | | device_debug::breakpoint *bp = [self findBreakpointAtAddress:address forDevice:device]; |
| 320 | | if (bp != NULL) |
| 321 | | { |
| 322 | | if (useConsole) |
| 323 | | { |
| 324 | | NSString *command; |
| 325 | | if (bp->enabled()) |
| 326 | | command = [NSString stringWithFormat:@"bpdisable %X", (unsigned)bp->index()]; |
| 327 | | else |
| 328 | | command = [NSString stringWithFormat:@"bpenable %X", (unsigned)bp->index()]; |
| 329 | | debug_console_execute_command(*machine, [command UTF8String], 1); |
| 330 | | } |
| 331 | | else |
| 332 | | { |
| 333 | | device.debug()->breakpoint_enable(bp->index(), !bp->enabled()); |
| 334 | | debug_console_printf(*machine, |
| 335 | | "Breakpoint %X %s\n", |
| 336 | | (UINT32)bp->index(), |
| 337 | | bp->enabled() ? "enabled" : "disabled"); |
| 338 | | } |
| 339 | | machine->debug_view().update_all(); |
| 340 | | debugger_refresh_display(*machine); |
| 341 | | } |
| 342 | | } |
| 343 | | } |
| 344 | | } |
| 345 | | |
| 346 | | |
| 347 | | - (IBAction)debugRunToCursor:(id)sender { |
| 348 | | if (view->cursor_visible()) |
| 349 | | { |
| 350 | | device_t &device = [self source]->device(); |
| 351 | | if (!useConsole || (debug_cpu_get_visible_cpu(*machine) == &device)) |
| 352 | | { |
| 353 | | offs_t const address = downcast<debug_view_disasm *>(view)->selected_address(); |
| 354 | | if (useConsole) |
| 355 | | { |
| 356 | | NSString *command = [NSString stringWithFormat:@"go 0x%lX", (unsigned long)address]; |
| 357 | | debug_console_execute_command(*machine, [command UTF8String], 1); |
| 358 | | } |
| 359 | | else |
| 360 | | { |
| 361 | | device.debug()->go(address); |
| 362 | | } |
| 363 | | } |
| 364 | | } |
| 365 | | } |
| 366 | | |
| 367 | | |
| 368 | | - (IBAction)showRightColumn:(id)sender { |
| 369 | | downcast<debug_view_disasm *>(view)->set_right_column((disasm_right_column) [sender tag]); |
| 370 | | } |
| 371 | | |
| 372 | | |
| 373 | | - (void)insertActionItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index { |
| 374 | | { |
| 375 | | NSMenuItem *breakItem = [menu insertItemWithTitle:@"Toggle Breakpoint at Cursor" |
| 376 | | action:@selector(debugToggleBreakpoint:) |
| 377 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey] |
| 378 | | atIndex:index++]; |
| 379 | | [breakItem setKeyEquivalentModifierMask:0]; |
| 380 | | [breakItem setTarget:self]; |
| 381 | | } |
| 382 | | { |
| 383 | | NSMenuItem *disableItem = [menu insertItemWithTitle:@"Disable Breakpoint at Cursor" |
| 384 | | action:@selector(debugToggleBreakpointEnable:) |
| 385 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF9FunctionKey] |
| 386 | | atIndex:index++]; |
| 387 | | [disableItem setKeyEquivalentModifierMask:NSShiftKeyMask]; |
| 388 | | [disableItem setAlternate:YES]; |
| 389 | | [disableItem setTarget:self]; |
| 390 | | } |
| 391 | | { |
| 392 | | NSMenu *runMenu = [[menu itemWithTitle:@"Run"] submenu]; |
| 393 | | NSMenuItem *runItem; |
| 394 | | if (runMenu != nil) { |
| 395 | | runItem = [runMenu addItemWithTitle:@"to Cursor" |
| 396 | | action:@selector(debugRunToCursor:) |
| 397 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF4FunctionKey]]; |
| 398 | | } else { |
| 399 | | runItem = [menu insertItemWithTitle:@"Run to Cursor" |
| 400 | | action:@selector(debugRunToCursor:) |
| 401 | | keyEquivalent:[NSString stringWithFormat:@"%C", (short)NSF4FunctionKey] |
| 402 | | atIndex:index++]; |
| 403 | | } |
| 404 | | [runItem setKeyEquivalentModifierMask:0]; |
| 405 | | [runItem setTarget:self]; |
| 406 | | } |
| 407 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 408 | | { |
| 409 | | NSMenuItem *rawItem = [menu insertItemWithTitle:@"Show Raw Opcodes" |
| 410 | | action:@selector(showRightColumn:) |
| 411 | | keyEquivalent:@"r" |
| 412 | | atIndex:index++]; |
| 413 | | [rawItem setTarget:self]; |
| 414 | | [rawItem setTag:DASM_RIGHTCOL_RAW]; |
| 415 | | } |
| 416 | | { |
| 417 | | NSMenuItem *encItem = [menu insertItemWithTitle:@"Show Encrypted Opcodes" |
| 418 | | action:@selector(showRightColumn:) |
| 419 | | keyEquivalent:@"e" |
| 420 | | atIndex:index++]; |
| 421 | | [encItem setTarget:self]; |
| 422 | | [encItem setTag:DASM_RIGHTCOL_ENCRYPTED]; |
| 423 | | } |
| 424 | | { |
| 425 | | NSMenuItem *commentsItem = [menu insertItemWithTitle:@"Show Comments" |
| 426 | | action:@selector(showRightColumn:) |
| 427 | | keyEquivalent:@"n" |
| 428 | | atIndex:index++]; |
| 429 | | [commentsItem setTarget:self]; |
| 430 | | [commentsItem setTag:DASM_RIGHTCOL_COMMENTS]; |
| 431 | | } |
| 432 | | if (index < [menu numberOfItems]) |
| 433 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 434 | | } |
| 435 | | |
| 436 | | |
| 437 | | - (void)insertSubviewItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index { |
| 438 | | for (const debug_view_source *source = view->source_list().first(); source != NULL; source = source->next()) |
| 439 | | { |
| 440 | | [[menu insertItemWithTitle:[NSString stringWithUTF8String:source->name()] |
| 441 | | action:NULL |
| 442 | | keyEquivalent:@"" |
| 443 | | atIndex:index++] setTag:view->source_list().indexof(*source)]; |
| 444 | | } |
| 445 | | if (index < [menu numberOfItems]) |
| 446 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 447 | | } |
| 448 | | |
| 449 | | @end |
trunk/src/osd/modules/debugger/osx/disassemblyviewer.m
| r243601 | r243602 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // disassemblyviewer.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 "debugconsole.h" |
| 15 | | #import "debugview.h" |
| 16 | | #import "disassemblyview.h" |
| 17 | | |
| 18 | | #include "debug/debugcpu.h" |
| 19 | | |
| 20 | | |
| 21 | | @implementation MAMEDisassemblyViewer |
| 22 | | |
| 23 | | - (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c { |
| 24 | | NSScrollView *dasmScroll; |
| 25 | | NSView *expressionContainer; |
| 26 | | NSPopUpButton *actionButton; |
| 27 | | NSRect expressionFrame; |
| 28 | | |
| 29 | | if (!(self = [super initWithMachine:m title:@"Disassembly" console:c])) |
| 30 | | return nil; |
| 31 | | NSRect const contentBounds = [[window contentView] bounds]; |
| 32 | | |
| 33 | | // create the expression field |
| 34 | | expressionField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)]; |
| 35 | | [expressionField setAutoresizingMask:(NSViewWidthSizable | NSViewMaxXMargin | NSViewMinYMargin)]; |
| 36 | | [expressionField setFont:[[MAMEDebugView class] defaultFont]]; |
| 37 | | [expressionField setFocusRingType:NSFocusRingTypeNone]; |
| 38 | | [expressionField setTarget:self]; |
| 39 | | [expressionField setAction:@selector(doExpression:)]; |
| 40 | | [expressionField setDelegate:self]; |
| 41 | | expressionFrame = [expressionField frame]; |
| 42 | | expressionFrame.size.width = (contentBounds.size.width - expressionFrame.size.height) / 2; |
| 43 | | [expressionField setFrameSize:expressionFrame.size]; |
| 44 | | |
| 45 | | // create the subview popup |
| 46 | | subviewButton = [[NSPopUpButton alloc] initWithFrame:NSOffsetRect(expressionFrame, |
| 47 | | expressionFrame.size.width, |
| 48 | | 0)]; |
| 49 | | [subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinXMargin | NSViewMinYMargin)]; |
| 50 | | [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle]; |
| 51 | | [subviewButton setFocusRingType:NSFocusRingTypeNone]; |
| 52 | | [subviewButton setFont:[[MAMEDebugView class] defaultFont]]; |
| 53 | | [subviewButton setTarget:self]; |
| 54 | | [subviewButton setAction:@selector(changeSubview:)]; |
| 55 | | [[subviewButton cell] setArrowPosition:NSPopUpArrowAtBottom]; |
| 56 | | |
| 57 | | // create a container for the expression field and subview popup |
| 58 | | expressionFrame = NSMakeRect(expressionFrame.size.height, |
| 59 | | contentBounds.size.height - expressionFrame.size.height, |
| 60 | | contentBounds.size.width - expressionFrame.size.height, |
| 61 | | expressionFrame.size.height); |
| 62 | | expressionContainer = [[NSView alloc] initWithFrame:expressionFrame]; |
| 63 | | [expressionContainer setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)]; |
| 64 | | [expressionContainer addSubview:expressionField]; |
| 65 | | [expressionField release]; |
| 66 | | [expressionContainer addSubview:subviewButton]; |
| 67 | | [subviewButton release]; |
| 68 | | [[window contentView] addSubview:expressionContainer]; |
| 69 | | [expressionContainer release]; |
| 70 | | |
| 71 | | // create the disassembly view |
| 72 | | dasmView = [[MAMEDisassemblyView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) |
| 73 | | machine:*machine |
| 74 | | useConsole:NO]; |
| 75 | | [dasmView insertSubviewItemsInMenu:[subviewButton menu] atIndex:0]; |
| 76 | | dasmScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, |
| 77 | | 0, |
| 78 | | contentBounds.size.width, |
| 79 | | expressionFrame.origin.y)]; |
| 80 | | [dasmScroll setDrawsBackground:YES]; |
| 81 | | [dasmScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 82 | | [dasmScroll setHasHorizontalScroller:YES]; |
| 83 | | [dasmScroll setHasVerticalScroller:YES]; |
| 84 | | [dasmScroll setAutohidesScrollers:YES]; |
| 85 | | [dasmScroll setBorderType:NSNoBorder]; |
| 86 | | [dasmScroll setDocumentView:dasmView]; |
| 87 | | [dasmView release]; |
| 88 | | [[window contentView] addSubview:dasmScroll]; |
| 89 | | [dasmScroll release]; |
| 90 | | |
| 91 | | // create the action popup |
| 92 | | actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0, |
| 93 | | expressionFrame.origin.y, |
| 94 | | expressionFrame.size.height, |
| 95 | | expressionFrame.size.height)]; |
| 96 | | [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)]; |
| 97 | | [dasmView insertActionItemsInMenu:[actionButton menu] atIndex:1]; |
| 98 | | [[window contentView] addSubview:actionButton]; |
| 99 | | [actionButton release]; |
| 100 | | |
| 101 | | // set default state |
| 102 | | [dasmView selectSubviewForDevice:debug_cpu_get_visible_cpu(*machine)]; |
| 103 | | [dasmView setExpression:@"curpc"]; |
| 104 | | [expressionField setStringValue:@"curpc"]; |
| 105 | | [expressionField selectText:self]; |
| 106 | | [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[dasmView selectedSubviewIndex]]]; |
| 107 | | [window makeFirstResponder:expressionField]; |
| 108 | | [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]]; |
| 109 | | |
| 110 | | // calculate the optimal size for everything |
| 111 | | NSSize const desired = [NSScrollView frameSizeForContentSize:[dasmView maximumFrameSize] |
| 112 | | hasHorizontalScroller:YES |
| 113 | | hasVerticalScroller:YES |
| 114 | | borderType:[dasmScroll borderType]]; |
| 115 | | [self cascadeWindowWithDesiredSize:desired forView:dasmScroll]; |
| 116 | | |
| 117 | | // don't forget the result |
| 118 | | return self; |
| 119 | | } |
| 120 | | |
| 121 | | |
| 122 | | - (void)dealloc { |
| 123 | | [super dealloc]; |
| 124 | | } |
| 125 | | |
| 126 | | |
| 127 | | - (id <MAMEDebugViewExpressionSupport>)documentView { |
| 128 | | return dasmView; |
| 129 | | } |
| 130 | | |
| 131 | | |
| 132 | | - (IBAction)debugNewMemoryWindow:(id)sender { |
| 133 | | debug_view_disasm_source const *source = [dasmView source]; |
| 134 | | [console debugNewMemoryWindowForSpace:&source->space() |
| 135 | | device:&source->device() |
| 136 | | expression:nil]; |
| 137 | | } |
| 138 | | |
| 139 | | |
| 140 | | - (IBAction)debugNewDisassemblyWindow:(id)sender { |
| 141 | | debug_view_disasm_source const *source = [dasmView source]; |
| 142 | | [console debugNewDisassemblyWindowForSpace:&source->space() |
| 143 | | device:&source->device() |
| 144 | | expression:[dasmView expression]]; |
| 145 | | } |
| 146 | | |
| 147 | | |
| 148 | | - (BOOL)selectSubviewForDevice:(device_t *)device { |
| 149 | | BOOL const result = [dasmView selectSubviewForDevice:device]; |
| 150 | | [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[dasmView selectedSubviewIndex]]]; |
| 151 | | [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]]; |
| 152 | | return result; |
| 153 | | } |
| 154 | | |
| 155 | | |
| 156 | | - (BOOL)selectSubviewForSpace:(address_space *)space { |
| 157 | | BOOL const result = [dasmView selectSubviewForSpace:space]; |
| 158 | | [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[dasmView selectedSubviewIndex]]]; |
| 159 | | [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]]; |
| 160 | | return result; |
| 161 | | } |
| 162 | | |
| 163 | | |
| 164 | | - (IBAction)changeSubview:(id)sender { |
| 165 | | [dasmView selectSubviewAtIndex:[[sender selectedItem] tag]]; |
| 166 | | [window setTitle:[NSString stringWithFormat:@"Disassembly: %@", [dasmView selectedSubviewName]]]; |
| 167 | | } |
| 168 | | |
| 169 | | @end |
trunk/src/osd/modules/debugger/osx/memoryview.m
| r243601 | r243602 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // memoryview.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 | | |
| 17 | | |
| 18 | | @implementation MAMEMemoryView |
| 19 | | |
| 20 | | - (id)initWithFrame:(NSRect)f machine:(running_machine &)m { |
| 21 | | NSMenu *contextMenu; |
| 22 | | |
| 23 | | if (!(self = [super initWithFrame:f type:DVT_MEMORY machine:m])) |
| 24 | | return nil; |
| 25 | | |
| 26 | | contextMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Memory"]; |
| 27 | | [self insertActionItemsInMenu:contextMenu atIndex:0]; |
| 28 | | [self setMenu:contextMenu]; |
| 29 | | [contextMenu release]; |
| 30 | | |
| 31 | | return self; |
| 32 | | } |
| 33 | | |
| 34 | | |
| 35 | | - (void)dealloc { |
| 36 | | [super dealloc]; |
| 37 | | } |
| 38 | | |
| 39 | | |
| 40 | | - (BOOL)validateMenuItem:(NSMenuItem *)item { |
| 41 | | SEL action = [item action]; |
| 42 | | NSInteger tag = [item tag]; |
| 43 | | debug_view_memory *memview = downcast<debug_view_memory *>(view); |
| 44 | | |
| 45 | | if (action == @selector(showChunkSize:)) { |
| 46 | | [item setState:((tag == memview->bytes_per_chunk()) ? NSOnState : NSOffState)]; |
| 47 | | } else if (action == @selector(showPhysicalAddresses:)) { |
| 48 | | [item setState:((tag == memview->physical()) ? NSOnState : NSOffState)]; |
| 49 | | } else if (action == @selector(showReverseView:)) { |
| 50 | | [item setState:((tag == memview->reverse()) ? NSOnState : NSOffState)]; |
| 51 | | } else if (action == @selector(showReverseViewToggle:)) { |
| 52 | | [item setState:(memview->reverse() ? NSOnState : NSOffState)]; |
| 53 | | } |
| 54 | | return YES; |
| 55 | | } |
| 56 | | |
| 57 | | |
| 58 | | - (NSSize)maximumFrameSize { |
| 59 | | debug_view_xy max; |
| 60 | | device_t *curcpu = debug_cpu_get_visible_cpu(*machine); |
| 61 | | debug_view_source const *source = view->source_for_device(curcpu); |
| 62 | | |
| 63 | | max.x = max.y = 0; |
| 64 | | for (const debug_view_source *source = view->source_list().first(); |
| 65 | | source != NULL; |
| 66 | | source = source->next()) |
| 67 | | { |
| 68 | | debug_view_xy current; |
| 69 | | view->set_source(*source); |
| 70 | | current = view->total_size(); |
| 71 | | if (current.x > max.x) |
| 72 | | max.x = current.x; |
| 73 | | if (current.y > max.y) |
| 74 | | max.y = current.y; |
| 75 | | } |
| 76 | | view->set_source(*source); |
| 77 | | return NSMakeSize(max.x * fontWidth, max.y * fontHeight); |
| 78 | | } |
| 79 | | |
| 80 | | |
| 81 | | - (NSString *)selectedSubviewName { |
| 82 | | debug_view_source const *source = view->source(); |
| 83 | | if (source != NULL) |
| 84 | | return [NSString stringWithUTF8String:source->name()]; |
| 85 | | else |
| 86 | | return @""; |
| 87 | | } |
| 88 | | |
| 89 | | |
| 90 | | - (int)selectedSubviewIndex { |
| 91 | | debug_view_source const *source = view->source(); |
| 92 | | if (source != NULL) |
| 93 | | return view->source_list().indexof(*source); |
| 94 | | else |
| 95 | | return -1; |
| 96 | | } |
| 97 | | |
| 98 | | |
| 99 | | - (void)selectSubviewAtIndex:(int)index { |
| 100 | | int const selected = view->source_list().indexof(*view->source()); |
| 101 | | if (selected != index) { |
| 102 | | view->set_source(*view->source_list().find(index)); |
| 103 | | if ([[self window] firstResponder] != self) |
| 104 | | view->set_cursor_visible(false); |
| 105 | | } |
| 106 | | } |
| 107 | | |
| 108 | | |
| 109 | | - (BOOL)selectSubviewForDevice:(device_t *)device { |
| 110 | | debug_view_source const *const source = view->source_for_device(device); |
| 111 | | if (source != NULL) |
| 112 | | { |
| 113 | | if (view->source() != source) |
| 114 | | { |
| 115 | | view->set_source(*source); |
| 116 | | if ([[self window] firstResponder] != self) |
| 117 | | view->set_cursor_visible(false); |
| 118 | | } |
| 119 | | return YES; |
| 120 | | } |
| 121 | | else |
| 122 | | { |
| 123 | | return NO; |
| 124 | | } |
| 125 | | } |
| 126 | | |
| 127 | | |
| 128 | | - (BOOL)selectSubviewForSpace:(address_space *)space { |
| 129 | | if (space == NULL) return NO; |
| 130 | | debug_view_memory_source const *source = downcast<debug_view_memory_source const *>(view->first_source()); |
| 131 | | while ((source != NULL) && (source->space() != space)) |
| 132 | | source = downcast<debug_view_memory_source *>(source->next()); |
| 133 | | if (source != NULL) |
| 134 | | { |
| 135 | | if (view->source() != source) |
| 136 | | { |
| 137 | | view->set_source(*source); |
| 138 | | if ([[self window] firstResponder] != self) |
| 139 | | view->set_cursor_visible(false); |
| 140 | | } |
| 141 | | return YES; |
| 142 | | } |
| 143 | | else |
| 144 | | { |
| 145 | | return NO; |
| 146 | | } |
| 147 | | } |
| 148 | | |
| 149 | | |
| 150 | | - (NSString *)expression { |
| 151 | | return [NSString stringWithUTF8String:downcast<debug_view_memory *>(view)->expression()]; |
| 152 | | } |
| 153 | | |
| 154 | | |
| 155 | | - (void)setExpression:(NSString *)exp { |
| 156 | | downcast<debug_view_memory *>(view)->set_expression([exp UTF8String]); |
| 157 | | } |
| 158 | | |
| 159 | | |
| 160 | | - (debug_view_memory_source const *)source { |
| 161 | | return downcast<debug_view_memory_source const *>(view->source()); |
| 162 | | } |
| 163 | | |
| 164 | | |
| 165 | | - (IBAction)showChunkSize:(id)sender { |
| 166 | | downcast<debug_view_memory *>(view)->set_bytes_per_chunk([sender tag]); |
| 167 | | } |
| 168 | | |
| 169 | | |
| 170 | | - (IBAction)showPhysicalAddresses:(id)sender { |
| 171 | | downcast<debug_view_memory *>(view)->set_physical([sender tag]); |
| 172 | | } |
| 173 | | |
| 174 | | |
| 175 | | - (IBAction)showReverseView:(id)sender { |
| 176 | | downcast<debug_view_memory *>(view)->set_reverse([sender tag]); |
| 177 | | } |
| 178 | | |
| 179 | | |
| 180 | | - (IBAction)showReverseViewToggle:(id)sender { |
| 181 | | downcast<debug_view_memory *>(view)->set_reverse(!downcast<debug_view_memory *>(view)->reverse()); |
| 182 | | } |
| 183 | | |
| 184 | | |
| 185 | | - (IBAction)changeBytesPerLine:(id)sender { |
| 186 | | debug_view_memory *const memView = downcast<debug_view_memory *>(view); |
| 187 | | memView->set_chunks_per_row(memView->chunks_per_row() + [sender tag]); |
| 188 | | } |
| 189 | | |
| 190 | | |
| 191 | | - (void)insertActionItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index { |
| 192 | | NSInteger tag; |
| 193 | | for (tag = 1; tag <= 8; tag <<= 1) { |
| 194 | | NSString *title = [NSString stringWithFormat:@"%ld-byte Chunks", (long)tag]; |
| 195 | | NSMenuItem *chunkItem = [menu insertItemWithTitle:title |
| 196 | | action:@selector(showChunkSize:) |
| 197 | | keyEquivalent:[NSString stringWithFormat:@"%ld", (long)tag] |
| 198 | | atIndex:index++]; |
| 199 | | [chunkItem setTarget:self]; |
| 200 | | [chunkItem setTag:tag]; |
| 201 | | } |
| 202 | | |
| 203 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 204 | | |
| 205 | | NSMenuItem *logicalItem = [menu insertItemWithTitle:@"Logical Addresses" |
| 206 | | action:@selector(showPhysicalAddresses:) |
| 207 | | keyEquivalent:@"v" |
| 208 | | atIndex:index++]; |
| 209 | | [logicalItem setTarget:self]; |
| 210 | | [logicalItem setTag:FALSE]; |
| 211 | | |
| 212 | | NSMenuItem *physicalItem = [menu insertItemWithTitle:@"Physical Addresses" |
| 213 | | action:@selector(showPhysicalAddresses:) |
| 214 | | keyEquivalent:@"y" |
| 215 | | atIndex:index++]; |
| 216 | | [physicalItem setTarget:self]; |
| 217 | | [physicalItem setTag:TRUE]; |
| 218 | | |
| 219 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 220 | | |
| 221 | | NSMenuItem *reverseItem = [menu insertItemWithTitle:@"Reverse View" |
| 222 | | action:@selector(showReverseViewToggle:) |
| 223 | | keyEquivalent:@"r" |
| 224 | | atIndex:index++]; |
| 225 | | [reverseItem setTarget:self]; |
| 226 | | |
| 227 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 228 | | |
| 229 | | NSMenuItem *increaseItem = [menu insertItemWithTitle:@"Increase Bytes Per Line" |
| 230 | | action:@selector(changeBytesPerLine:) |
| 231 | | keyEquivalent:@"p" |
| 232 | | atIndex:index++]; |
| 233 | | [increaseItem setTarget:self]; |
| 234 | | [increaseItem setTag:1]; |
| 235 | | |
| 236 | | NSMenuItem *decreaseItem = [menu insertItemWithTitle:@"Decrease Bytes Per Line" |
| 237 | | action:@selector(changeBytesPerLine:) |
| 238 | | keyEquivalent:@"o" |
| 239 | | atIndex:index++]; |
| 240 | | [decreaseItem setTarget:self]; |
| 241 | | [decreaseItem setTag:-1]; |
| 242 | | |
| 243 | | if (index < [menu numberOfItems]) |
| 244 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 245 | | } |
| 246 | | |
| 247 | | |
| 248 | | - (void)insertSubviewItemsInMenu:(NSMenu *)menu atIndex:(NSInteger)index { |
| 249 | | for (const debug_view_source *source = view->source_list().first(); source != NULL; source = source->next()) |
| 250 | | { |
| 251 | | [[menu insertItemWithTitle:[NSString stringWithUTF8String:source->name()] |
| 252 | | action:NULL |
| 253 | | keyEquivalent:@"" |
| 254 | | atIndex:index++] setTag:view->source_list().indexof(*source)]; |
| 255 | | } |
| 256 | | if (index < [menu numberOfItems]) |
| 257 | | [menu insertItem:[NSMenuItem separatorItem] atIndex:index++]; |
| 258 | | } |
| 259 | | |
| 260 | | @end |
trunk/src/osd/modules/debugger/osx/memoryviewer.m
| r243601 | r243602 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // memoryviewer.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 "debugconsole.h" |
| 15 | | #import "debugview.h" |
| 16 | | #import "memoryview.h" |
| 17 | | |
| 18 | | #include "debug/debugcpu.h" |
| 19 | | #include "debug/dvmemory.h" |
| 20 | | |
| 21 | | |
| 22 | | @implementation MAMEMemoryViewer |
| 23 | | |
| 24 | | - (id)initWithMachine:(running_machine &)m console:(MAMEDebugConsole *)c { |
| 25 | | NSScrollView *memoryScroll; |
| 26 | | NSView *expressionContainer; |
| 27 | | NSPopUpButton *actionButton; |
| 28 | | NSRect contentBounds, expressionFrame; |
| 29 | | |
| 30 | | if (!(self = [super initWithMachine:m title:@"Memory" console:c])) |
| 31 | | return nil; |
| 32 | | contentBounds = [[window contentView] bounds]; |
| 33 | | |
| 34 | | // create the expression field |
| 35 | | expressionField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 19)]; |
| 36 | | [expressionField setAutoresizingMask:(NSViewWidthSizable | NSViewMaxXMargin | NSViewMinYMargin)]; |
| 37 | | [expressionField setFont:[[MAMEDebugView class] defaultFont]]; |
| 38 | | [expressionField setFocusRingType:NSFocusRingTypeNone]; |
| 39 | | [expressionField setTarget:self]; |
| 40 | | [expressionField setAction:@selector(doExpression:)]; |
| 41 | | [expressionField setDelegate:self]; |
| 42 | | expressionFrame = [expressionField frame]; |
| 43 | | expressionFrame.size.width = (contentBounds.size.width - expressionFrame.size.height) / 2; |
| 44 | | [expressionField setFrameSize:expressionFrame.size]; |
| 45 | | |
| 46 | | // create the subview popup |
| 47 | | subviewButton = [[NSPopUpButton alloc] initWithFrame:NSOffsetRect(expressionFrame, |
| 48 | | expressionFrame.size.width, |
| 49 | | 0)]; |
| 50 | | [subviewButton setAutoresizingMask:(NSViewWidthSizable | NSViewMinXMargin | NSViewMinYMargin)]; |
| 51 | | [subviewButton setBezelStyle:NSShadowlessSquareBezelStyle]; |
| 52 | | [subviewButton setFocusRingType:NSFocusRingTypeNone]; |
| 53 | | [subviewButton setFont:[[MAMEDebugView class] defaultFont]]; |
| 54 | | [subviewButton setTarget:self]; |
| 55 | | [subviewButton setAction:@selector(changeSubview:)]; |
| 56 | | [[subviewButton cell] setArrowPosition:NSPopUpArrowAtBottom]; |
| 57 | | |
| 58 | | // create a container for the expression field and subview popup |
| 59 | | expressionFrame = NSMakeRect(expressionFrame.size.height, |
| 60 | | contentBounds.size.height - expressionFrame.size.height, |
| 61 | | contentBounds.size.width - expressionFrame.size.height, |
| 62 | | expressionFrame.size.height); |
| 63 | | expressionContainer = [[NSView alloc] initWithFrame:expressionFrame]; |
| 64 | | [expressionContainer setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)]; |
| 65 | | [expressionContainer addSubview:expressionField]; |
| 66 | | [expressionField release]; |
| 67 | | [expressionContainer addSubview:subviewButton]; |
| 68 | | [subviewButton release]; |
| 69 | | [[window contentView] addSubview:expressionContainer]; |
| 70 | | [expressionContainer release]; |
| 71 | | |
| 72 | | // create the memory view |
| 73 | | memoryView = [[MAMEMemoryView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) |
| 74 | | machine:*machine]; |
| 75 | | [memoryView insertSubviewItemsInMenu:[subviewButton menu] atIndex:0]; |
| 76 | | memoryScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0, |
| 77 | | 0, |
| 78 | | contentBounds.size.width, |
| 79 | | expressionFrame.origin.y)]; |
| 80 | | [memoryScroll setDrawsBackground:YES]; |
| 81 | | [memoryScroll setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; |
| 82 | | [memoryScroll setHasHorizontalScroller:YES]; |
| 83 | | [memoryScroll setHasVerticalScroller:YES]; |
| 84 | | [memoryScroll setAutohidesScrollers:YES]; |
| 85 | | [memoryScroll setBorderType:NSNoBorder]; |
| 86 | | [memoryScroll setDocumentView:memoryView]; |
| 87 | | [memoryView release]; |
| 88 | | [[window contentView] addSubview:memoryScroll]; |
| 89 | | [memoryScroll release]; |
| 90 | | |
| 91 | | // create the action popup |
| 92 | | actionButton = [[self class] newActionButtonWithFrame:NSMakeRect(0, |
| 93 | | expressionFrame.origin.y, |
| 94 | | expressionFrame.size.height, |
| 95 | | expressionFrame.size.height)]; |
| 96 | | [actionButton setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)]; |
| 97 | | [memoryView insertActionItemsInMenu:[actionButton menu] atIndex:1]; |
| 98 | | [[window contentView] addSubview:actionButton]; |
| 99 | | [actionButton release]; |
| 100 | | |
| 101 | | // set default state |
| 102 | | [memoryView selectSubviewForDevice:debug_cpu_get_visible_cpu(*machine)]; |
| 103 | | [memoryView setExpression:@"0"]; |
| 104 | | [expressionField setStringValue:@"0"]; |
| 105 | | [expressionField selectText:self]; |
| 106 | | [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[memoryView selectedSubviewIndex]]]; |
| 107 | | [window makeFirstResponder:expressionField]; |
| 108 | | [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]]; |
| 109 | | |
| 110 | | // calculate the optimal size for everything |
| 111 | | NSSize const desired = [NSScrollView frameSizeForContentSize:[memoryView maximumFrameSize] |
| 112 | | hasHorizontalScroller:YES |
| 113 | | hasVerticalScroller:YES |
| 114 | | borderType:[memoryScroll borderType]]; |
| 115 | | [self cascadeWindowWithDesiredSize:desired forView:memoryScroll]; |
| 116 | | |
| 117 | | // don't forget the result |
| 118 | | return self; |
| 119 | | } |
| 120 | | |
| 121 | | |
| 122 | | - (void)dealloc { |
| 123 | | [super dealloc]; |
| 124 | | } |
| 125 | | |
| 126 | | |
| 127 | | - (id <MAMEDebugViewExpressionSupport>)documentView { |
| 128 | | return memoryView; |
| 129 | | } |
| 130 | | |
| 131 | | |
| 132 | | - (IBAction)debugNewMemoryWindow:(id)sender { |
| 133 | | debug_view_memory_source const *source = [memoryView source]; |
| 134 | | [console debugNewMemoryWindowForSpace:source->space() |
| 135 | | device:source->device() |
| 136 | | expression:[memoryView expression]]; |
| 137 | | } |
| 138 | | |
| 139 | | |
| 140 | | - (IBAction)debugNewDisassemblyWindow:(id)sender { |
| 141 | | debug_view_memory_source const *source = [memoryView source]; |
| 142 | | [console debugNewDisassemblyWindowForSpace:source->space() |
| 143 | | device:source->device() |
| 144 | | expression:[memoryView expression]]; |
| 145 | | } |
| 146 | | |
| 147 | | |
| 148 | | - (BOOL)selectSubviewForDevice:(device_t *)device { |
| 149 | | BOOL const result = [memoryView selectSubviewForDevice:device]; |
| 150 | | [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[memoryView selectedSubviewIndex]]]; |
| 151 | | [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]]; |
| 152 | | return result; |
| 153 | | } |
| 154 | | |
| 155 | | |
| 156 | | - (BOOL)selectSubviewForSpace:(address_space *)space { |
| 157 | | BOOL const result = [memoryView selectSubviewForSpace:space]; |
| 158 | | [subviewButton selectItemAtIndex:[subviewButton indexOfItemWithTag:[memoryView selectedSubviewIndex]]]; |
| 159 | | [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]]; |
| 160 | | return result; |
| 161 | | } |
| 162 | | |
| 163 | | |
| 164 | | - (IBAction)changeSubview:(id)sender { |
| 165 | | [memoryView selectSubviewAtIndex:[[sender selectedItem] tag]]; |
| 166 | | [window setTitle:[NSString stringWithFormat:@"Memory: %@", [memoryView selectedSubviewName]]]; |
| 167 | | } |
| 168 | | |
| 169 | | @end |
trunk/src/osd/modules/debugger/osx/pointsviewer.m
| r243601 | r243602 | |
| 1 | | // license:BSD-3-Clause |
| 2 | | // copyright-holders:Vas Crabb |
| 3 | | //============================================================ |
| 4 | | // |
| 5 | | // pointsviewer.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 |
trunk/src/osd/modules/debugger/qt/breakpointswindow.c
| r243601 | r243602 | |
| 1 | | #define NO_MEM_TRACKING |
| 2 | | |
| 3 | | #include "breakpointswindow.h" |
| 4 | | |
| 5 | | #include "debug/debugcon.h" |
| 6 | | #include "debug/debugcpu.h" |
| 7 | | #include "debug/dvbpoints.h" |
| 8 | | #include "debug/dvwpoints.h" |
| 9 | | |
| 10 | | |
| 11 | | BreakpointsWindow::BreakpointsWindow(running_machine* machine, QWidget* parent) : |
| 12 | | WindowQt(machine, NULL) |
| 13 | | { |
| 14 | | setWindowTitle("Debug: All Breakpoints"); |
| 15 | | |
| 16 | | if (parent != NULL) |
| 17 | | { |
| 18 | | QPoint parentPos = parent->pos(); |
| 19 | | setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400); |
| 20 | | } |
| 21 | | |
| 22 | | // |
| 23 | | // The main frame and its input and breakpoints widgets |
| 24 | | // |
| 25 | | QFrame* mainWindowFrame = new QFrame(this); |
| 26 | | |
| 27 | | // The main breakpoints view |
| 28 | | m_breakpointsView = new DebuggerView(DVT_BREAK_POINTS, m_machine, this); |
| 29 | | |
| 30 | | // Layout |
| 31 | | QVBoxLayout* vLayout = new QVBoxLayout(mainWindowFrame); |
| 32 | | vLayout->setObjectName("vlayout"); |
| 33 | | vLayout->setSpacing(3); |
| 34 | | vLayout->setContentsMargins(2,2,2,2); |
| 35 | | vLayout->addWidget(m_breakpointsView); |
| 36 | | |
| 37 | | setCentralWidget(mainWindowFrame); |
| 38 | | |
| 39 | | // |
| 40 | | // Menu bars |
| 41 | | // |
| 42 | | QActionGroup* typeGroup = new QActionGroup(this); |
| 43 | | typeGroup->setObjectName("typegroup"); |
| 44 | | QAction* typeBreak = new QAction("Breakpoints", this); |
| 45 | | typeBreak->setObjectName("typebreak"); |
| 46 | | QAction* typeWatch = new QAction("Watchpoints", this); |
| 47 | | typeWatch->setObjectName("typewatch"); |
| 48 | | typeBreak->setCheckable(true); |
| 49 | | typeWatch->setCheckable(true); |
| 50 | | typeBreak->setActionGroup(typeGroup); |
| 51 | | typeWatch->setActionGroup(typeGroup); |
| 52 | | typeBreak->setShortcut(QKeySequence("Ctrl+1")); |
| 53 | | typeWatch->setShortcut(QKeySequence("Ctrl+2")); |
| 54 | | typeBreak->setChecked(true); |
| 55 | | connect(typeGroup, SIGNAL(triggered(QAction*)), this, SLOT(typeChanged(QAction*))); |
| 56 | | |
| 57 | | // Assemble the options menu |
| 58 | | QMenu* optionsMenu = menuBar()->addMenu("&Options"); |
| 59 | | optionsMenu->addActions(typeGroup->actions()); |
| 60 | | } |
| 61 | | |
| 62 | | |
| 63 | | BreakpointsWindow::~BreakpointsWindow() |
| 64 | | { |
| 65 | | } |
| 66 | | |
| 67 | | |
| 68 | | void BreakpointsWindow::typeChanged(QAction* changedTo) |
| 69 | | { |
| 70 | | // Clean |
| 71 | | delete m_breakpointsView; |
| 72 | | m_breakpointsView = NULL; |
| 73 | | |
| 74 | | // Create |
| 75 | | if (changedTo->text() == "Breakpoints") |
| 76 | | { |
| 77 | | m_breakpointsView = new DebuggerView(DVT_BREAK_POINTS, m_machine, this); |
| 78 | | setWindowTitle("Debug: All Breakpoints"); |
| 79 | | } |
| 80 | | else if (changedTo->text() == "Watchpoints") |
| 81 | | { |
| 82 | | m_breakpointsView = new DebuggerView(DVT_WATCH_POINTS, m_machine, this); |
| 83 | | setWindowTitle("Debug: All Watchpoints"); |
| 84 | | } |
| 85 | | |
| 86 | | // Re-register |
| 87 | | QVBoxLayout* layout = findChild<QVBoxLayout*>("vlayout"); |
| 88 | | layout->addWidget(m_breakpointsView); |
| 89 | | } |
| 90 | | |
| 91 | | |
| 92 | | |
| 93 | | //========================================================================= |
| 94 | | // BreakpointsWindowQtConfig |
| 95 | | //========================================================================= |
| 96 | | void BreakpointsWindowQtConfig::buildFromQWidget(QWidget* widget) |
| 97 | | { |
| 98 | | WindowQtConfig::buildFromQWidget(widget); |
| 99 | | BreakpointsWindow* window = dynamic_cast<BreakpointsWindow*>(widget); |
| 100 | | |
| 101 | | QActionGroup* typeGroup = window->findChild<QActionGroup*>("typegroup"); |
| 102 | | if (typeGroup->checkedAction()->text() == "Breakpoints") |
| 103 | | m_bwType = 0; |
| 104 | | else if (typeGroup->checkedAction()->text() == "Watchpoints") |
| 105 | | m_bwType = 1; |
| 106 | | } |
| 107 | | |
| 108 | | |
| 109 | | void BreakpointsWindowQtConfig::applyToQWidget(QWidget* widget) |
| 110 | | { |
| 111 | | WindowQtConfig::applyToQWidget(widget); |
| 112 | | BreakpointsWindow* window = dynamic_cast<BreakpointsWindow*>(widget); |
| 113 | | |
| 114 | | QActionGroup* typeGroup = window->findChild<QActionGroup*>("typegroup"); |
| 115 | | typeGroup->actions()[m_bwType]->trigger(); |
| 116 | | } |
| 117 | | |
| 118 | | |
| 119 | | void BreakpointsWindowQtConfig::addToXmlDataNode(xml_data_node* node) const |
| 120 | | { |
| 121 | | WindowQtConfig::addToXmlDataNode(node); |
| 122 | | xml_set_attribute_int(node, "bwtype", m_bwType); |
| 123 | | } |
| 124 | | |
| 125 | | |
| 126 | | void BreakpointsWindowQtConfig::recoverFromXmlNode(xml_data_node* node) |
| 127 | | { |
| 128 | | WindowQtConfig::recoverFromXmlNode(node); |
| 129 | | m_bwType = xml_get_attribute_int(node, "bwtype", m_bwType); |
| 130 | | } |
trunk/src/osd/modules/debugger/qt/dasmwindow.c
| r243601 | r243602 | |
| 1 | | #define NO_MEM_TRACKING |
| 2 | | |
| 3 | | #include "dasmwindow.h" |
| 4 | | |
| 5 | | #include "debug/debugcon.h" |
| 6 | | #include "debug/debugcpu.h" |
| 7 | | #include "debug/dvdisasm.h" |
| 8 | | |
| 9 | | |
| 10 | | DasmWindow::DasmWindow(running_machine* machine, QWidget* parent) : |
| 11 | | WindowQt(machine, NULL) |
| 12 | | { |
| 13 | | setWindowTitle("Debug: Disassembly View"); |
| 14 | | |
| 15 | | if (parent != NULL) |
| 16 | | { |
| 17 | | QPoint parentPos = parent->pos(); |
| 18 | | setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400); |
| 19 | | } |
| 20 | | |
| 21 | | // |
| 22 | | // The main frame and its input and log widgets |
| 23 | | // |
| 24 | | QFrame* mainWindowFrame = new QFrame(this); |
| 25 | | |
| 26 | | // The top frame & groupbox that contains the input widgets |
| 27 | | QFrame* topSubFrame = new QFrame(mainWindowFrame); |
| 28 | | |
| 29 | | // The input edit |
| 30 | | m_inputEdit = new QLineEdit(topSubFrame); |
| 31 | | connect(m_inputEdit, SIGNAL(returnPressed()), this, SLOT(expressionSubmitted())); |
| 32 | | |
| 33 | | // The cpu combo box |
| 34 | | m_cpuComboBox = new QComboBox(topSubFrame); |
| 35 | | m_cpuComboBox->setObjectName("cpu"); |
| 36 | | m_cpuComboBox->setMinimumWidth(300); |
| 37 | | connect(m_cpuComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(cpuChanged(int))); |
| 38 | | |
| 39 | | // The main disasm window |
| 40 | | m_dasmView = new DebuggerView(DVT_DISASSEMBLY, |
| 41 | | m_machine, |
| 42 | | this); |
| 43 | | |
| 44 | | // Force a recompute of the disassembly region |
| 45 | | downcast<debug_view_disasm*>(m_dasmView->view())->set_expression("curpc"); |
| 46 | | |
| 47 | | // Populate the combo box & set the proper cpu |
| 48 | | populateComboBox(); |
| 49 | | //const debug_view_source *source = mem->views[0]->view->source_for_device(curcpu); |
| 50 | | //gtk_combo_box_set_active(zone_w, mem->views[0]->view->source_list().indexof(*source)); |
| 51 | | //mem->views[0]->view->set_source(*source); |
| 52 | | |
| 53 | | |
| 54 | | // Layout |
| 55 | | QHBoxLayout* subLayout = new QHBoxLayout(topSubFrame); |
| 56 | | subLayout->addWidget(m_inputEdit); |
| 57 | | subLayout->addWidget(m_cpuComboBox); |
| 58 | | subLayout->setSpacing(3); |
| 59 | | subLayout->setContentsMargins(2,2,2,2); |
| 60 | | |
| 61 | | QVBoxLayout* vLayout = new QVBoxLayout(mainWindowFrame); |
| 62 | | vLayout->setSpacing(3); |
| 63 | | vLayout->setContentsMargins(2,2,2,2); |
| 64 | | vLayout->addWidget(topSubFrame); |
| 65 | | vLayout->addWidget(m_dasmView); |
| 66 | | |
| 67 | | setCentralWidget(mainWindowFrame); |
| 68 | | |
| 69 | | // |
| 70 | | // Menu bars |
| 71 | | // |
| 72 | | // Create two commands |
| 73 | | QAction* breakpointSetAct = new QAction("Toggle Breakpoint At Cursor", this); |
| 74 | | QAction* runToCursorAct = new QAction("Run To Cursor", this); |
| 75 | | breakpointSetAct->setShortcut(Qt::Key_F9); |
| 76 | | runToCursorAct->setShortcut(Qt::Key_F4); |
| 77 | | connect(breakpointSetAct, SIGNAL(triggered(bool)), this, SLOT(toggleBreakpointAtCursor(bool))); |
| 78 | | connect(runToCursorAct, SIGNAL(triggered(bool)), this, SLOT(runToCursor(bool))); |
| 79 | | |
| 80 | | // Right bar options |
| 81 | | QActionGroup* rightBarGroup = new QActionGroup(this); |
| 82 | | rightBarGroup->setObjectName("rightbargroup"); |
| 83 | | QAction* rightActRaw = new QAction("Raw Opcodes", this); |
| 84 | | QAction* rightActEncrypted = new QAction("Encrypted Opcodes", this); |
| 85 | | QAction* rightActComments = new QAction("Comments", this); |
| 86 | | rightActRaw->setCheckable(true); |
| 87 | | rightActEncrypted->setCheckable(true); |
| 88 | | rightActComments->setCheckable(true); |
| 89 | | rightActRaw->setActionGroup(rightBarGroup); |
| 90 | | rightActEncrypted->setActionGroup(rightBarGroup); |
| 91 | | rightActComments->setActionGroup(rightBarGroup); |
| 92 | | rightActRaw->setShortcut(QKeySequence("Ctrl+R")); |
| 93 | | rightActEncrypted->setShortcut(QKeySequence("Ctrl+E")); |
| 94 | | rightActComments->setShortcut(QKeySequence("Ctrl+C")); |
| 95 | | rightActRaw->setChecked(true); |
| 96 | | connect(rightBarGroup, SIGNAL(triggered(QAction*)), this, SLOT(rightBarChanged(QAction*))); |
| 97 | | |
| 98 | | // Assemble the options menu |
| 99 | | QMenu* optionsMenu = menuBar()->addMenu("&Options"); |
| 100 | | optionsMenu->addAction(breakpointSetAct); |
| 101 | | optionsMenu->addAction(runToCursorAct); |
| 102 | | optionsMenu->addSeparator(); |
| 103 | | optionsMenu->addActions(rightBarGroup->actions()); |
| 104 | | } |
| 105 | | |
| 106 | | |
| 107 | | DasmWindow::~DasmWindow() |
| 108 | | { |
| 109 | | } |
| 110 | | |
| 111 | | |
| 112 | | void DasmWindow::cpuChanged(int index) |
| 113 | | { |
| 114 | | m_dasmView->view()->set_source(*m_dasmView->view()->source_list().find(index)); |
| 115 | | m_dasmView->viewport()->update(); |
| 116 | | } |
| 117 | | |
| 118 | | |
| 119 | | void DasmWindow::expressionSubmitted() |
| 120 | | { |
| 121 | | const QString expression = m_inputEdit->text(); |
| 122 | | downcast<debug_view_disasm*>(m_dasmView->view())->set_expression(expression.toLocal8Bit().data()); |
| 123 | | m_dasmView->viewport()->update(); |
| 124 | | } |
| 125 | | |
| 126 | | |
| 127 | | void DasmWindow::toggleBreakpointAtCursor(bool changedTo) |
| 128 | | { |
| 129 | | if (m_dasmView->view()->cursor_visible()) |
| 130 | | { |
| 131 | | if (debug_cpu_get_visible_cpu(*m_machine) == m_dasmView->view()->source()->device()) |
| 132 | | { |
| 133 | | offs_t address = downcast<debug_view_disasm *>(m_dasmView->view())->selected_address(); |
| 134 | | device_debug *cpuinfo = m_dasmView->view()->source()->device()->debug(); |
| 135 | | |
| 136 | | // Find an existing breakpoint at this address |
| 137 | | INT32 bpindex = -1; |
| 138 | | for (device_debug::breakpoint* bp = cpuinfo->breakpoint_first(); |
| 139 | | bp != NULL; |
| 140 | | bp = bp->next()) |
| 141 | | { |
| 142 | | if (address == bp->address()) |
| 143 | | { |
| 144 | | bpindex = bp->index(); |
| 145 | | break; |
| 146 | | } |
| 147 | | } |
| 148 | | |
| 149 | | // If none exists, add a new one |
| 150 | | astring command; |
| 151 | | if (bpindex == -1) |
| 152 | | { |
| 153 | | command.printf("bpset 0x%X", address); |
| 154 | | } |
| 155 | | else |
| 156 | | { |
| 157 | | command.printf("bpclear 0x%X", bpindex); |
| 158 | | } |
| 159 | | debug_console_execute_command(*m_machine, command, 1); |
| 160 | | } |
| 161 | | } |
| 162 | | |
| 163 | | refreshAll(); |
| 164 | | } |
| 165 | | |
| 166 | | |
| 167 | | void DasmWindow::runToCursor(bool changedTo) |
| 168 | | { |
| 169 | | if (m_dasmView->view()->cursor_visible()) |
| 170 | | { |
| 171 | | if (debug_cpu_get_visible_cpu(*m_machine) == m_dasmView->view()->source()->device()) |
| 172 | | { |
| 173 | | offs_t address = downcast<debug_view_disasm*>(m_dasmView->view())->selected_address(); |
| 174 | | astring command; |
| 175 | | command.printf("go 0x%X", address); |
| 176 | | debug_console_execute_command(*m_machine, command, 1); |
| 177 | | } |
| 178 | | } |
| 179 | | } |
| 180 | | |
| 181 | | |
| 182 | | void DasmWindow::rightBarChanged(QAction* changedTo) |
| 183 | | { |
| 184 | | debug_view_disasm* dasmView = downcast<debug_view_disasm*>(m_dasmView->view()); |
| 185 | | if (changedTo->text() == "Raw Opcodes") |
| 186 | | { |
| 187 | | dasmView->set_right_column(DASM_RIGHTCOL_RAW); |
| 188 | | } |
| 189 | | else if (changedTo->text() == "Encrypted Opcodes") |
| 190 | | { |
| 191 | | dasmView->set_right_column(DASM_RIGHTCOL_ENCRYPTED); |
| 192 | | } |
| 193 | | else if (changedTo->text() == "Comments") |
| 194 | | { |
| 195 | | dasmView->set_right_column(DASM_RIGHTCOL_COMMENTS); |
| 196 | | } |
| 197 | | m_dasmView->viewport()->update(); |
| 198 | | } |
| 199 | | |
| 200 | | |
| 201 | | void DasmWindow::populateComboBox() |
| 202 | | { |
| 203 | | if (m_dasmView == NULL) |
| 204 | | return; |
| 205 | | |
| 206 | | m_cpuComboBox->clear(); |
| 207 | | for (const debug_view_source* source = m_dasmView->view()->first_source(); |
| 208 | | source != NULL; |
| 209 | | source = source->next()) |
| 210 | | { |
| 211 | | m_cpuComboBox->addItem(source->name()); |
| 212 | | } |
| 213 | | } |
| 214 | | |
| 215 | | |
| 216 | | //========================================================================= |
| 217 | | // DasmWindowQtConfig |
| 218 | | //========================================================================= |
| 219 | | void DasmWindowQtConfig::buildFromQWidget(QWidget* widget) |
| 220 | | { |
| 221 | | WindowQtConfig::buildFromQWidget(widget); |
| 222 | | DasmWindow* window = dynamic_cast<DasmWindow*>(widget); |
| 223 | | QComboBox* cpu = window->findChild<QComboBox*>("cpu"); |
| 224 | | m_cpu = cpu->currentIndex(); |
| 225 | | |
| 226 | | QActionGroup* rightBarGroup = window->findChild<QActionGroup*>("rightbargroup"); |
| 227 | | if (rightBarGroup->checkedAction()->text() == "Raw Opcodes") |
| 228 | | m_rightBar = 0; |
| 229 | | else if (rightBarGroup->checkedAction()->text() == "Encrypted Opcodes") |
| 230 | | m_rightBar = 1; |
| 231 | | else if (rightBarGroup->checkedAction()->text() == "Comments") |
| 232 | | m_rightBar = 2; |
| 233 | | } |
| 234 | | |
| 235 | | void DasmWindowQtConfig::applyToQWidget(QWidget* widget) |
| 236 | | { |
| 237 | | WindowQtConfig::applyToQWidget(widget); |
| 238 | | DasmWindow* window = dynamic_cast<DasmWindow*>(widget); |
| 239 | | QComboBox* cpu = window->findChild<QComboBox*>("cpu"); |
| 240 | | cpu->setCurrentIndex(m_cpu); |
| 241 | | |
| 242 | | QActionGroup* rightBarGroup = window->findChild<QActionGroup*>("rightbargroup"); |
| 243 | | rightBarGroup->actions()[m_rightBar]->trigger(); |
| 244 | | } |
| 245 | | |
| 246 | | void DasmWindowQtConfig::addToXmlDataNode(xml_data_node* node) const |
| 247 | | { |
| 248 | | WindowQtConfig::addToXmlDataNode(node); |
| 249 | | xml_set_attribute_int(node, "cpu", m_cpu); |
| 250 | | xml_set_attribute_int(node, "rightbar", m_rightBar); |
| 251 | | } |
| 252 | | |
| 253 | | void DasmWindowQtConfig::recoverFromXmlNode(xml_data_node* node) |
| 254 | | { |
| 255 | | WindowQtConfig::recoverFromXmlNode(node); |
| 256 | | m_cpu = xml_get_attribute_int(node, "cpu", m_cpu); |
| 257 | | m_rightBar = xml_get_attribute_int(node, "rightbar", m_rightBar); |
| 258 | | } |
trunk/src/osd/modules/debugger/qt/debuggerview.c
| r243601 | r243602 | |
| 1 | | #define NO_MEM_TRACKING |
| 2 | | |
| 3 | | #include "debuggerview.h" |
| 4 | | |
| 5 | | DebuggerView::DebuggerView(const debug_view_type& type, |
| 6 | | running_machine* machine, |
| 7 | | QWidget* parent) : |
| 8 | | QAbstractScrollArea(parent), |
| 9 | | m_preferBottom(false), |
| 10 | | m_view(NULL), |
| 11 | | m_machine(machine) |
| 12 | | { |
| 13 | | // I like setting the font per-view since it doesn't override the menuing fonts. |
| 14 | | QFont viewFontRequest("Courier New"); |
| 15 | | viewFontRequest.setFixedPitch(true); |
| 16 | | viewFontRequest.setPointSize(11); |
| 17 | | setFont(viewFontRequest); |
| 18 | | |
| 19 | | m_view = m_machine->debug_view().alloc_view(type, |
| 20 | | DebuggerView::debuggerViewUpdate, |
| 21 | | this); |
| 22 | | |
| 23 | | connect(verticalScrollBar(), SIGNAL(valueChanged(int)), |
| 24 | | this, SLOT(verticalScrollSlot(int))); |
| 25 | | connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), |
| 26 | | this, SLOT(horizontalScrollSlot(int))); |
| 27 | | } |
| 28 | | |
| 29 | | |
| 30 | | DebuggerView::~DebuggerView() |
| 31 | | { |
| 32 | | if (m_machine && m_view) |
| 33 | | m_machine->debug_view().free_view(*m_view); |
| 34 | | } |
| 35 | | |
| 36 | | // TODO: remove this version no later than January 1, 2015 |
| 37 | | #if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) |
| 38 | | void DebuggerView::paintEvent(QPaintEvent* event) |
| 39 | | { |
| 40 | | // Tell the MAME debug view how much real estate is available |
| 41 | | QFontMetrics actualFont = fontMetrics(); |
| 42 | | const int fontWidth = MAX(1, actualFont.width('_')); |
| 43 | | const int fontHeight = MAX(1, actualFont.height()); |
| 44 | | m_view->set_visible_size(debug_view_xy(width()/fontWidth, height()/fontHeight)); |
| 45 | | |
| 46 | | |
| 47 | | // Handle the scroll bars |
| 48 | | const int horizontalScrollCharDiff = m_view->total_size().x - m_view->visible_size().x; |
| 49 | | const int horizontalScrollSize = horizontalScrollCharDiff < 0 ? 0 : horizontalScrollCharDiff; |
| 50 | | horizontalScrollBar()->setRange(0, horizontalScrollSize); |
| 51 | | |
| 52 | | // If the horizontal scroll bar appears, make sure to adjust the vertical scrollbar accordingly |
| 53 | | const int verticalScrollAdjust = horizontalScrollSize > 0 ? 1 : 0; |
| 54 | | |
| 55 | | const int verticalScrollCharDiff = m_view->total_size().y - m_view->visible_size().y; |
| 56 | | const int verticalScrollSize = verticalScrollCharDiff < 0 ? 0 : verticalScrollCharDiff+verticalScrollAdjust; |
| 57 | | bool atEnd = false; |
| 58 | | if (verticalScrollBar()->value() == verticalScrollBar()->maximum()) |
| 59 | | { |
| 60 | | atEnd = true; |
| 61 | | } |
| 62 | | verticalScrollBar()->setRange(0, verticalScrollSize); |
| 63 | | if (m_preferBottom && atEnd) |
| 64 | | { |
| 65 | | verticalScrollBar()->setValue(verticalScrollSize); |
| 66 | | } |
| 67 | | |
| 68 | | |
| 69 | | // Draw the viewport widget |
| 70 | | QPainter painter(viewport()); |
| 71 | | painter.fillRect(0, 0, width(), height(), QBrush(Qt::white)); |
| 72 | | painter.setBackgroundMode(Qt::OpaqueMode); |
| 73 | | painter.setBackground(QColor(255,255,255)); |
| 74 | | |
| 75 | | // Background control |
| 76 | | QBrush bgBrush; |
| 77 | | bgBrush.setStyle(Qt::SolidPattern); |
| 78 | | painter.setPen(QPen(QColor(0,0,0))); |
| 79 | | |
| 80 | | size_t viewDataOffset = 0; |
| 81 | | const debug_view_xy& visibleCharDims = m_view->visible_size(); |
| 82 | | for (int y = 0; y < visibleCharDims.y; y++) |
| 83 | | { |
| 84 | | for (int x = 0; x < visibleCharDims.x; x++) |
| 85 | | { |
| 86 | | const unsigned char textAttr = m_view->viewdata()[viewDataOffset].attrib; |
| 87 | | |
| 88 | | if (x == 0 || textAttr != m_view->viewdata()[viewDataOffset-1].attrib) |
| 89 | | { |
| 90 | | // Text color handling |
| 91 | | QColor fgColor(0,0,0); |
| 92 | | QColor bgColor(255,255,255); |
| 93 | | |
| 94 | | if(textAttr & DCA_VISITED) |
| 95 | | { |
| 96 | | bgColor.setRgb(0xc6, 0xe2, 0xff); |
| 97 | | } |
| 98 | | if(textAttr & DCA_ANCILLARY) |
| 99 | | { |
| 100 | | bgColor.setRgb(0xe0, 0xe0, 0xe0); |
| 101 | | } |
| 102 | | if(textAttr & DCA_SELECTED) |
| 103 | | { |
| 104 | | bgColor.setRgb(0xff, 0x80, 0x80); |
| 105 | | } |
| 106 | | if(textAttr & DCA_CURRENT) |
| 107 | | { |
| 108 | | bgColor.setRgb(0xff, 0xff, 0x00); |
| 109 | | } |
| 110 | | if ((textAttr & DCA_SELECTED) && (textAttr & DCA_CURRENT)) |
| 111 | | { |
| 112 | | bgColor.setRgb(0xff,0xc0,0x80); |
| 113 | | } |
| 114 | | if(textAttr & DCA_CHANGED) |
| 115 | | { |
| 116 | | fgColor.setRgb(0xff, 0x00, 0x00); |
| 117 | | } |
| 118 | | if(textAttr & DCA_INVALID) |
| 119 | | { |
| 120 | | fgColor.setRgb(0x00, 0x00, 0xff); |
| 121 | | } |
| 122 | | if(textAttr & DCA_DISABLED) |
| 123 | | { |
| 124 | | fgColor.setRgb((fgColor.red() + bgColor.red()) >> 1, |
| 125 | | (fgColor.green() + bgColor.green()) >> 1, |
| 126 | | (fgColor.blue() + bgColor.blue()) >> 1); |
| 127 | | } |
| 128 | | if(textAttr & DCA_COMMENT) |
| 129 | | { |
| 130 | | fgColor.setRgb(0x00, 0x80, 0x00); |
| 131 | | } |
| 132 | | |
| 133 | | bgBrush.setColor(bgColor); |
| 134 | | painter.setBackground(bgBrush); |
| 135 | | painter.setPen(QPen(fgColor)); |
| 136 | | } |
| 137 | | |
| 138 | | // Your character is not guaranteed to take up the entire fontWidth x fontHeight, so fill before. |
| 139 | | painter.fillRect(x*fontWidth, y*fontHeight, fontWidth, fontHeight, bgBrush); |
| 140 | | |
| 141 | | // There is a touchy interplay between font height, drawing difference, visible position, etc |
| 142 | | // Fonts don't get drawn "down and to the left" like boxes, so some wiggling is needed. |
| 143 | | painter.drawText(x*fontWidth, |
| 144 | | (y*fontHeight + (fontHeight*0.80)), |
| 145 | | QString(m_view->viewdata()[viewDataOffset].byte)); |
| 146 | | viewDataOffset++; |
| 147 | | } |
| 148 | | } |
| 149 | | } |
| 150 | | #else |
| 151 | | void DebuggerView::paintEvent(QPaintEvent* event) |
| 152 | | { |
| 153 | | // Tell the MAME debug view how much real estate is available |
| 154 | | QFontMetrics actualFont = fontMetrics(); |
| 155 | | const double fontWidth = actualFont.width(QString(100, '_')) / 100.; |
| 156 | | const int fontHeight = MAX(1, actualFont.height()); |
| 157 | | m_view->set_visible_size(debug_view_xy(width()/fontWidth, height()/fontHeight)); |
| 158 | | |
| 159 | | |
| 160 | | // Handle the scroll bars |
| 161 | | const int horizontalScrollCharDiff = m_view->total_size().x - m_view->visible_size().x; |
| 162 | | const int horizontalScrollSize = horizontalScrollCharDiff < 0 ? 0 : horizontalScrollCharDiff; |
| 163 | | horizontalScrollBar()->setRange(0, horizontalScrollSize); |
| 164 | | |
| 165 | | // If the horizontal scroll bar appears, make sure to adjust the vertical scrollbar accordingly |
| 166 | | const int verticalScrollAdjust = horizontalScrollSize > 0 ? 1 : 0; |
| 167 | | |
| 168 | | const int verticalScrollCharDiff = m_view->total_size().y - m_view->visible_size().y; |
| 169 | | const int verticalScrollSize = verticalScrollCharDiff < 0 ? 0 : verticalScrollCharDiff+verticalScrollAdjust; |
| 170 | | bool atEnd = false; |
| 171 | | if (verticalScrollBar()->value() == verticalScrollBar()->maximum()) |
| 172 | | { |
| 173 | | atEnd = true; |
| 174 | | } |
| 175 | | verticalScrollBar()->setRange(0, verticalScrollSize); |
| 176 | | if (m_preferBottom && atEnd) |
| 177 | | { |
| 178 | | verticalScrollBar()->setValue(verticalScrollSize); |
| 179 | | } |
| 180 | | |
| 181 | | |
| 182 | | // Draw the viewport widget |
| 183 | | QPainter painter(viewport()); |
| 184 | | painter.fillRect(0, 0, width(), height(), QBrush(Qt::white)); |
| 185 | | painter.setBackgroundMode(Qt::OpaqueMode); |
| 186 | | painter.setBackground(QColor(255,255,255)); |
| 187 | | |
| 188 | | // Background control |
| 189 | | QBrush bgBrush; |
| 190 | | bgBrush.setStyle(Qt::SolidPattern); |
| 191 | | painter.setPen(QPen(QColor(0,0,0))); |
| 192 | | |
| 193 | | size_t viewDataOffset = 0; |
| 194 | | const debug_view_xy& visibleCharDims = m_view->visible_size(); |
| 195 | | const debug_view_char* viewdata = m_view->viewdata(); |
| 196 | | for (int y = 0; y < visibleCharDims.y; y++) |
| 197 | | { |
| 198 | | int width = 1; |
| 199 | | for (int x = 0; x < visibleCharDims.x; viewDataOffset += width, x += width) |
| 200 | | { |
| 201 | | const unsigned char textAttr = viewdata[viewDataOffset].attrib; |
| 202 | | |
| 203 | | // Text color handling |
| 204 | | QColor fgColor(0,0,0); |
| 205 | | QColor bgColor(255,255,255); |
| 206 | | |
| 207 | | if(textAttr & DCA_VISITED) |
| 208 | | { |
| 209 | | bgColor.setRgb(0xc6, 0xe2, 0xff); |
| 210 | | } |
| 211 | | if(textAttr & DCA_ANCILLARY) |
| 212 | | { |
| 213 | | bgColor.setRgb(0xe0, 0xe0, 0xe0); |
| 214 | | } |
| 215 | | if(textAttr & DCA_SELECTED) |
| 216 | | { |
| 217 | | bgColor.setRgb(0xff, 0x80, 0x80); |
| 218 | | } |
| 219 | | if(textAttr & DCA_CURRENT) |
| 220 | | { |
| 221 | | bgColor.setRgb(0xff, 0xff, 0x00); |
| 222 | | } |
| 223 | | if ((textAttr & DCA_SELECTED) && (textAttr & DCA_CURRENT)) |
| 224 | | { |
| 225 | | bgColor.setRgb(0xff,0xc0,0x80); |
| 226 | | } |
| 227 | | if(textAttr & DCA_CHANGED) |
| 228 | | { |
| 229 | | fgColor.setRgb(0xff, 0x00, 0x00); |
| 230 | | } |
| 231 | | if(textAttr & DCA_INVALID) |
| 232 | | { |
| 233 | | fgColor.setRgb(0x00, 0x00, 0xff); |
| 234 | | } |
| 235 | | if(textAttr & DCA_DISABLED) |
| 236 | | { |
| 237 | | fgColor.setRgb((fgColor.red() + bgColor.red()) >> 1, |
| 238 | | (fgColor.green() + bgColor.green()) >> 1, |
| 239 | | (fgColor.blue() + bgColor.blue()) >> 1); |
| 240 | | } |
| 241 | | if(textAttr & DCA_COMMENT) |
| 242 | | { |
| 243 | | fgColor.setRgb(0x00, 0x80, 0x00); |
| 244 | | } |
| 245 | | |
| 246 | | bgBrush.setColor(bgColor); |
| 247 | | painter.setBackground(bgBrush); |
| 248 | | painter.setPen(QPen(fgColor)); |
| 249 | | |
| 250 | | QString text(QChar(viewdata[viewDataOffset].byte)); |
| 251 | | for (width = 1; x + width < visibleCharDims.x; width++) |
| 252 | | { |
| 253 | | if (textAttr != viewdata[viewDataOffset + width].attrib) |
| 254 | | break; |
| 255 | | text.append(QChar(viewdata[viewDataOffset + width].byte)); |
| 256 | | } |
| 257 | | |
| 258 | | // Your characters are not guaranteed to take up the entire length x fontWidth x fontHeight, so fill before. |
| 259 | | painter.fillRect(x*fontWidth, y*fontHeight, width*fontWidth, fontHeight, bgBrush); |
| 260 | | |
| 261 | | // There is a touchy interplay between font height, drawing difference, visible position, etc |
| 262 | | // Fonts don't get drawn "down and to the left" like boxes, so some wiggling is needed. |
| 263 | | painter.drawText(x*fontWidth, (y*fontHeight + (fontHeight*0.80)), text); |
| 264 | | } |
| 265 | | } |
| 266 | | } |
| 267 | | #endif |
| 268 | | |
| 269 | | void DebuggerView::keyPressEvent(QKeyEvent* event) |
| 270 | | { |
| 271 | | if (m_view == NULL) |
| 272 | | return QWidget::keyPressEvent(event); |
| 273 | | |
| 274 | | Qt::KeyboardModifiers keyMods = QApplication::keyboardModifiers(); |
| 275 | | const bool ctrlDown = keyMods.testFlag(Qt::ControlModifier); |
| 276 | | |
| 277 | | int keyPress = -1; |
| 278 | | switch (event->key()) |
| 279 | | { |
| 280 | | case Qt::Key_Up: |
| 281 | | keyPress = DCH_UP; |
| 282 | | break; |
| 283 | | case Qt::Key_Down: |
| 284 | | keyPress = DCH_DOWN; |
| 285 | | break; |
| 286 | | case Qt::Key_Left: |
| 287 | | keyPress = DCH_LEFT; |
| 288 | | if (ctrlDown) keyPress = DCH_CTRLLEFT; |
| 289 | | break; |
| 290 | | case Qt::Key_Right: |
| 291 | | keyPress = DCH_RIGHT; |
| 292 | | if (ctrlDown) keyPress = DCH_CTRLRIGHT; |
| 293 | | break; |
| 294 | | case Qt::Key_PageUp: |
| 295 | | keyPress = DCH_PUP; |
| 296 | | break; |
| 297 | | case Qt::Key_PageDown: |
| 298 | | keyPress = DCH_PDOWN; |
| 299 | | break; |
| 300 | | case Qt::Key_Home: |
| 301 | | keyPress = DCH_HOME; |
| 302 | | if (ctrlDown) keyPress = DCH_CTRLHOME; |
| 303 | | break; |
| 304 | | case Qt::Key_End: |
| 305 | | keyPress = DCH_END; |
| 306 | | if (ctrlDown) keyPress = DCH_CTRLEND; |
| 307 | | break; |
| 308 | | case Qt::Key_0: keyPress = '0'; break; |
| 309 | | case Qt::Key_1: keyPress = '1'; break; |
| 310 | | case Qt::Key_2: keyPress = '2'; break; |
| 311 | | case Qt::Key_3: keyPress = '3'; break; |
| 312 | | case Qt::Key_4: keyPress = '4'; break; |
| 313 | | case Qt::Key_5: keyPress = '5'; break; |
| 314 | | case Qt::Key_6: keyPress = '6'; break; |
| 315 | | case Qt::Key_7: keyPress = '7'; break; |
| 316 | | case Qt::Key_8: keyPress = '8'; break; |
| 317 | | case Qt::Key_9: keyPress = '9'; break; |
| 318 | | case Qt::Key_A: keyPress = 'a'; break; |
| 319 | | case Qt::Key_B: keyPress = 'b'; break; |
| 320 | | case Qt::Key_C: keyPress = 'c'; break; |
| 321 | | case Qt::Key_D: keyPress = 'd'; break; |
| 322 | | case Qt::Key_E: keyPress = 'e'; break; |
| 323 | | case Qt::Key_F: keyPress = 'f'; break; |
| 324 | | default: |
| 325 | | return QWidget::keyPressEvent(event); |
| 326 | | } |
| 327 | | |
| 328 | | m_view->set_cursor_visible(true); |
| 329 | | m_view->process_char(keyPress); |
| 330 | | |
| 331 | | // Catch the view up with the cursor |
| 332 | | verticalScrollBar()->setValue(m_view->visible_position().y); |
| 333 | | |
| 334 | | viewport()->update(); |
| 335 | | update(); |
| 336 | | } |
| 337 | | |
| 338 | | |
| 339 | | void DebuggerView::mousePressEvent(QMouseEvent* event) |
| 340 | | { |
| 341 | | if (m_view == NULL) |
| 342 | | return; |
| 343 | | |
| 344 | | if (event->button() == Qt::LeftButton) |
| 345 | | { |
| 346 | | QFontMetrics actualFont = fontMetrics(); |
| 347 | | const double fontWidth = actualFont.width(QString(100, '_')) / 100.; |
| 348 | | const int fontHeight = MAX(1, actualFont.height()); |
| 349 | | |
| 350 | | debug_view_xy topLeft = m_view->visible_position(); |
| 351 | | debug_view_xy clickViewPosition; |
| 352 | | clickViewPosition.x = topLeft.x + (event->x() / fontWidth); |
| 353 | | clickViewPosition.y = topLeft.y + (event->y() / fontHeight); |
| 354 | | m_view->process_click(DCK_LEFT_CLICK, clickViewPosition); |
| 355 | | |
| 356 | | viewport()->update(); |
| 357 | | update(); |
| 358 | | } |
| 359 | | } |
| 360 | | |
| 361 | | |
| 362 | | void DebuggerView::verticalScrollSlot(int value) |
| 363 | | { |
| 364 | | m_view->set_visible_position(debug_view_xy(horizontalScrollBar()->value(), value)); |
| 365 | | } |
| 366 | | |
| 367 | | |
| 368 | | void DebuggerView::horizontalScrollSlot(int value) |
| 369 | | { |
| 370 | | m_view->set_visible_position(debug_view_xy(value, verticalScrollBar()->value())); |
| 371 | | } |
| 372 | | |
| 373 | | |
| 374 | | void DebuggerView::debuggerViewUpdate(debug_view& debugView, void* osdPrivate) |
| 375 | | { |
| 376 | | // Get a handle to the DebuggerView being updated & redraw |
| 377 | | DebuggerView* dView = (DebuggerView*)osdPrivate; |
| 378 | | dView->verticalScrollBar()->setValue(dView->view()->visible_position().y); |
| 379 | | dView->horizontalScrollBar()->setValue(dView->view()->visible_position().x); |
| 380 | | dView->viewport()->update(); |
| 381 | | dView->update(); |
| 382 | | } |
trunk/src/osd/modules/debugger/qt/debugqtbreakpointswindow.c
| r0 | r243602 | |
| 1 | #define NO_MEM_TRACKING |
| 2 | |
| 3 | #include "debugqtbreakpointswindow.h" |
| 4 | |
| 5 | #include "debug/debugcon.h" |
| 6 | #include "debug/debugcpu.h" |
| 7 | #include "debug/dvbpoints.h" |
| 8 | #include "debug/dvwpoints.h" |
| 9 | |
| 10 | |
| 11 | BreakpointsWindow::BreakpointsWindow(running_machine* machine, QWidget* parent) : |
| 12 | WindowQt(machine, NULL) |
| 13 | { |
| 14 | setWindowTitle("Debug: All Breakpoints"); |
| 15 | |
| 16 | if (parent != NULL) |
| 17 | { |
| 18 | QPoint parentPos = parent->pos(); |
| 19 | setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400); |
| 20 | } |
| 21 | |
| 22 | // |
| 23 | // The main frame and its input and breakpoints widgets |
| 24 | // |
| 25 | QFrame* mainWindowFrame = new QFrame(this); |
| 26 | |
| 27 | // The main breakpoints view |
| 28 | m_breakpointsView = new DebuggerView(DVT_BREAK_POINTS, m_machine, this); |
| 29 | |
| 30 | // Layout |
| 31 | QVBoxLayout* vLayout = new QVBoxLayout(mainWindowFrame); |
| 32 | vLayout->setObjectName("vlayout"); |
| 33 | vLayout->setSpacing(3); |
| 34 | vLayout->setContentsMargins(2,2,2,2); |
| 35 | vLayout->addWidget(m_breakpointsView); |
| 36 | |
| 37 | setCentralWidget(mainWindowFrame); |
| 38 | |
| 39 | // |
| 40 | // Menu bars |
| 41 | // |
| 42 | QActionGroup* typeGroup = new QActionGroup(this); |
| 43 | typeGroup->setObjectName("typegroup"); |
| 44 | QAction* typeBreak = new QAction("Breakpoints", this); |
| 45 | typeBreak->setObjectName("typebreak"); |
| 46 | QAction* typeWatch = new QAction("Watchpoints", this); |
| 47 | typeWatch->setObjectName("typewatch"); |
| 48 | typeBreak->setCheckable(true); |
| 49 | typeWatch->setCheckable(true); |
| 50 | typeBreak->setActionGroup(typeGroup); |
| 51 | typeWatch->setActionGroup(typeGroup); |
| 52 | typeBreak->setShortcut(QKeySequence("Ctrl+1")); |
| 53 | typeWatch->setShortcut(QKeySequence("Ctrl+2")); |
| 54 | typeBreak->setChecked(true); |
| 55 | connect(typeGroup, SIGNAL(triggered(QAction*)), this, SLOT(typeChanged(QAction*))); |
| 56 | |
| 57 | // Assemble the options menu |
| 58 | QMenu* optionsMenu = menuBar()->addMenu("&Options"); |
| 59 | optionsMenu->addActions(typeGroup->actions()); |
| 60 | } |
| 61 | |
| 62 | |
| 63 | BreakpointsWindow::~BreakpointsWindow() |
| 64 | { |
| 65 | } |
| 66 | |
| 67 | |
| 68 | void BreakpointsWindow::typeChanged(QAction* changedTo) |
| 69 | { |
| 70 | // Clean |
| 71 | delete m_breakpointsView; |
| 72 | m_breakpointsView = NULL; |
| 73 | |
| 74 | // Create |
| 75 | if (changedTo->text() == "Breakpoints") |
| 76 | { |
| 77 | m_breakpointsView = new DebuggerView(DVT_BREAK_POINTS, m_machine, this); |
| 78 | setWindowTitle("Debug: All Breakpoints"); |
| 79 | } |
| 80 | else if (changedTo->text() == "Watchpoints") |
| 81 | { |
| 82 | m_breakpointsView = new DebuggerView(DVT_WATCH_POINTS, m_machine, this); |
| 83 | setWindowTitle("Debug: All Watchpoints"); |
| 84 | } |
| 85 | |
| 86 | // Re-register |
| 87 | QVBoxLayout* layout = findChild<QVBoxLayout*>("vlayout"); |
| 88 | layout->addWidget(m_breakpointsView); |
| 89 | } |
| 90 | |
| 91 | |
| 92 | |
| 93 | //========================================================================= |
| 94 | // BreakpointsWindowQtConfig |
| 95 | //========================================================================= |
| 96 | void BreakpointsWindowQtConfig::buildFromQWidget(QWidget* widget) |
| 97 | { |
| 98 | WindowQtConfig::buildFromQWidget(widget); |
| 99 | BreakpointsWindow* window = dynamic_cast<BreakpointsWindow*>(widget); |
| 100 | |
| 101 | QActionGroup* typeGroup = window->findChild<QActionGroup*>("typegroup"); |
| 102 | if (typeGroup->checkedAction()->text() == "Breakpoints") |
| 103 | m_bwType = 0; |
| 104 | else if (typeGroup->checkedAction()->text() == "Watchpoints") |
| 105 | m_bwType = 1; |
| 106 | } |
| 107 | |
| 108 | |
| 109 | void BreakpointsWindowQtConfig::applyToQWidget(QWidget* widget) |
| 110 | { |
| 111 | WindowQtConfig::applyToQWidget(widget); |
| 112 | BreakpointsWindow* window = dynamic_cast<BreakpointsWindow*>(widget); |
| 113 | |
| 114 | QActionGroup* typeGroup = window->findChild<QActionGroup*>("typegroup"); |
| 115 | typeGroup->actions()[m_bwType]->trigger(); |
| 116 | } |
| 117 | |
| 118 | |
| 119 | void BreakpointsWindowQtConfig::addToXmlDataNode(xml_data_node* node) const |
| 120 | { |
| 121 | WindowQtConfig::addToXmlDataNode(node); |
| 122 | xml_set_attribute_int(node, "bwtype", m_bwType); |
| 123 | } |
| 124 | |
| 125 | |
| 126 | void BreakpointsWindowQtConfig::recoverFromXmlNode(xml_data_node* node) |
| 127 | { |
| 128 | WindowQtConfig::recoverFromXmlNode(node); |
| 129 | m_bwType = xml_get_attribute_int(node, "bwtype", m_bwType); |
| 130 | } |
trunk/src/osd/modules/debugger/qt/debugqtdasmwindow.c
| r0 | r243602 | |
| 1 | #define NO_MEM_TRACKING |
| 2 | |
| 3 | #include "debugqtdasmwindow.h" |
| 4 | |
| 5 | #include "debug/debugcon.h" |
| 6 | #include "debug/debugcpu.h" |
| 7 | #include "debug/dvdisasm.h" |
| 8 | |
| 9 | |
| 10 | DasmWindow::DasmWindow(running_machine* machine, QWidget* parent) : |
| 11 | WindowQt(machine, NULL) |
| 12 | { |
| 13 | setWindowTitle("Debug: Disassembly View"); |
| 14 | |
| 15 | if (parent != NULL) |
| 16 | { |
| 17 | QPoint parentPos = parent->pos(); |
| 18 | setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400); |
| 19 | } |
| 20 | |
| 21 | // |
| 22 | // The main frame and its input and log widgets |
| 23 | // |
| 24 | QFrame* mainWindowFrame = new QFrame(this); |
| 25 | |
| 26 | // The top frame & groupbox that contains the input widgets |
| 27 | QFrame* topSubFrame = new QFrame(mainWindowFrame); |
| 28 | |
| 29 | // The input edit |
| 30 | m_inputEdit = new QLineEdit(topSubFrame); |
| 31 | connect(m_inputEdit, SIGNAL(returnPressed()), this, SLOT(expressionSubmitted())); |
| 32 | |
| 33 | // The cpu combo box |
| 34 | m_cpuComboBox = new QComboBox(topSubFrame); |
| 35 | m_cpuComboBox->setObjectName("cpu"); |
| 36 | m_cpuComboBox->setMinimumWidth(300); |
| 37 | connect(m_cpuComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(cpuChanged(int))); |
| 38 | |
| 39 | // The main disasm window |
| 40 | m_dasmView = new DebuggerView(DVT_DISASSEMBLY, |
| 41 | m_machine, |
| 42 | this); |
| 43 | |
| 44 | // Force a recompute of the disassembly region |
| 45 | downcast<debug_view_disasm*>(m_dasmView->view())->set_expression("curpc"); |
| 46 | |
| 47 | // Populate the combo box & set the proper cpu |
| 48 | populateComboBox(); |
| 49 | //const debug_view_source *source = mem->views[0]->view->source_for_device(curcpu); |
| 50 | //gtk_combo_box_set_active(zone_w, mem->views[0]->view->source_list().indexof(*source)); |
| 51 | //mem->views[0]->view->set_source(*source); |
| 52 | |
| 53 | |
| 54 | // Layout |
| 55 | QHBoxLayout* subLayout = new QHBoxLayout(topSubFrame); |
| 56 | subLayout->addWidget(m_inputEdit); |
| 57 | subLayout->addWidget(m_cpuComboBox); |
| 58 | subLayout->setSpacing(3); |
| 59 | subLayout->setContentsMargins(2,2,2,2); |
| 60 | |
| 61 | QVBoxLayout* vLayout = new QVBoxLayout(mainWindowFrame); |
| 62 | vLayout->setSpacing(3); |
| 63 | vLayout->setContentsMargins(2,2,2,2); |
| 64 | vLayout->addWidget(topSubFrame); |
| 65 | vLayout->addWidget(m_dasmView); |
| 66 | |
| 67 | setCentralWidget(mainWindowFrame); |
| 68 | |
| 69 | // |
| 70 | // Menu bars |
| 71 | // |
| 72 | // Create two commands |
| 73 | QAction* breakpointSetAct = new QAction("Toggle Breakpoint At Cursor", this); |
| 74 | QAction* runToCursorAct = new QAction("Run To Cursor", this); |
| 75 | breakpointSetAct->setShortcut(Qt::Key_F9); |
| 76 | runToCursorAct->setShortcut(Qt::Key_F4); |
| 77 | connect(breakpointSetAct, SIGNAL(triggered(bool)), this, SLOT(toggleBreakpointAtCursor(bool))); |
| 78 | connect(runToCursorAct, SIGNAL(triggered(bool)), this, SLOT(runToCursor(bool))); |
| 79 | |
| 80 | // Right bar options |
| 81 | QActionGroup* rightBarGroup = new QActionGroup(this); |
| 82 | rightBarGroup->setObjectName("rightbargroup"); |
| 83 | QAction* rightActRaw = new QAction("Raw Opcodes", this); |
| 84 | QAction* rightActEncrypted = new QAction("Encrypted Opcodes", this); |
| 85 | QAction* rightActComments = new QAction("Comments", this); |
| 86 | rightActRaw->setCheckable(true); |
| 87 | rightActEncrypted->setCheckable(true); |
| 88 | rightActComments->setCheckable(true); |
| 89 | rightActRaw->setActionGroup(rightBarGroup); |
| 90 | rightActEncrypted->setActionGroup(rightBarGroup); |
| 91 | rightActComments->setActionGroup(rightBarGroup); |
| 92 | rightActRaw->setShortcut(QKeySequence("Ctrl+R")); |
| 93 | rightActEncrypted->setShortcut(QKeySequence("Ctrl+E")); |
| 94 | rightActComments->setShortcut(QKeySequence("Ctrl+C")); |
| 95 | rightActRaw->setChecked(true); |
| 96 | connect(rightBarGroup, SIGNAL(triggered(QAction*)), this, SLOT(rightBarChanged(QAction*))); |
| 97 | |
| 98 | // Assemble the options menu |
| 99 | QMenu* optionsMenu = menuBar()->addMenu("&Options"); |
| 100 | optionsMenu->addAction(breakpointSetAct); |
| 101 | optionsMenu->addAction(runToCursorAct); |
| 102 | optionsMenu->addSeparator(); |
| 103 | optionsMenu->addActions(rightBarGroup->actions()); |
| 104 | } |
| 105 | |
| 106 | |
| 107 | DasmWindow::~DasmWindow() |
| 108 | { |
| 109 | } |
| 110 | |
| 111 | |
| 112 | void DasmWindow::cpuChanged(int index) |
| 113 | { |
| 114 | m_dasmView->view()->set_source(*m_dasmView->view()->source_list().find(index)); |
| 115 | m_dasmView->viewport()->update(); |
| 116 | } |
| 117 | |
| 118 | |
| 119 | void DasmWindow::expressionSubmitted() |
| 120 | { |
| 121 | const QString expression = m_inputEdit->text(); |
| 122 | downcast<debug_view_disasm*>(m_dasmView->view())->set_expression(expression.toLocal8Bit().data()); |
| 123 | m_dasmView->viewport()->update(); |
| 124 | } |
| 125 | |
| 126 | |
| 127 | void DasmWindow::toggleBreakpointAtCursor(bool changedTo) |
| 128 | { |
| 129 | if (m_dasmView->view()->cursor_visible()) |
| 130 | { |
| 131 | if (debug_cpu_get_visible_cpu(*m_machine) == m_dasmView->view()->source()->device()) |
| 132 | { |
| 133 | offs_t address = downcast<debug_view_disasm *>(m_dasmView->view())->selected_address(); |
| 134 | device_debug *cpuinfo = m_dasmView->view()->source()->device()->debug(); |
| 135 | |
| 136 | // Find an existing breakpoint at this address |
| 137 | INT32 bpindex = -1; |
| 138 | for (device_debug::breakpoint* bp = cpuinfo->breakpoint_first(); |
| 139 | bp != NULL; |
| 140 | bp = bp->next()) |
| 141 | { |
| 142 | if (address == bp->address()) |
| 143 | { |
| 144 | bpindex = bp->index(); |
| 145 | break; |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | // If none exists, add a new one |
| 150 | astring command; |
| 151 | if (bpindex == -1) |
| 152 | { |
| 153 | command.printf("bpset 0x%X", address); |
| 154 | } |
| 155 | else |
| 156 | { |
| 157 | command.printf("bpclear 0x%X", bpindex); |
| 158 | } |
| 159 | debug_console_execute_command(*m_machine, command, 1); |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | refreshAll(); |
| 164 | } |
| 165 | |
| 166 | |
| 167 | void DasmWindow::runToCursor(bool changedTo) |
| 168 | { |
| 169 | if (m_dasmView->view()->cursor_visible()) |
| 170 | { |
| 171 | if (debug_cpu_get_visible_cpu(*m_machine) == m_dasmView->view()->source()->device()) |
| 172 | { |
| 173 | offs_t address = downcast<debug_view_disasm*>(m_dasmView->view())->selected_address(); |
| 174 | astring command; |
| 175 | command.printf("go 0x%X", address); |
| 176 | debug_console_execute_command(*m_machine, command, 1); |
| 177 | } |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | |
| 182 | void DasmWindow::rightBarChanged(QAction* changedTo) |
| 183 | { |
| 184 | debug_view_disasm* dasmView = downcast<debug_view_disasm*>(m_dasmView->view()); |
| 185 | if (changedTo->text() == "Raw Opcodes") |
| 186 | { |
| 187 | dasmView->set_right_column(DASM_RIGHTCOL_RAW); |
| 188 | } |
| 189 | else if (changedTo->text() == "Encrypted Opcodes") |
| 190 | { |
| 191 | dasmView->set_right_column(DASM_RIGHTCOL_ENCRYPTED); |
| 192 | } |
| 193 | else if (changedTo->text() == "Comments") |
| 194 | { |
| 195 | dasmView->set_right_column(DASM_RIGHTCOL_COMMENTS); |
| 196 | } |
| 197 | m_dasmView->viewport()->update(); |
| 198 | } |
| 199 | |
| 200 | |
| 201 | void DasmWindow::populateComboBox() |
| 202 | { |
| 203 | if (m_dasmView == NULL) |
| 204 | return; |
| 205 | |
| 206 | m_cpuComboBox->clear(); |
| 207 | for (const debug_view_source* source = m_dasmView->view()->first_source(); |
| 208 | source != NULL; |
| 209 | source = source->next()) |
| 210 | { |
| 211 | m_cpuComboBox->addItem(source->name()); |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | |
| 216 | //========================================================================= |
| 217 | // DasmWindowQtConfig |
| 218 | //========================================================================= |
| 219 | void DasmWindowQtConfig::buildFromQWidget(QWidget* widget) |
| 220 | { |
| 221 | WindowQtConfig::buildFromQWidget(widget); |
| 222 | DasmWindow* window = dynamic_cast<DasmWindow*>(widget); |
| 223 | QComboBox* cpu = window->findChild<QComboBox*>("cpu"); |
| 224 | m_cpu = cpu->currentIndex(); |
| 225 | |
| 226 | QActionGroup* rightBarGroup = window->findChild<QActionGroup*>("rightbargroup"); |
| 227 | if (rightBarGroup->checkedAction()->text() == "Raw Opcodes") |
| 228 | m_rightBar = 0; |
| 229 | else if (rightBarGroup->checkedAction()->text() == "Encrypted Opcodes") |
| 230 | m_rightBar = 1; |
| 231 | else if (rightBarGroup->checkedAction()->text() == "Comments") |
| 232 | m_rightBar = 2; |
| 233 | } |
| 234 | |
| 235 | void DasmWindowQtConfig::applyToQWidget(QWidget* widget) |
| 236 | { |
| 237 | WindowQtConfig::applyToQWidget(widget); |
| 238 | DasmWindow* window = dynamic_cast<DasmWindow*>(widget); |
| 239 | QComboBox* cpu = window->findChild<QComboBox*>("cpu"); |
| 240 | cpu->setCurrentIndex(m_cpu); |
| 241 | |
| 242 | QActionGroup* rightBarGroup = window->findChild<QActionGroup*>("rightbargroup"); |
| 243 | rightBarGroup->actions()[m_rightBar]->trigger(); |
| 244 | } |
| 245 | |
| 246 | void DasmWindowQtConfig::addToXmlDataNode(xml_data_node* node) const |
| 247 | { |
| 248 | WindowQtConfig::addToXmlDataNode(node); |
| 249 | xml_set_attribute_int(node, "cpu", m_cpu); |
| 250 | xml_set_attribute_int(node, "rightbar", m_rightBar); |
| 251 | } |
| 252 | |
| 253 | void DasmWindowQtConfig::recoverFromXmlNode(xml_data_node* node) |
| 254 | { |
| 255 | WindowQtConfig::recoverFromXmlNode(node); |
| 256 | m_cpu = xml_get_attribute_int(node, "cpu", m_cpu); |
| 257 | m_rightBar = xml_get_attribute_int(node, "rightbar", m_rightBar); |
| 258 | } |
trunk/src/osd/modules/debugger/qt/debugqtdeviceinformationwindow.c
| r0 | r243602 | |
| 1 | #define NO_MEM_TRACKING |
| 2 | |
| 3 | #include "debugqtdeviceinformationwindow.h" |
| 4 | |
| 5 | |
| 6 | DeviceInformationWindow::DeviceInformationWindow(running_machine* machine, device_t* device, QWidget* parent) : |
| 7 | WindowQt(machine, NULL) |
| 8 | { |
| 9 | m_device = device; |
| 10 | |
| 11 | if (parent != NULL) |
| 12 | { |
| 13 | QPoint parentPos = parent->pos(); |
| 14 | setGeometry(parentPos.x()+100, parentPos.y()+100, 600, 400); |
| 15 | } |
| 16 | |
| 17 | if(m_device) |
| 18 | fill_device_information(); |
| 19 | } |
| 20 | |
| 21 | |
| 22 | DeviceInformationWindow::~DeviceInformationWindow() |
| 23 | { |
| 24 | } |
| 25 | |
| 26 | void DeviceInformationWindow::fill_device_information() |
| 27 | { |
| 28 | char title[4069]; |
| 29 | sprintf(title, "Debug: Device %s", m_device->tag()); |
| 30 | setWindowTitle(title); |
| 31 | |
| 32 | |
| 33 | QFrame *mainWindowFrame = new QFrame(this); |
| 34 | QVBoxLayout *vLayout = new QVBoxLayout(mainWindowFrame); |
| 35 | vLayout->setObjectName("vlayout"); |
| 36 | vLayout->setSpacing(3); |
| 37 | vLayout->setContentsMargins(2,2,2,2); |
| 38 | |
| 39 | QFrame *primaryFrame = new QFrame(mainWindowFrame); |
| 40 | primaryFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); |
| 41 | QGridLayout *gl1 = new QGridLayout(primaryFrame); |
| 42 | gl1->addWidget(new QLabel(QString("Tag"), primaryFrame), 0, 0); |
| 43 | gl1->addWidget(new QLabel(QString(m_device->tag()), primaryFrame), 0, 1); |
| 44 | gl1->addWidget(new QLabel(QString("Name"), primaryFrame), 1, 0); |
| 45 | gl1->addWidget(new QLabel(QString(m_device->name()), primaryFrame), 1, 1); |
| 46 | gl1->addWidget(new QLabel(QString("Shortname"), primaryFrame), 2, 0); |
| 47 | gl1->addWidget(new QLabel(QString(m_device->shortname()), primaryFrame), 2, 1); |
| 48 | |
| 49 | int cpos = 3; |
| 50 | device_interface *intf = m_device->first_interface(); |
| 51 | if(intf) { |
| 52 | gl1->addWidget(new QLabel(QString("Interfaces"), primaryFrame), cpos, 0); |
| 53 | while(intf) { |
| 54 | gl1->addWidget(new QLabel(QString(intf->interface_type()), primaryFrame), cpos, 1); |
| 55 | cpos++; |
| 56 | intf = intf->interface_next(); |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | vLayout->addWidget(primaryFrame); |
| 61 | |
| 62 | device_memory_interface *d_memory; |
| 63 | if(m_device->interface(d_memory)) { |
| 64 | QFrame *f = new QFrame(mainWindowFrame); |
| 65 | f->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); |
| 66 | QVBoxLayout *vb = new QVBoxLayout(f); |
| 67 | bool first = true; |
| 68 | for(address_spacenum i=AS_0; i<ADDRESS_SPACES; i++) |
| 69 | if(d_memory->has_space(i)) { |
| 70 | QFrame *ff = new QFrame(f); |
| 71 | QHBoxLayout *hb = new QHBoxLayout(ff); |
| 72 | if(first) { |
| 73 | hb->addWidget(new QLabel("Memory maps")); |
| 74 | first = false; |
| 75 | } |
| 76 | hb->addStretch(); |
| 77 | hb->addWidget(new QLabel(d_memory->space_config(i)->name())); |
| 78 | vb->addWidget(ff); |
| 79 | } |
| 80 | vLayout->addWidget(f); |
| 81 | } |
| 82 | |
| 83 | vLayout->addStretch(); |
| 84 | |
| 85 | setCentralWidget(mainWindowFrame); |
| 86 | } |
| 87 | |
| 88 | void DeviceInformationWindow::set_device(const char *tag) |
| 89 | { |
| 90 | m_device = m_machine->device(tag); |
| 91 | if(!m_device) |
| 92 | m_device = &m_machine->root_device(); |
| 93 | fill_device_information(); |
| 94 | } |
| 95 | |
| 96 | const char *DeviceInformationWindow::device_tag() const |
| 97 | { |
| 98 | return m_device->tag(); |
| 99 | } |
| 100 | |
| 101 | |
| 102 | //========================================================================= |
| 103 | // DeviceInformationWindowQtConfig |
| 104 | //========================================================================= |
| 105 | void DeviceInformationWindowQtConfig::buildFromQWidget(QWidget* widget) |
| 106 | { |
| 107 | WindowQtConfig::buildFromQWidget(widget); |
| 108 | DeviceInformationWindow* window = dynamic_cast<DeviceInformationWindow*>(widget); |
| 109 | m_device_tag = window->device_tag(); |
| 110 | } |
| 111 | |
| 112 | |
| 113 | void DeviceInformationWindowQtConfig::applyToQWidget(QWidget* widget) |
| 114 | { |
| 115 | WindowQtConfig::applyToQWidget(widget); |
| 116 | DeviceInformationWindow* window = dynamic_cast<DeviceInformationWindow*>(widget); |
| 117 | window->set_device(m_device_tag.cstr()); |
| 118 | } |
| 119 | |
| 120 | |
| 121 | void DeviceInformationWindowQtConfig::addToXmlDataNode(xml_data_node* node) const |
| 122 | { |
| 123 | WindowQtConfig::addToXmlDataNode(node); |
| 124 | xml_set_attribute(node, "device-tag", m_device_tag); |
| 125 | } |
| 126 | |
| 127 | |
| 128 | void DeviceInformationWindowQtConfig::recoverFromXmlNode(xml_data_node* node) |
| 129 | { |
| 130 | WindowQtConfig::recoverFromXmlNode(node); |
| 131 | m_device_tag = xml_get_attribute_string(node, "device-tag", ":"); |
| 132 | } |
trunk/src/osd/modules/debugger/qt/debugqtdeviceswindow.c
| r0 | r243602 | |
| 1 | #define NO_MEM_TRACKING |
| 2 | |
| 3 | #include "debugqtdeviceswindow.h" |
| 4 | #include "debugqtdeviceinformationwindow.h" |
| 5 | |
| 6 | DevicesWindowModel::DevicesWindowModel(running_machine *machine, QObject *parent) |
| 7 | { |
| 8 | m_machine = machine; |
| 9 | } |
| 10 | |
| 11 | DevicesWindowModel::~DevicesWindowModel() |
| 12 | { |
| 13 | } |
| 14 | |
| 15 | QVariant DevicesWindowModel::data(const QModelIndex &index, int role) const |
| 16 | { |
| 17 | if(!index.isValid() || role != Qt::DisplayRole) |
| 18 | return QVariant(); |
| 19 | |
| 20 | device_t *dev = static_cast<device_t *>(index.internalPointer()); |
| 21 | switch(index.column()) { |
| 22 | case 0: return dev == &m_machine->root_device() ? QString("<root>") : QString(dev->basetag()); |
| 23 | case 1: return QString(dev->name()); |
| 24 | } |
| 25 | |
| 26 | return QVariant(); |
| 27 | } |
| 28 | |
| 29 | Qt::ItemFlags DevicesWindowModel::flags(const QModelIndex &index) const |
| 30 | { |
| 31 | if(!index.isValid()) |
| 32 | return 0; |
| 33 | |
| 34 | return QAbstractItemModel::flags(index); |
| 35 | } |
| 36 | |
| 37 | QVariant DevicesWindowModel::headerData(int section, Qt::Orientation orientation, int role) const |
| 38 | { |
| 39 | if(role != Qt::DisplayRole || section < 0 || section >= 2) |
| 40 | return QVariant(); |
| 41 | return QString(section ? "Name" : "Tag"); |
| 42 | } |
| 43 | |
| 44 | QModelIndex DevicesWindowModel::index(int row, int column, const QModelIndex &parent) const |
| 45 | { |
| 46 | if(!hasIndex(row, column, parent)) |
| 47 | return QModelIndex(); |
| 48 | |
| 49 | device_t *target = NULL; |
| 50 | |
| 51 | if(!parent.isValid()) { |
| 52 | if(row == 0) |
| 53 | target = &m_machine->root_device(); |
| 54 | |
| 55 | } else { |
| 56 | device_t *dparent = static_cast<device_t *>(parent.internalPointer()); |
| 57 | int count = row; |
| 58 | for(target = dparent->first_subdevice(); count && target; target = target->next()) |
| 59 | count--; |
| 60 | } |
| 61 | |
| 62 | if(target) |
| 63 | return createIndex(row, column, target); |
| 64 | |
| 65 | return QModelIndex(); |
| 66 | } |
| 67 | |
| 68 | QModelIndex DevicesWindowModel::parent(const QModelIndex &index) const |
| 69 | { |
| 70 | if(!index.isValid()) |
| 71 | return QModelIndex(); |
| 72 | |
| 73 | device_t *dchild = static_cast<device_t *>(index.internalPointer()); |
| 74 | device_t *dparent = dchild->owner(); |
| 75 | |
| 76 | if(!dparent) |
| 77 | return QModelIndex(); |
| 78 | |
| 79 | device_t *dpp = dparent->owner(); |
| 80 | int row = 0; |
| 81 | if(dpp) { |
| 82 | for(device_t *child = dpp->first_subdevice(); child && child != dparent; child = child->next()) |
| 83 | row++; |
| 84 | } |
| 85 | return createIndex(row, 0, dparent); |
| 86 | } |
| 87 | |
| 88 | int DevicesWindowModel::rowCount(const QModelIndex &parent) const |
| 89 | { |
| 90 | if(!parent.isValid()) |
| 91 | return 1; |
| 92 | |
| 93 | device_t *dparent = static_cast<device_t *>(parent.internalPointer()); |
| 94 | int count = 0; |
| 95 | for(device_t *child = dparent->first_subdevice(); child; child = child->next()) |
| 96 | count++; |
| 97 | |
| 98 | return count; |
| 99 | } |
| 100 | |
| 101 | int DevicesWindowModel::columnCount(const QModelIndex &parent) const |
| 102 | { |
| 103 | return 2; |
| 104 | } |
| 105 | |
| 106 | |
| 107 | |
| 108 | DevicesWindow::DevicesWindow(running_machine* machine, QWidget* parent) : |
| 109 | WindowQt(machine, NULL), |
| 110 | m_devices_model(machine) |
| 111 | { |
| 112 | m_selected_device = NULL; |
| 113 | |
| 114 | setWindowTitle("Debug: All Devices"); |
| 115 | |
| 116 | if (parent != NULL) |
| 117 | { |
| 118 | QPoint parentPos = parent->pos(); |
| 119 | setGeometry(parentPos.x()+100, parentPos.y()+100, 600, 400); |
| 120 | } |
| 121 | |
| 122 | // |
| 123 | // The tree widget |
| 124 | // |
| 125 | m_devices_view = new QTreeView(this); |
| 126 | m_devices_view->setModel(&m_devices_model); |
| 127 | m_devices_view->expandAll(); |
| 128 | m_devices_view->resizeColumnToContents(0); |
| 129 | connect(m_devices_view->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &,const QModelIndex &)), this, SLOT(currentRowChanged(const QModelIndex &,const QModelIndex &))); |
| 130 | connect(m_devices_view, SIGNAL(activated(const QModelIndex &)), this, SLOT(activated(const QModelIndex &))); |
| 131 | setCentralWidget(m_devices_view); |
| 132 | } |
| 133 | |
| 134 | |
| 135 | DevicesWindow::~DevicesWindow() |
| 136 | { |
| 137 | } |
| 138 | |
| 139 | |
| 140 | void DevicesWindow::currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous) |
| 141 | { |
| 142 | m_selected_device = static_cast<device_t *>(current.internalPointer()); |
| 143 | } |
| 144 | |
| 145 | |
| 146 | void DevicesWindow::activated(const QModelIndex &index) |
| 147 | { |
| 148 | device_t *dev = static_cast<device_t *>(index.internalPointer()); |
| 149 | (new DeviceInformationWindow(m_machine, dev, this))->show(); |
| 150 | } |
| 151 | |
| 152 | |
| 153 | |
| 154 | //========================================================================= |
| 155 | // DevicesWindowQtConfig |
| 156 | //========================================================================= |
| 157 | void DevicesWindowQtConfig::buildFromQWidget(QWidget* widget) |
| 158 | { |
| 159 | WindowQtConfig::buildFromQWidget(widget); |
| 160 | // DevicesWindow* window = dynamic_cast<DevicesWindow*>(widget); |
| 161 | } |
| 162 | |
| 163 | |
| 164 | void DevicesWindowQtConfig::applyToQWidget(QWidget* widget) |
| 165 | { |
| 166 | WindowQtConfig::applyToQWidget(widget); |
| 167 | // DevicesWindow* window = dynamic_cast<DevicesWindow*>(widget); |
| 168 | } |
| 169 | |
| 170 | |
| 171 | void DevicesWindowQtConfig::addToXmlDataNode(xml_data_node* node) const |
| 172 | { |
| 173 | WindowQtConfig::addToXmlDataNode(node); |
| 174 | } |
| 175 | |
| 176 | |
| 177 | void DevicesWindowQtConfig::recoverFromXmlNode(xml_data_node* node) |
| 178 | { |
| 179 | WindowQtConfig::recoverFromXmlNode(node); |
| 180 | } |
trunk/src/osd/modules/debugger/qt/debugqtmainwindow.c
| r0 | r243602 | |
| 1 | #define NO_MEM_TRACKING |
| 2 | |
| 3 | #include "debugqtmainwindow.h" |
| 4 | |
| 5 | #include "debug/debugcon.h" |
| 6 | #include "debug/debugcpu.h" |
| 7 | #include "debug/dvdisasm.h" |
| 8 | |
| 9 | |
| 10 | MainWindow::MainWindow(running_machine* machine, QWidget* parent) : |
| 11 | WindowQt(machine, NULL), |
| 12 | m_historyIndex(0), |
| 13 | m_inputHistory() |
| 14 | { |
| 15 | setGeometry(300, 300, 1000, 600); |
| 16 | |
| 17 | // |
| 18 | // The main frame and its input and log widgets |
| 19 | // |
| 20 | QFrame* mainWindowFrame = new QFrame(this); |
| 21 | |
| 22 | // The input line |
| 23 | m_inputEdit = new QLineEdit(mainWindowFrame); |
| 24 | connect(m_inputEdit, SIGNAL(returnPressed()), this, SLOT(executeCommand())); |
| 25 | m_inputEdit->installEventFilter(this); |
| 26 | |
| 27 | |
| 28 | // The log view |
| 29 | m_consoleView = new DebuggerView(DVT_CONSOLE, |
| 30 | m_machine, |
| 31 | mainWindowFrame); |
| 32 | m_consoleView->setFocusPolicy(Qt::NoFocus); |
| 33 | m_consoleView->setPreferBottom(true); |
| 34 | |
| 35 | QVBoxLayout* vLayout = new QVBoxLayout(mainWindowFrame); |
| 36 | vLayout->addWidget(m_consoleView); |
| 37 | vLayout->addWidget(m_inputEdit); |
| 38 | vLayout->setSpacing(3); |
| 39 | vLayout->setContentsMargins(4,0,4,2); |
| 40 | |
| 41 | setCentralWidget(mainWindowFrame); |
| 42 | |
| 43 | // |
| 44 | // Options Menu |
| 45 | // |
| 46 | // Create two commands |
| 47 | QAction* breakpointSetAct = new QAction("Toggle Breakpoint At Cursor", this); |
| 48 | QAction* runToCursorAct = new QAction("Run To Cursor", this); |
| 49 | breakpointSetAct->setShortcut(Qt::Key_F9); |
| 50 | runToCursorAct->setShortcut(Qt::Key_F4); |
| 51 | connect(breakpointSetAct, SIGNAL(triggered(bool)), this, SLOT(toggleBreakpointAtCursor(bool))); |
| 52 | connect(runToCursorAct, SIGNAL(triggered(bool)), this, SLOT(runToCursor(bool))); |
| 53 | |
| 54 | // Right bar options |
| 55 | QActionGroup* rightBarGroup = new QActionGroup(this); |
| 56 | rightBarGroup->setObjectName("rightbargroup"); |
| 57 | QAction* rightActRaw = new QAction("Raw Opcodes", this); |
| 58 | QAction* rightActEncrypted = new QAction("Encrypted Opcodes", this); |
| 59 | QAction* rightActComments = new QAction("Comments", this); |
| 60 | rightActRaw->setCheckable(true); |
| 61 | rightActEncrypted->setCheckable(true); |
| 62 | rightActComments->setCheckable(true); |
| 63 | rightActRaw->setActionGroup(rightBarGroup); |
| 64 | rightActEncrypted->setActionGroup(rightBarGroup); |
| 65 | rightActComments->setActionGroup(rightBarGroup); |
| 66 | rightActRaw->setShortcut(QKeySequence("Ctrl+R")); |
| 67 | rightActEncrypted->setShortcut(QKeySequence("Ctrl+E")); |
| 68 | rightActComments->setShortcut(QKeySequence("Ctrl+C")); |
| 69 | rightActRaw->setChecked(true); |
| 70 | connect(rightBarGroup, SIGNAL(triggered(QAction*)), this, SLOT(rightBarChanged(QAction*))); |
| 71 | |
| 72 | // Assemble the options menu |
| 73 | QMenu* optionsMenu = menuBar()->addMenu("&Options"); |
| 74 | optionsMenu->addAction(breakpointSetAct); |
| 75 | optionsMenu->addAction(runToCursorAct); |
| 76 | optionsMenu->addSeparator(); |
| 77 | optionsMenu->addActions(rightBarGroup->actions()); |
| 78 | |
| 79 | // |
| 80 | // Images menu |
| 81 | // |
| 82 | image_interface_iterator imageIterTest(m_machine->root_device()); |
| 83 | if (imageIterTest.first() != NULL) |
| 84 | { |
| 85 | createImagesMenu(); |
| 86 | } |
| 87 | |
| 88 | // |
| 89 | // Dock window menu |
| 90 | // |
| 91 | QMenu* dockMenu = menuBar()->addMenu("Doc&ks"); |
| 92 | |
| 93 | setCorner(Qt::TopRightCorner, Qt::TopDockWidgetArea); |
| 94 | setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); |
| 95 | |
| 96 | // The processor dock |
| 97 | QDockWidget* cpuDock = new QDockWidget("processor", this); |
| 98 | cpuDock->setObjectName("cpudock"); |
| 99 | cpuDock->setAllowedAreas(Qt::LeftDockWidgetArea); |
| 100 | m_procFrame = new ProcessorDockWidget(m_machine, cpuDock); |
| 101 | cpuDock->setWidget(dynamic_cast<QWidget*>(m_procFrame)); |
| 102 | |
| 103 | addDockWidget(Qt::LeftDockWidgetArea, cpuDock); |
| 104 | dockMenu->addAction(cpuDock->toggleViewAction()); |
| 105 | |
| 106 | // The disassembly dock |
| 107 | QDockWidget* dasmDock = new QDockWidget("dasm", this); |
| 108 | dasmDock->setObjectName("dasmdock"); |
| 109 | dasmDock->setAllowedAreas(Qt::TopDockWidgetArea); |
| 110 | m_dasmFrame = new DasmDockWidget(m_machine, dasmDock); |
| 111 | dasmDock->setWidget(m_dasmFrame); |
| 112 | |
| 113 | addDockWidget(Qt::TopDockWidgetArea, dasmDock); |
| 114 | dockMenu->addAction(dasmDock->toggleViewAction()); |
| 115 | } |
| 116 | |
| 117 | |
| 118 | MainWindow::~MainWindow() |
| 119 | { |
| 120 | } |
| 121 | |
| 122 | |
| 123 | void MainWindow::setProcessor(device_t* processor) |
| 124 | { |
| 125 | // Cpu swap |
| 126 | m_procFrame->view()->view()->set_source(*m_procFrame->view()->view()->source_for_device(processor)); |
| 127 | m_dasmFrame->view()->view()->set_source(*m_dasmFrame->view()->view()->source_for_device(processor)); |
| 128 | |
| 129 | // Scrollbar refresh - seems I should be able to do in the DebuggerView |
| 130 | m_dasmFrame->view()->verticalScrollBar()->setValue(m_dasmFrame->view()->view()->visible_position().y); |
| 131 | m_dasmFrame->view()->verticalScrollBar()->setValue(m_dasmFrame->view()->view()->visible_position().y); |
| 132 | |
| 133 | // Window title |
| 134 | astring title; |
| 135 | title.printf("Debug: %s - %s '%s'", m_machine->system().name, processor->name(), processor->tag()); |
| 136 | setWindowTitle(title.cstr()); |
| 137 | } |
| 138 | |
| 139 | |
| 140 | // Used to intercept the user clicking 'X' in the upper corner |
| 141 | void MainWindow::closeEvent(QCloseEvent* event) |
| 142 | { |
| 143 | debugActQuit(); |
| 144 | |
| 145 | // Insure the window doesn't disappear before we get a chance to save its parameters |
| 146 | event->ignore(); |
| 147 | } |
| 148 | |
| 149 | |
| 150 | // Used to intercept the user hitting the up arrow in the input widget |
| 151 | bool MainWindow::eventFilter(QObject* obj, QEvent* event) |
| 152 | { |
| 153 | // Only filter keypresses |
| 154 | QKeyEvent* keyEvent = NULL; |
| 155 | if (event->type() == QEvent::KeyPress) |
| 156 | { |
| 157 | keyEvent = static_cast<QKeyEvent*>(event); |
| 158 | } |
| 159 | else |
| 160 | { |
| 161 | return QObject::eventFilter(obj, event); |
| 162 | } |
| 163 | |
| 164 | // Catch up & down keys |
| 165 | if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down) |
| 166 | { |
| 167 | if (keyEvent->key() == Qt::Key_Up) |
| 168 | { |
| 169 | if (m_historyIndex > 0) |
| 170 | m_historyIndex--; |
| 171 | } |
| 172 | else if (keyEvent->key() == Qt::Key_Down) |
| 173 | { |
| 174 | if (m_historyIndex < m_inputHistory.size()) |
| 175 | m_historyIndex++; |
| 176 | } |
| 177 | |
| 178 | // Populate the input edit or clear it if you're at the end |
| 179 | if (m_historyIndex == m_inputHistory.size()) |
| 180 | { |
| 181 | m_inputEdit->setText(""); |
| 182 | } |
| 183 | else |
| 184 | { |
| 185 | m_inputEdit->setText(m_inputHistory[m_historyIndex]); |
| 186 | } |
| 187 | } |
| 188 | else if (keyEvent->key() == Qt::Key_Enter) |
| 189 | { |
| 190 | executeCommand(false); |
| 191 | } |
| 192 | else |
| 193 | { |
| 194 | return QObject::eventFilter(obj, event); |
| 195 | } |
| 196 | |
| 197 | return true; |
| 198 | } |
| 199 | |
| 200 | |
| 201 | void MainWindow::toggleBreakpointAtCursor(bool changedTo) |
| 202 | { |
| 203 | debug_view_disasm* dasmView = downcast<debug_view_disasm*>(m_dasmFrame->view()->view()); |
| 204 | if (dasmView->cursor_visible()) |
| 205 | { |
| 206 | if (debug_cpu_get_visible_cpu(*m_machine) == dasmView->source()->device()) |
| 207 | { |
| 208 | offs_t address = downcast<debug_view_disasm *>(dasmView)->selected_address(); |
| 209 | device_debug *cpuinfo = dasmView->source()->device()->debug(); |
| 210 | |
| 211 | // Find an existing breakpoint at this address |
| 212 | INT32 bpindex = -1; |
| 213 | for (device_debug::breakpoint* bp = cpuinfo->breakpoint_first(); |
| 214 | bp != NULL; |
| 215 | bp = bp->next()) |
| 216 | { |
| 217 | if (address == bp->address()) |
| 218 | { |
| 219 | bpindex = bp->index(); |
| 220 | break; |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | // If none exists, add a new one |
| 225 | astring command; |
| 226 | if (bpindex == -1) |
| 227 | { |
| 228 | command.printf("bpset 0x%X", address); |
| 229 | } |
| 230 | else |
| 231 | { |
| 232 | command.printf("bpclear 0x%X", bpindex); |
| 233 | } |
| 234 | debug_console_execute_command(*m_machine, command, 1); |
| 235 | } |
| 236 | } |
| 237 | |
| 238 | refreshAll(); |
| 239 | } |
| 240 | |
| 241 | |
| 242 | void MainWindow::runToCursor(bool changedTo) |
| 243 | { |
| 244 | debug_view_disasm* dasmView = downcast<debug_view_disasm*>(m_dasmFrame->view()->view()); |
| 245 | if (dasmView->cursor_visible()) |
| 246 | { |
| 247 | if (debug_cpu_get_visible_cpu(*m_machine) == dasmView->source()->device()) |
| 248 | { |
| 249 | offs_t address = downcast<debug_view_disasm*>(dasmView)->selected_address(); |
| 250 | astring command; |
| 251 | command.printf("go 0x%X", address); |
| 252 | debug_console_execute_command(*m_machine, command, 1); |
| 253 | } |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | |
| 258 | void MainWindow::rightBarChanged(QAction* changedTo) |
| 259 | { |
| 260 | debug_view_disasm* dasmView = downcast<debug_view_disasm*>(m_dasmFrame->view()->view()); |
| 261 | if (changedTo->text() == "Raw Opcodes") |
| 262 | { |
| 263 | dasmView->set_right_column(DASM_RIGHTCOL_RAW); |
| 264 | } |
| 265 | else if (changedTo->text() == "Encrypted Opcodes") |
| 266 | { |
| 267 | dasmView->set_right_column(DASM_RIGHTCOL_ENCRYPTED); |
| 268 | } |
| 269 | else if (changedTo->text() == "Comments") |
| 270 | { |
| 271 | dasmView->set_right_column(DASM_RIGHTCOL_COMMENTS); |
| 272 | } |
| 273 | m_dasmFrame->view()->viewport()->update(); |
| 274 | } |
| 275 | |
| 276 | |
| 277 | void MainWindow::executeCommand(bool withClear) |
| 278 | { |
| 279 | QString command = m_inputEdit->text(); |
| 280 | |
| 281 | // A blank command is a "silent step" |
| 282 | if (command == "") |
| 283 | { |
| 284 | debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step(); |
| 285 | return; |
| 286 | } |
| 287 | |
| 288 | // Send along the command |
| 289 | debug_console_execute_command(*m_machine, |
| 290 | command.toLocal8Bit().data(), |
| 291 | true); |
| 292 | |
| 293 | // Add history & set the index to be the top of the stack |
| 294 | addToHistory(command); |
| 295 | |
| 296 | // Clear out the text and reset the history pointer only if asked |
| 297 | if (withClear) |
| 298 | { |
| 299 | m_inputEdit->clear(); |
| 300 | m_historyIndex = m_inputHistory.size(); |
| 301 | } |
| 302 | |
| 303 | // Refresh |
| 304 | m_consoleView->viewport()->update(); |
| 305 | refreshAll(); |
| 306 | } |
| 307 | |
| 308 | |
| 309 | void MainWindow::mountImage(bool changedTo) |
| 310 | { |
| 311 | // The image interface index was assigned to the QAction's data memeber |
| 312 | const int imageIndex = dynamic_cast<QAction*>(sender())->data().toInt(); |
| 313 | image_interface_iterator iter(m_machine->root_device()); |
| 314 | device_image_interface *img = iter.byindex(imageIndex); |
| 315 | if (img == NULL) |
| 316 | { |
| 317 | debug_console_printf(*m_machine, "Something is wrong with the mount menu.\n"); |
| 318 | refreshAll(); |
| 319 | return; |
| 320 | } |
| 321 | |
| 322 | // File dialog |
| 323 | QString filename = QFileDialog::getOpenFileName(this, |
| 324 | "Select an image file", |
| 325 | QDir::currentPath(), |
| 326 | tr("All files (*.*)")); |
| 327 | |
| 328 | if (img->load(filename.toUtf8().data()) != IMAGE_INIT_PASS) |
| 329 | { |
| 330 | debug_console_printf(*m_machine, "Image could not be mounted.\n"); |
| 331 | refreshAll(); |
| 332 | return; |
| 333 | } |
| 334 | |
| 335 | // Activate the unmount menu option |
| 336 | QAction* unmountAct = sender()->parent()->findChild<QAction*>("unmount"); |
| 337 | unmountAct->setEnabled(true); |
| 338 | |
| 339 | // Set the mount name |
| 340 | QMenu* parentMenuItem = dynamic_cast<QMenu*>(sender()->parent()); |
| 341 | QString baseString = parentMenuItem->title(); |
| 342 | baseString.truncate(baseString.lastIndexOf(QString(" : "))); |
| 343 | const QString newTitle = baseString + QString(" : ") + QString(img->filename()); |
| 344 | parentMenuItem->setTitle(newTitle); |
| 345 | |
| 346 | debug_console_printf(*m_machine, "Image %s mounted successfully.\n", filename.toUtf8().data()); |
| 347 | refreshAll(); |
| 348 | } |
| 349 | |
| 350 | |
| 351 | void MainWindow::unmountImage(bool changedTo) |
| 352 | { |
| 353 | // The image interface index was assigned to the QAction's data memeber |
| 354 | const int imageIndex = dynamic_cast<QAction*>(sender())->data().toInt(); |
| 355 | image_interface_iterator iter(m_machine->root_device()); |
| 356 | device_image_interface *img = iter.byindex(imageIndex); |
| 357 | |
| 358 | img->unload(); |
| 359 | |
| 360 | // Deactivate the unmount menu option |
| 361 | dynamic_cast<QAction*>(sender())->setEnabled(false); |
| 362 | |
| 363 | // Set the mount name |
| 364 | QMenu* parentMenuItem = dynamic_cast<QMenu*>(sender()->parent()); |
| 365 | QString baseString = parentMenuItem->title(); |
| 366 | baseString.truncate(baseString.lastIndexOf(QString(" : "))); |
| 367 | const QString newTitle = baseString + QString(" : ") + QString("[empty slot]"); |
| 368 | parentMenuItem->setTitle(newTitle); |
| 369 | |
| 370 | debug_console_printf(*m_machine, "Image successfully unmounted.\n"); |
| 371 | refreshAll(); |
| 372 | } |
| 373 | |
| 374 | |
| 375 | void MainWindow::debugActClose() |
| 376 | { |
| 377 | m_machine->schedule_exit(); |
| 378 | } |
| 379 | |
| 380 | |
| 381 | void MainWindow::addToHistory(const QString& command) |
| 382 | { |
| 383 | if (command == "") |
| 384 | return; |
| 385 | |
| 386 | // Always push back when there is no previous history |
| 387 | if (m_inputHistory.size() == 0) |
| 388 | { |
| 389 | m_inputHistory.push_back(m_inputEdit->text()); |
| 390 | return; |
| 391 | } |
| 392 | |
| 393 | // If there is previous history, make sure it's not what you just executed |
| 394 | if (m_inputHistory.back() != m_inputEdit->text()) |
| 395 | { |
| 396 | m_inputHistory.push_back(m_inputEdit->text()); |
| 397 | } |
| 398 | } |
| 399 | |
| 400 | |
| 401 | void MainWindow::createImagesMenu() |
| 402 | { |
| 403 | QMenu* imagesMenu = menuBar()->addMenu("&Images"); |
| 404 | |
| 405 | int interfaceIndex = 0; |
| 406 | image_interface_iterator iter(m_machine->root_device()); |
| 407 | for (device_image_interface *img = iter.first(); img != NULL; img = iter.next()) |
| 408 | { |
| 409 | astring menuName; |
| 410 | menuName.format("%s : %s", img->device().name(), img->exists() ? img->filename() : "[empty slot]"); |
| 411 | |
| 412 | QMenu* interfaceMenu = imagesMenu->addMenu(menuName.cstr()); |
| 413 | interfaceMenu->setObjectName(img->device().name()); |
| 414 | |
| 415 | QAction* mountAct = new QAction("Mount...", interfaceMenu); |
| 416 | QAction* unmountAct = new QAction("Unmount", interfaceMenu); |
| 417 | mountAct->setObjectName("mount"); |
| 418 | mountAct->setData(QVariant(interfaceIndex)); |
| 419 | unmountAct->setObjectName("unmount"); |
| 420 | unmountAct->setData(QVariant(interfaceIndex)); |
| 421 | connect(mountAct, SIGNAL(triggered(bool)), this, SLOT(mountImage(bool))); |
| 422 | connect(unmountAct, SIGNAL(triggered(bool)), this, SLOT(unmountImage(bool))); |
| 423 | |
| 424 | if (!img->exists()) |
| 425 | unmountAct->setEnabled(false); |
| 426 | |
| 427 | interfaceMenu->addAction(mountAct); |
| 428 | interfaceMenu->addAction(unmountAct); |
| 429 | |
| 430 | // TODO: Cassette operations |
| 431 | |
| 432 | interfaceIndex++; |
| 433 | } |
| 434 | } |
| 435 | |
| 436 | |
| 437 | //========================================================================= |
| 438 | // MainWindowQtConfig |
| 439 | //========================================================================= |
| 440 | void MainWindowQtConfig::buildFromQWidget(QWidget* widget) |
| 441 | { |
| 442 | WindowQtConfig::buildFromQWidget(widget); |
| 443 | MainWindow* window = dynamic_cast<MainWindow*>(widget); |
| 444 | m_windowState = window->saveState(); |
| 445 | |
| 446 | QActionGroup* rightBarGroup = window->findChild<QActionGroup*>("rightbargroup"); |
| 447 | if (rightBarGroup->checkedAction()->text() == "Raw Opcodes") |
| 448 | m_rightBar = 0; |
| 449 | else if (rightBarGroup->checkedAction()->text() == "Encrypted Opcodes") |
| 450 | m_rightBar = 1; |
| 451 | else if (rightBarGroup->checkedAction()->text() == "Comments") |
| 452 | m_rightBar = 2; |
| 453 | } |
| 454 | |
| 455 | |
| 456 | void MainWindowQtConfig::applyToQWidget(QWidget* widget) |
| 457 | { |
| 458 | WindowQtConfig::applyToQWidget(widget); |
| 459 | MainWindow* window = dynamic_cast<MainWindow*>(widget); |
| 460 | window->restoreState(m_windowState); |
| 461 | |
| 462 | QActionGroup* rightBarGroup = window->findChild<QActionGroup*>("rightbargroup"); |
| 463 | rightBarGroup->actions()[m_rightBar]->trigger(); |
| 464 | } |
| 465 | |
| 466 | |
| 467 | void MainWindowQtConfig::addToXmlDataNode(xml_data_node* node) const |
| 468 | { |
| 469 | WindowQtConfig::addToXmlDataNode(node); |
| 470 | xml_set_attribute_int(node, "rightbar", m_rightBar); |
| 471 | xml_set_attribute(node, "qtwindowstate", m_windowState.toPercentEncoding().data()); |
| 472 | } |
| 473 | |
| 474 | |
| 475 | void MainWindowQtConfig::recoverFromXmlNode(xml_data_node* node) |
| 476 | { |
| 477 | WindowQtConfig::recoverFromXmlNode(node); |
| 478 | const char* state = xml_get_attribute_string(node, "qtwindowstate", ""); |
| 479 | m_windowState = QByteArray::fromPercentEncoding(state); |
| 480 | m_rightBar = xml_get_attribute_int(node, "rightbar", m_rightBar); |
| 481 | } |
| 482 | |
| 483 | DasmDockWidget::~DasmDockWidget() |
| 484 | { |
| 485 | } |
| 486 | |
| 487 | ProcessorDockWidget::~ProcessorDockWidget() |
| 488 | { |
| 489 | } |
trunk/src/osd/modules/debugger/qt/debugqtmainwindow.h
| r0 | r243602 | |
| 1 | #ifndef __DEBUG_QT_MAIN_WINDOW_H__ |
| 2 | #define __DEBUG_QT_MAIN_WINDOW_H__ |
| 3 | |
| 4 | #include <QtGui/QtGui> |
| 5 | #include <vector> |
| 6 | |
| 7 | #include "debug/dvdisasm.h" |
| 8 | |
| 9 | #include "debugqtview.h" |
| 10 | #include "debugqtwindow.h" |
| 11 | |
| 12 | class DasmDockWidget; |
| 13 | class ProcessorDockWidget; |
| 14 | |
| 15 | |
| 16 | //============================================================ |
| 17 | // The Main Window. Contains processor and dasm docks. |
| 18 | //============================================================ |
| 19 | class MainWindow : public WindowQt |
| 20 | { |
| 21 | Q_OBJECT |
| 22 | |
| 23 | public: |
| 24 | MainWindow(running_machine* machine, QWidget* parent=NULL); |
| 25 | virtual ~MainWindow(); |
| 26 | |
| 27 | void setProcessor(device_t* processor); |
| 28 | |
| 29 | |
| 30 | protected: |
| 31 | // Used to intercept the user clicking 'X' in the upper corner |
| 32 | void closeEvent(QCloseEvent* event); |
| 33 | |
| 34 | // Used to intercept the user hitting the up arrow in the input widget |
| 35 | bool eventFilter(QObject* obj, QEvent* event); |
| 36 | |
| 37 | |
| 38 | private slots: |
| 39 | void toggleBreakpointAtCursor(bool changedTo); |
| 40 | void runToCursor(bool changedTo); |
| 41 | void rightBarChanged(QAction* changedTo); |
| 42 | |
| 43 | void executeCommand(bool withClear=true); |
| 44 | |
| 45 | void mountImage(bool changedTo); |
| 46 | void unmountImage(bool changedTo); |
| 47 | |
| 48 | // Closing the main window actually exits the program |
| 49 | void debugActClose(); |
| 50 | |
| 51 | |
| 52 | private: |
| 53 | // Widgets and docks |
| 54 | QLineEdit* m_inputEdit; |
| 55 | DebuggerView* m_consoleView; |
| 56 | ProcessorDockWidget* m_procFrame; |
| 57 | DasmDockWidget* m_dasmFrame; |
| 58 | |
| 59 | // Terminal history |
| 60 | int m_historyIndex; |
| 61 | std::vector<QString> m_inputHistory; |
| 62 | void addToHistory(const QString& command); |
| 63 | |
| 64 | void createImagesMenu(); |
| 65 | }; |
| 66 | |
| 67 | |
| 68 | //============================================================ |
| 69 | // Docks with the Main Window. Disassembly. |
| 70 | //============================================================ |
| 71 | class DasmDockWidget : public QWidget |
| 72 | { |
| 73 | Q_OBJECT |
| 74 | |
| 75 | public: |
| 76 | DasmDockWidget(running_machine* machine, QWidget* parent=NULL) : |
| 77 | QWidget(parent), |
| 78 | m_machine(machine) |
| 79 | { |
| 80 | m_dasmView = new DebuggerView(DVT_DISASSEMBLY, |
| 81 | m_machine, |
| 82 | this); |
| 83 | |
| 84 | // Force a recompute of the disassembly region |
| 85 | downcast<debug_view_disasm*>(m_dasmView->view())->set_expression("curpc"); |
| 86 | |
| 87 | QVBoxLayout* dvLayout = new QVBoxLayout(this); |
| 88 | dvLayout->addWidget(m_dasmView); |
| 89 | dvLayout->setContentsMargins(4,0,4,0); |
| 90 | } |
| 91 | |
| 92 | |
| 93 | virtual ~DasmDockWidget(); |
| 94 | |
| 95 | |
| 96 | DebuggerView* view() { return m_dasmView; } |
| 97 | |
| 98 | |
| 99 | QSize minimumSizeHint() const |
| 100 | { |
| 101 | return QSize(150,150); |
| 102 | } |
| 103 | |
| 104 | |
| 105 | QSize sizeHint() const |
| 106 | { |
| 107 | return QSize(150,200); |
| 108 | } |
| 109 | |
| 110 | |
| 111 | private: |
| 112 | DebuggerView* m_dasmView; |
| 113 | |
| 114 | running_machine* m_machine; |
| 115 | }; |
| 116 | |
| 117 | |
| 118 | //============================================================ |
| 119 | // Docks with the Main Window. Processor information. |
| 120 | //============================================================ |
| 121 | class ProcessorDockWidget : public QWidget |
| 122 | { |
| 123 | Q_OBJECT |
| 124 | |
| 125 | public: |
| 126 | ProcessorDockWidget(running_machine* machine, |
| 127 | QWidget* parent=NULL) : |
| 128 | QWidget(parent), |
| 129 | m_processorView(NULL), |
| 130 | m_machine(machine) |
| 131 | { |
| 132 | m_processorView = new DebuggerView(DVT_STATE, |
| 133 | m_machine, |
| 134 | this); |
| 135 | m_processorView->setFocusPolicy(Qt::NoFocus); |
| 136 | |
| 137 | QVBoxLayout* cvLayout = new QVBoxLayout(this); |
| 138 | cvLayout->addWidget(m_processorView); |
| 139 | cvLayout->setContentsMargins(4,0,4,2); |
| 140 | } |
| 141 | |
| 142 | |
| 143 | virtual ~ProcessorDockWidget(); |
| 144 | |
| 145 | |
| 146 | DebuggerView* view() { return m_processorView; } |
| 147 | |
| 148 | |
| 149 | QSize minimumSizeHint() const |
| 150 | { |
| 151 | return QSize(150,300); |
| 152 | } |
| 153 | |
| 154 | |
| 155 | QSize sizeHint() const |
| 156 | { |
| 157 | return QSize(200,300); |
| 158 | } |
| 159 | |
| 160 | |
| 161 | private: |
| 162 | DebuggerView* m_processorView; |
| 163 | |
| 164 | running_machine* m_machine; |
| 165 | }; |
| 166 | |
| 167 | |
| 168 | //========================================================================= |
| 169 | // A way to store the configuration of a window long enough to read/write. |
| 170 | //========================================================================= |
| 171 | class MainWindowQtConfig : public WindowQtConfig |
| 172 | { |
| 173 | public: |
| 174 | MainWindowQtConfig() : |
| 175 | WindowQtConfig(WIN_TYPE_MAIN), |
| 176 | m_rightBar(0), |
| 177 | m_windowState() |
| 178 | {} |
| 179 | |
| 180 | ~MainWindowQtConfig() {} |
| 181 | |
| 182 | // Settings |
| 183 | int m_rightBar; |
| 184 | QByteArray m_windowState; |
| 185 | |
| 186 | void buildFromQWidget(QWidget* widget); |
| 187 | void applyToQWidget(QWidget* widget); |
| 188 | void addToXmlDataNode(xml_data_node* node) const; |
| 189 | void recoverFromXmlNode(xml_data_node* node); |
| 190 | }; |
| 191 | |
| 192 | |
| 193 | |
| 194 | #endif |
trunk/src/osd/modules/debugger/qt/debugqtmemorywindow.c
| r0 | r243602 | |
| 1 | #define NO_MEM_TRACKING |
| 2 | |
| 3 | #include "debugqtmemorywindow.h" |
| 4 | |
| 5 | #include "debug/dvmemory.h" |
| 6 | #include "debug/debugcon.h" |
| 7 | #include "debug/debugcpu.h" |
| 8 | |
| 9 | |
| 10 | MemoryWindow::MemoryWindow(running_machine* machine, QWidget* parent) : |
| 11 | WindowQt(machine, NULL) |
| 12 | { |
| 13 | setWindowTitle("Debug: Memory View"); |
| 14 | |
| 15 | if (parent != NULL) |
| 16 | { |
| 17 | QPoint parentPos = parent->pos(); |
| 18 | setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400); |
| 19 | } |
| 20 | |
| 21 | // |
| 22 | // The main frame and its input and log widgets |
| 23 | // |
| 24 | QFrame* mainWindowFrame = new QFrame(this); |
| 25 | |
| 26 | // The top frame & groupbox that contains the input widgets |
| 27 | QFrame* topSubFrame = new QFrame(mainWindowFrame); |
| 28 | |
| 29 | // The input edit |
| 30 | m_inputEdit = new QLineEdit(topSubFrame); |
| 31 | connect(m_inputEdit, SIGNAL(returnPressed()), this, SLOT(expressionSubmitted())); |
| 32 | |
| 33 | // The memory space combo box |
| 34 | m_memoryComboBox = new QComboBox(topSubFrame); |
| 35 | m_memoryComboBox->setObjectName("memoryregion"); |
| 36 | m_memoryComboBox->setMinimumWidth(300); |
| 37 | connect(m_memoryComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(memoryRegionChanged(int))); |
| 38 | |
| 39 | // The main memory window |
| 40 | m_memTable = new DebuggerMemView(DVT_MEMORY, m_machine, this); |
| 41 | |
| 42 | // Layout |
| 43 | QHBoxLayout* subLayout = new QHBoxLayout(topSubFrame); |
| 44 | subLayout->addWidget(m_inputEdit); |
| 45 | subLayout->addWidget(m_memoryComboBox); |
| 46 | subLayout->setSpacing(3); |
| 47 | subLayout->setContentsMargins(2,2,2,2); |
| 48 | |
| 49 | QVBoxLayout* vLayout = new QVBoxLayout(mainWindowFrame); |
| 50 | vLayout->setSpacing(3); |
| 51 | vLayout->setContentsMargins(2,2,2,2); |
| 52 | vLayout->addWidget(topSubFrame); |
| 53 | vLayout->addWidget(m_memTable); |
| 54 | |
| 55 | setCentralWidget(mainWindowFrame); |
| 56 | |
| 57 | // |
| 58 | // Menu bars |
| 59 | // |
| 60 | // Create a byte-chunk group |
| 61 | QActionGroup* chunkGroup = new QActionGroup(this); |
| 62 | chunkGroup->setObjectName("chunkgroup"); |
| 63 | QAction* chunkActOne = new QAction("1-byte chunks", this); |
| 64 | chunkActOne->setObjectName("chunkActOne"); |
| 65 | QAction* chunkActTwo = new QAction("2-byte chunks", this); |
| 66 | chunkActTwo->setObjectName("chunkActTwo"); |
| 67 | QAction* chunkActFour = new QAction("4-byte chunks", this); |
| 68 | chunkActFour->setObjectName("chunkActFour"); |
| 69 | chunkActOne->setCheckable(true); |
| 70 | chunkActTwo->setCheckable(true); |
| 71 | chunkActFour->setCheckable(true); |
| 72 | chunkActOne->setActionGroup(chunkGroup); |
| 73 | chunkActTwo->setActionGroup(chunkGroup); |
| 74 | chunkActFour->setActionGroup(chunkGroup); |
| 75 | chunkActOne->setShortcut(QKeySequence("Ctrl+1")); |
| 76 | chunkActTwo->setShortcut(QKeySequence("Ctrl+2")); |
| 77 | chunkActFour->setShortcut(QKeySequence("Ctrl+4")); |
| 78 | chunkActOne->setChecked(true); |
| 79 | connect(chunkGroup, SIGNAL(triggered(QAction*)), this, SLOT(chunkChanged(QAction*))); |
| 80 | |
| 81 | // Create a address display group |
| 82 | QActionGroup* addressGroup = new QActionGroup(this); |
| 83 | addressGroup->setObjectName("addressgroup"); |
| 84 | QAction* addressActLogical = new QAction("Logical Addresses", this); |
| 85 | QAction* addressActPhysical = new QAction("Physical Addresses", this); |
| 86 | addressActLogical->setCheckable(true); |
| 87 | addressActPhysical->setCheckable(true); |
| 88 | addressActLogical->setActionGroup(addressGroup); |
| 89 | addressActPhysical->setActionGroup(addressGroup); |
| 90 | addressActLogical->setShortcut(QKeySequence("Ctrl+G")); |
| 91 | addressActPhysical->setShortcut(QKeySequence("Ctrl+Y")); |
| 92 | addressActLogical->setChecked(true); |
| 93 | connect(addressGroup, SIGNAL(triggered(QAction*)), this, SLOT(addressChanged(QAction*))); |
| 94 | |
| 95 | // Create a reverse view radio |
| 96 | QAction* reverseAct = new QAction("Reverse View", this); |
| 97 | reverseAct->setObjectName("reverse"); |
| 98 | reverseAct->setCheckable(true); |
| 99 | reverseAct->setShortcut(QKeySequence("Ctrl+R")); |
| 100 | connect(reverseAct, SIGNAL(toggled(bool)), this, SLOT(reverseChanged(bool))); |
| 101 | |
| 102 | // Create increase and decrease bytes-per-line actions |
| 103 | QAction* increaseBplAct = new QAction("Increase Bytes Per Line", this); |
| 104 | QAction* decreaseBplAct = new QAction("Decrease Bytes Per Line", this); |
| 105 | increaseBplAct->setShortcut(QKeySequence("Ctrl+P")); |
| 106 | decreaseBplAct->setShortcut(QKeySequence("Ctrl+O")); |
| 107 | connect(increaseBplAct, SIGNAL(triggered(bool)), this, SLOT(increaseBytesPerLine(bool))); |
| 108 | connect(decreaseBplAct, SIGNAL(triggered(bool)), this, SLOT(decreaseBytesPerLine(bool))); |
| 109 | |
| 110 | // Assemble the options menu |
| 111 | QMenu* optionsMenu = menuBar()->addMenu("&Options"); |
| 112 | optionsMenu->addActions(chunkGroup->actions()); |
| 113 | optionsMenu->addSeparator(); |
| 114 | optionsMenu->addActions(addressGroup->actions()); |
| 115 | optionsMenu->addSeparator(); |
| 116 | optionsMenu->addAction(reverseAct); |
| 117 | optionsMenu->addSeparator(); |
| 118 | optionsMenu->addAction(increaseBplAct); |
| 119 | optionsMenu->addAction(decreaseBplAct); |
| 120 | |
| 121 | |
| 122 | // |
| 123 | // Initialize |
| 124 | // |
| 125 | populateComboBox(); |
| 126 | |
| 127 | // Set to the current CPU's memory view |
| 128 | setToCurrentCpu(); |
| 129 | } |
| 130 | |
| 131 | |
| 132 | MemoryWindow::~MemoryWindow() |
| 133 | { |
| 134 | } |
| 135 | |
| 136 | |
| 137 | void MemoryWindow::memoryRegionChanged(int index) |
| 138 | { |
| 139 | m_memTable->view()->set_source(*m_memTable->view()->source_list().find(index)); |
| 140 | m_memTable->viewport()->update(); |
| 141 | |
| 142 | // Update the chunk size radio buttons to the memory region's default |
| 143 | debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view()); |
| 144 | switch(memView->bytes_per_chunk()) |
| 145 | { |
| 146 | case 1: chunkSizeMenuItem("chunkActOne")->setChecked(true); break; |
| 147 | case 2: chunkSizeMenuItem("chunkActTwo")->setChecked(true); break; |
| 148 | case 4: chunkSizeMenuItem("chunkActFour")->setChecked(true); break; |
| 149 | default: break; |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | |
| 154 | void MemoryWindow::expressionSubmitted() |
| 155 | { |
| 156 | const QString expression = m_inputEdit->text(); |
| 157 | downcast<debug_view_memory*>(m_memTable->view())->set_expression(expression.toLocal8Bit().data()); |
| 158 | |
| 159 | // Make the cursor pop |
| 160 | m_memTable->view()->set_cursor_visible(true); |
| 161 | |
| 162 | // Check where the cursor is and adjust the scroll accordingly |
| 163 | debug_view_xy cursorPosition = m_memTable->view()->cursor_position(); |
| 164 | // TODO: check if the region is already visible? |
| 165 | m_memTable->verticalScrollBar()->setValue(cursorPosition.y); |
| 166 | |
| 167 | m_memTable->update(); |
| 168 | m_memTable->viewport()->update(); |
| 169 | } |
| 170 | |
| 171 | |
| 172 | void MemoryWindow::chunkChanged(QAction* changedTo) |
| 173 | { |
| 174 | debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view()); |
| 175 | if (changedTo->text() == "1-byte chunks") |
| 176 | { |
| 177 | memView->set_bytes_per_chunk(1); |
| 178 | } |
| 179 | else if (changedTo->text() == "2-byte chunks") |
| 180 | { |
| 181 | memView->set_bytes_per_chunk(2); |
| 182 | } |
| 183 | else if (changedTo->text() == "4-byte chunks") |
| 184 | { |
| 185 | memView->set_bytes_per_chunk(4); |
| 186 | } |
| 187 | m_memTable->viewport()->update(); |
| 188 | } |
| 189 | |
| 190 | |
| 191 | void MemoryWindow::addressChanged(QAction* changedTo) |
| 192 | { |
| 193 | debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view()); |
| 194 | if (changedTo->text() == "Logical Addresses") |
| 195 | { |
| 196 | memView->set_physical(false); |
| 197 | } |
| 198 | else if (changedTo->text() == "Physical Addresses") |
| 199 | { |
| 200 | memView->set_physical(true); |
| 201 | } |
| 202 | m_memTable->viewport()->update(); |
| 203 | } |
| 204 | |
| 205 | |
| 206 | void MemoryWindow::reverseChanged(bool changedTo) |
| 207 | { |
| 208 | debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view()); |
| 209 | memView->set_reverse(changedTo); |
| 210 | m_memTable->viewport()->update(); |
| 211 | } |
| 212 | |
| 213 | |
| 214 | void MemoryWindow::increaseBytesPerLine(bool changedTo) |
| 215 | { |
| 216 | debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view()); |
| 217 | memView->set_chunks_per_row(memView->chunks_per_row() + 1); |
| 218 | m_memTable->viewport()->update(); |
| 219 | } |
| 220 | |
| 221 | |
| 222 | void MemoryWindow::decreaseBytesPerLine(bool checked) |
| 223 | { |
| 224 | debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view()); |
| 225 | memView->set_chunks_per_row(memView->chunks_per_row() - 1); |
| 226 | m_memTable->viewport()->update(); |
| 227 | } |
| 228 | |
| 229 | |
| 230 | void MemoryWindow::populateComboBox() |
| 231 | { |
| 232 | if (m_memTable == NULL) |
| 233 | return; |
| 234 | |
| 235 | m_memoryComboBox->clear(); |
| 236 | for (const debug_view_source* source = m_memTable->view()->first_source(); |
| 237 | source != NULL; |
| 238 | source = source->next()) |
| 239 | { |
| 240 | m_memoryComboBox->addItem(source->name()); |
| 241 | } |
| 242 | } |
| 243 | |
| 244 | |
| 245 | void MemoryWindow::setToCurrentCpu() |
| 246 | { |
| 247 | device_t* curCpu = debug_cpu_get_visible_cpu(*m_machine); |
| 248 | const debug_view_source *source = m_memTable->view()->source_for_device(curCpu); |
| 249 | const int listIndex = m_memTable->view()->source_list().indexof(*source); |
| 250 | m_memoryComboBox->setCurrentIndex(listIndex); |
| 251 | } |
| 252 | |
| 253 | |
| 254 | // I have a hard time storing QActions as class members. This is a substitute. |
| 255 | QAction* MemoryWindow::chunkSizeMenuItem(const QString& itemName) |
| 256 | { |
| 257 | QList<QMenu*> menus = menuBar()->findChildren<QMenu*>(); |
| 258 | for (int i = 0; i < menus.length(); i++) |
| 259 | { |
| 260 | if (menus[i]->title() != "&Options") continue; |
| 261 | QList<QAction*> actions = menus[i]->actions(); |
| 262 | for (int j = 0; j < actions.length(); j++) |
| 263 | { |
| 264 | if (actions[j]->objectName() == itemName) |
| 265 | return actions[j]; |
| 266 | } |
| 267 | } |
| 268 | return NULL; |
| 269 | } |
| 270 | |
| 271 | |
| 272 | //========================================================================= |
| 273 | // DebuggerMemView |
| 274 | //========================================================================= |
| 275 | void DebuggerMemView::mousePressEvent(QMouseEvent* event) |
| 276 | { |
| 277 | const bool leftClick = event->button() == Qt::LeftButton; |
| 278 | const bool rightClick = event->button() == Qt::RightButton; |
| 279 | |
| 280 | if (leftClick || rightClick) |
| 281 | { |
| 282 | QFontMetrics actualFont = fontMetrics(); |
| 283 | const double fontWidth = actualFont.width(QString(100, '_')) / 100.; |
| 284 | const int fontHeight = MAX(1, actualFont.height()); |
| 285 | |
| 286 | debug_view_xy topLeft = view()->visible_position(); |
| 287 | debug_view_xy clickViewPosition; |
| 288 | clickViewPosition.x = topLeft.x + (event->x() / fontWidth); |
| 289 | clickViewPosition.y = topLeft.y + (event->y() / fontHeight); |
| 290 | if (leftClick) |
| 291 | { |
| 292 | view()->process_click(DCK_LEFT_CLICK, clickViewPosition); |
| 293 | } |
| 294 | else if (rightClick) |
| 295 | { |
| 296 | // Display the last known PC to write to this memory location & copy it onto the clipboard |
| 297 | debug_view_memory* memView = downcast<debug_view_memory*>(view()); |
| 298 | const offs_t address = memView->addressAtCursorPosition(clickViewPosition); |
| 299 | const debug_view_memory_source* source = downcast<const debug_view_memory_source*>(memView->source()); |
| 300 | address_space* addressSpace = source->space(); |
| 301 | const int nativeDataWidth = addressSpace->data_width() / 8; |
| 302 | const UINT64 memValue = debug_read_memory(*addressSpace, |
| 303 | addressSpace->address_to_byte(address), |
| 304 | nativeDataWidth, |
| 305 | true); |
| 306 | const offs_t pc = source->device()->debug()->track_mem_pc_from_space_address_data(addressSpace->spacenum(), |
| 307 | address, |
| 308 | memValue); |
| 309 | if (pc != (offs_t)(-1)) |
| 310 | { |
| 311 | // TODO: You can specify a box that the tooltip stays alive within - might be good? |
| 312 | const QString addressAndPc = QString("Address %1 written at PC=%2").arg(address, 2, 16).arg(pc, 2, 16); |
| 313 | QToolTip::showText(QCursor::pos(), addressAndPc, NULL); |
| 314 | |
| 315 | // Copy the PC into the clipboard as well |
| 316 | QClipboard *clipboard = QApplication::clipboard(); |
| 317 | clipboard->setText(QString("%1").arg(pc, 2, 16)); |
| 318 | } |
| 319 | else |
| 320 | { |
| 321 | QToolTip::showText(QCursor::pos(), "UNKNOWN PC", NULL); |
| 322 | } |
| 323 | } |
| 324 | |
| 325 | viewport()->update(); |
| 326 | update(); |
| 327 | } |
| 328 | } |
| 329 | |
| 330 | |
| 331 | //========================================================================= |
| 332 | // MemoryWindowQtConfig |
| 333 | //========================================================================= |
| 334 | void MemoryWindowQtConfig::buildFromQWidget(QWidget* widget) |
| 335 | { |
| 336 | WindowQtConfig::buildFromQWidget(widget); |
| 337 | MemoryWindow* window = dynamic_cast<MemoryWindow*>(widget); |
| 338 | QComboBox* memoryRegion = window->findChild<QComboBox*>("memoryregion"); |
| 339 | m_memoryRegion = memoryRegion->currentIndex(); |
| 340 | |
| 341 | QAction* reverse = window->findChild<QAction*>("reverse"); |
| 342 | m_reverse = reverse->isChecked(); |
| 343 | |
| 344 | QActionGroup* addressGroup = window->findChild<QActionGroup*>("addressgroup"); |
| 345 | if (addressGroup->checkedAction()->text() == "Logical Addresses") |
| 346 | m_addressMode = 0; |
| 347 | else if (addressGroup->checkedAction()->text() == "Physical Addresses") |
| 348 | m_addressMode = 1; |
| 349 | |
| 350 | QActionGroup* chunkGroup = window->findChild<QActionGroup*>("chunkgroup"); |
| 351 | if (chunkGroup->checkedAction()->text() == "1-byte chunks") |
| 352 | m_chunkSize = 0; |
| 353 | else if (chunkGroup->checkedAction()->text() == "2-byte chunks") |
| 354 | m_chunkSize = 1; |
| 355 | else if (chunkGroup->checkedAction()->text() == "4-byte chunks") |
| 356 | m_chunkSize = 2; |
| 357 | } |
| 358 | |
| 359 | |
| 360 | void MemoryWindowQtConfig::applyToQWidget(QWidget* widget) |
| 361 | { |
| 362 | WindowQtConfig::applyToQWidget(widget); |
| 363 | MemoryWindow* window = dynamic_cast<MemoryWindow*>(widget); |
| 364 | QComboBox* memoryRegion = window->findChild<QComboBox*>("memoryregion"); |
| 365 | memoryRegion->setCurrentIndex(m_memoryRegion); |
| 366 | |
| 367 | QAction* reverse = window->findChild<QAction*>("reverse"); |
| 368 | if (m_reverse) reverse->trigger(); |
| 369 | |
| 370 | QActionGroup* addressGroup = window->findChild<QActionGroup*>("addressgroup"); |
| 371 | addressGroup->actions()[m_addressMode]->trigger(); |
| 372 | |
| 373 | QActionGroup* chunkGroup = window->findChild<QActionGroup*>("chunkgroup"); |
| 374 | chunkGroup->actions()[m_chunkSize]->trigger(); |
| 375 | } |
| 376 | |
| 377 | |
| 378 | void MemoryWindowQtConfig::addToXmlDataNode(xml_data_node* node) const |
| 379 | { |
| 380 | WindowQtConfig::addToXmlDataNode(node); |
| 381 | xml_set_attribute_int(node, "memoryregion", m_memoryRegion); |
| 382 | xml_set_attribute_int(node, "reverse", m_reverse); |
| 383 | xml_set_attribute_int(node, "addressmode", m_addressMode); |
| 384 | xml_set_attribute_int(node, "chunksize", m_chunkSize); |
| 385 | } |
| 386 | |
| 387 | |
| 388 | void MemoryWindowQtConfig::recoverFromXmlNode(xml_data_node* node) |
| 389 | { |
| 390 | WindowQtConfig::recoverFromXmlNode(node); |
| 391 | m_memoryRegion = xml_get_attribute_int(node, "memoryregion", m_memoryRegion); |
| 392 | m_reverse = xml_get_attribute_int(node, "reverse", m_reverse); |
| 393 | m_addressMode = xml_get_attribute_int(node, "addressmode", m_addressMode); |
| 394 | m_chunkSize = xml_get_attribute_int(node, "chunksize", m_chunkSize); |
| 395 | } |
trunk/src/osd/modules/debugger/qt/debugqtview.c
| r0 | r243602 | |
| 1 | #define NO_MEM_TRACKING |
| 2 | |
| 3 | #include "debugqtview.h" |
| 4 | |
| 5 | DebuggerView::DebuggerView(const debug_view_type& type, |
| 6 | running_machine* machine, |
| 7 | QWidget* parent) : |
| 8 | QAbstractScrollArea(parent), |
| 9 | m_preferBottom(false), |
| 10 | m_view(NULL), |
| 11 | m_machine(machine) |
| 12 | { |
| 13 | // I like setting the font per-view since it doesn't override the menuing fonts. |
| 14 | QFont viewFontRequest("Courier New"); |
| 15 | viewFontRequest.setFixedPitch(true); |
| 16 | viewFontRequest.setPointSize(11); |
| 17 | setFont(viewFontRequest); |
| 18 | |
| 19 | m_view = m_machine->debug_view().alloc_view(type, |
| 20 | DebuggerView::debuggerViewUpdate, |
| 21 | this); |
| 22 | |
| 23 | connect(verticalScrollBar(), SIGNAL(valueChanged(int)), |
| 24 | this, SLOT(verticalScrollSlot(int))); |
| 25 | connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), |
| 26 | this, SLOT(horizontalScrollSlot(int))); |
| 27 | } |
| 28 | |
| 29 | |
| 30 | DebuggerView::~DebuggerView() |
| 31 | { |
| 32 | if (m_machine && m_view) |
| 33 | m_machine->debug_view().free_view(*m_view); |
| 34 | } |
| 35 | |
| 36 | // TODO: remove this version no later than January 1, 2015 |
| 37 | #if QT_VERSION < QT_VERSION_CHECK(4, 7, 0) |
| 38 | void DebuggerView::paintEvent(QPaintEvent* event) |
| 39 | { |
| 40 | // Tell the MAME debug view how much real estate is available |
| 41 | QFontMetrics actualFont = fontMetrics(); |
| 42 | const int fontWidth = MAX(1, actualFont.width('_')); |
| 43 | const int fontHeight = MAX(1, actualFont.height()); |
| 44 | m_view->set_visible_size(debug_view_xy(width()/fontWidth, height()/fontHeight)); |
| 45 | |
| 46 | |
| 47 | // Handle the scroll bars |
| 48 | const int horizontalScrollCharDiff = m_view->total_size().x - m_view->visible_size().x; |
| 49 | const int horizontalScrollSize = horizontalScrollCharDiff < 0 ? 0 : horizontalScrollCharDiff; |
| 50 | horizontalScrollBar()->setRange(0, horizontalScrollSize); |
| 51 | |
| 52 | // If the horizontal scroll bar appears, make sure to adjust the vertical scrollbar accordingly |
| 53 | const int verticalScrollAdjust = horizontalScrollSize > 0 ? 1 : 0; |
| 54 | |
| 55 | const int verticalScrollCharDiff = m_view->total_size().y - m_view->visible_size().y; |
| 56 | const int verticalScrollSize = verticalScrollCharDiff < 0 ? 0 : verticalScrollCharDiff+verticalScrollAdjust; |
| 57 | bool atEnd = false; |
| 58 | if (verticalScrollBar()->value() == verticalScrollBar()->maximum()) |
| 59 | { |
| 60 | atEnd = true; |
| 61 | } |
| 62 | verticalScrollBar()->setRange(0, verticalScrollSize); |
| 63 | if (m_preferBottom && atEnd) |
| 64 | { |
| 65 | verticalScrollBar()->setValue(verticalScrollSize); |
| 66 | } |
| 67 | |
| 68 | |
| 69 | // Draw the viewport widget |
| 70 | QPainter painter(viewport()); |
| 71 | painter.fillRect(0, 0, width(), height(), QBrush(Qt::white)); |
| 72 | painter.setBackgroundMode(Qt::OpaqueMode); |
| 73 | painter.setBackground(QColor(255,255,255)); |
| 74 | |
| 75 | // Background control |
| 76 | QBrush bgBrush; |
| 77 | bgBrush.setStyle(Qt::SolidPattern); |
| 78 | painter.setPen(QPen(QColor(0,0,0))); |
| 79 | |
| 80 | size_t viewDataOffset = 0; |
| 81 | const debug_view_xy& visibleCharDims = m_view->visible_size(); |
| 82 | for (int y = 0; y < visibleCharDims.y; y++) |
| 83 | { |
| 84 | for (int x = 0; x < visibleCharDims.x; x++) |
| 85 | { |
| 86 | const unsigned char textAttr = m_view->viewdata()[viewDataOffset].attrib; |
| 87 | |
| 88 | if (x == 0 || textAttr != m_view->viewdata()[viewDataOffset-1].attrib) |
| 89 | { |
| 90 | // Text color handling |
| 91 | QColor fgColor(0,0,0); |
| 92 | QColor bgColor(255,255,255); |
| 93 | |
| 94 | if(textAttr & DCA_VISITED) |
| 95 | { |
| 96 | bgColor.setRgb(0xc6, 0xe2, 0xff); |
| 97 | } |
| 98 | if(textAttr & DCA_ANCILLARY) |
| 99 | { |
| 100 | bgColor.setRgb(0xe0, 0xe0, 0xe0); |
| 101 | } |
| 102 | if(textAttr & DCA_SELECTED) |
| 103 | { |
| 104 | bgColor.setRgb(0xff, 0x80, 0x80); |
| 105 | } |
| 106 | if(textAttr & DCA_CURRENT) |
| 107 | { |
| 108 | bgColor.setRgb(0xff, 0xff, 0x00); |
| 109 | } |
| 110 | if ((textAttr & DCA_SELECTED) && (textAttr & DCA_CURRENT)) |
| 111 | { |
| 112 | bgColor.setRgb(0xff,0xc0,0x80); |
| 113 | } |
| 114 | if(textAttr & DCA_CHANGED) |
| 115 | { |
| 116 | fgColor.setRgb(0xff, 0x00, 0x00); |
| 117 | } |
| 118 | if(textAttr & DCA_INVALID) |
| 119 | { |
| 120 | fgColor.setRgb(0x00, 0x00, 0xff); |
| 121 | } |
| 122 | if(textAttr & DCA_DISABLED) |
| 123 | { |
| 124 | fgColor.setRgb((fgColor.red() + bgColor.red()) >> 1, |
| 125 | (fgColor.green() + bgColor.green()) >> 1, |
| 126 | (fgColor.blue() + bgColor.blue()) >> 1); |
| 127 | } |
| 128 | if(textAttr & DCA_COMMENT) |
| 129 | { |
| 130 | fgColor.setRgb(0x00, 0x80, 0x00); |
| 131 | } |
| 132 | |
| 133 | bgBrush.setColor(bgColor); |
| 134 | painter.setBackground(bgBrush); |
| 135 | painter.setPen(QPen(fgColor)); |
| 136 | } |
| 137 | |
| 138 | // Your character is not guaranteed to take up the entire fontWidth x fontHeight, so fill before. |
| 139 | painter.fillRect(x*fontWidth, y*fontHeight, fontWidth, fontHeight, bgBrush); |
| 140 | |
| 141 | // There is a touchy interplay between font height, drawing difference, visible position, etc |
| 142 | // Fonts don't get drawn "down and to the left" like boxes, so some wiggling is needed. |
| 143 | painter.drawText(x*fontWidth, |
| 144 | (y*fontHeight + (fontHeight*0.80)), |
| 145 | QString(m_view->viewdata()[viewDataOffset].byte)); |
| 146 | viewDataOffset++; |
| 147 | } |
| 148 | } |
| 149 | } |
| 150 | #else |
| 151 | void DebuggerView::paintEvent(QPaintEvent* event) |
| 152 | { |
| 153 | // Tell the MAME debug view how much real estate is available |
| 154 | QFontMetrics actualFont = fontMetrics(); |
| 155 | const double fontWidth = actualFont.width(QString(100, '_')) / 100.; |
| 156 | const int fontHeight = MAX(1, actualFont.height()); |
| 157 | m_view->set_visible_size(debug_view_xy(width()/fontWidth, height()/fontHeight)); |
| 158 | |
| 159 | |
| 160 | // Handle the scroll bars |
| 161 | const int horizontalScrollCharDiff = m_view->total_size().x - m_view->visible_size().x; |
| 162 | const int horizontalScrollSize = horizontalScrollCharDiff < 0 ? 0 : horizontalScrollCharDiff; |
| 163 | horizontalScrollBar()->setRange(0, horizontalScrollSize); |
| 164 | |
| 165 | // If the horizontal scroll bar appears, make sure to adjust the vertical scrollbar accordingly |
| 166 | const int verticalScrollAdjust = horizontalScrollSize > 0 ? 1 : 0; |
| 167 | |
| 168 | const int verticalScrollCharDiff = m_view->total_size().y - m_view->visible_size().y; |
| 169 | const int verticalScrollSize = verticalScrollCharDiff < 0 ? 0 : verticalScrollCharDiff+verticalScrollAdjust; |
| 170 | bool atEnd = false; |
| 171 | if (verticalScrollBar()->value() == verticalScrollBar()->maximum()) |
| 172 | { |
| 173 | atEnd = true; |
| 174 | } |
| 175 | verticalScrollBar()->setRange(0, verticalScrollSize); |
| 176 | if (m_preferBottom && atEnd) |
| 177 | { |
| 178 | verticalScrollBar()->setValue(verticalScrollSize); |
| 179 | } |
| 180 | |
| 181 | |
| 182 | // Draw the viewport widget |
| 183 | QPainter painter(viewport()); |
| 184 | painter.fillRect(0, 0, width(), height(), QBrush(Qt::white)); |
| 185 | painter.setBackgroundMode(Qt::OpaqueMode); |
| 186 | painter.setBackground(QColor(255,255,255)); |
| 187 | |
| 188 | // Background control |
| 189 | QBrush bgBrush; |
| 190 | bgBrush.setStyle(Qt::SolidPattern); |
| 191 | painter.setPen(QPen(QColor(0,0,0))); |
| 192 | |
| 193 | size_t viewDataOffset = 0; |
| 194 | const debug_view_xy& visibleCharDims = m_view->visible_size(); |
| 195 | const debug_view_char* viewdata = m_view->viewdata(); |
| 196 | for (int y = 0; y < visibleCharDims.y; y++) |
| 197 | { |
| 198 | int width = 1; |
| 199 | for (int x = 0; x < visibleCharDims.x; viewDataOffset += width, x += width) |
| 200 | { |
| 201 | const unsigned char textAttr = viewdata[viewDataOffset].attrib; |
| 202 | |
| 203 | // Text color handling |
| 204 | QColor fgColor(0,0,0); |
| 205 | QColor bgColor(255,255,255); |
| 206 | |
| 207 | if(textAttr & DCA_VISITED) |
| 208 | { |
| 209 | bgColor.setRgb(0xc6, 0xe2, 0xff); |
| 210 | } |
| 211 | if(textAttr & DCA_ANCILLARY) |
| 212 | { |
| 213 | bgColor.setRgb(0xe0, 0xe0, 0xe0); |
| 214 | } |
| 215 | if(textAttr & DCA_SELECTED) |
| 216 | { |
| 217 | bgColor.setRgb(0xff, 0x80, 0x80); |
| 218 | } |
| 219 | if(textAttr & DCA_CURRENT) |
| 220 | { |
| 221 | bgColor.setRgb(0xff, 0xff, 0x00); |
| 222 | } |
| 223 | if ((textAttr & DCA_SELECTED) && (textAttr & DCA_CURRENT)) |
| 224 | { |
| 225 | bgColor.setRgb(0xff,0xc0,0x80); |
| 226 | } |
| 227 | if(textAttr & DCA_CHANGED) |
| 228 | { |
| 229 | fgColor.setRgb(0xff, 0x00, 0x00); |
| 230 | } |
| 231 | if(textAttr & DCA_INVALID) |
| 232 | { |
| 233 | fgColor.setRgb(0x00, 0x00, 0xff); |
| 234 | } |
| 235 | if(textAttr & DCA_DISABLED) |
| 236 | { |
| 237 | fgColor.setRgb((fgColor.red() + bgColor.red()) >> 1, |
| 238 | (fgColor.green() + bgColor.green()) >> 1, |
| 239 | (fgColor.blue() + bgColor.blue()) >> 1); |
| 240 | } |
| 241 | if(textAttr & DCA_COMMENT) |
| 242 | { |
| 243 | fgColor.setRgb(0x00, 0x80, 0x00); |
| 244 | } |
| 245 | |
| 246 | bgBrush.setColor(bgColor); |
| 247 | painter.setBackground(bgBrush); |
| 248 | painter.setPen(QPen(fgColor)); |
| 249 | |
| 250 | QString text(QChar(viewdata[viewDataOffset].byte)); |
| 251 | for (width = 1; x + width < visibleCharDims.x; width++) |
| 252 | { |
| 253 | if (textAttr != viewdata[viewDataOffset + width].attrib) |
| 254 | break; |
| 255 | text.append(QChar(viewdata[viewDataOffset + width].byte)); |
| 256 | } |
| 257 | |
| 258 | // Your characters are not guaranteed to take up the entire length x fontWidth x fontHeight, so fill before. |
| 259 | painter.fillRect(x*fontWidth, y*fontHeight, width*fontWidth, fontHeight, bgBrush); |
| 260 | |
| 261 | // There is a touchy interplay between font height, drawing difference, visible position, etc |
| 262 | // Fonts don't get drawn "down and to the left" like boxes, so some wiggling is needed. |
| 263 | painter.drawText(x*fontWidth, (y*fontHeight + (fontHeight*0.80)), text); |
| 264 | } |
| 265 | } |
| 266 | } |
| 267 | #endif |
| 268 | |
| 269 | void DebuggerView::keyPressEvent(QKeyEvent* event) |
| 270 | { |
| 271 | if (m_view == NULL) |
| 272 | return QWidget::keyPressEvent(event); |
| 273 | |
| 274 | Qt::KeyboardModifiers keyMods = QApplication::keyboardModifiers(); |
| 275 | const bool ctrlDown = keyMods.testFlag(Qt::ControlModifier); |
| 276 | |
| 277 | int keyPress = -1; |
| 278 | switch (event->key()) |
| 279 | { |
| 280 | case Qt::Key_Up: |
| 281 | keyPress = DCH_UP; |
| 282 | break; |
| 283 | case Qt::Key_Down: |
| 284 | keyPress = DCH_DOWN; |
| 285 | break; |
| 286 | case Qt::Key_Left: |
| 287 | keyPress = DCH_LEFT; |
| 288 | if (ctrlDown) keyPress = DCH_CTRLLEFT; |
| 289 | break; |
| 290 | case Qt::Key_Right: |
| 291 | keyPress = DCH_RIGHT; |
| 292 | if (ctrlDown) keyPress = DCH_CTRLRIGHT; |
| 293 | break; |
| 294 | case Qt::Key_PageUp: |
| 295 | keyPress = DCH_PUP; |
| 296 | break; |
| 297 | case Qt::Key_PageDown: |
| 298 | keyPress = DCH_PDOWN; |
| 299 | break; |
| 300 | case Qt::Key_Home: |
| 301 | keyPress = DCH_HOME; |
| 302 | if (ctrlDown) keyPress = DCH_CTRLHOME; |
| 303 | break; |
| 304 | case Qt::Key_End: |
| 305 | keyPress = DCH_END; |
| 306 | if (ctrlDown) keyPress = DCH_CTRLEND; |
| 307 | break; |
| 308 | case Qt::Key_0: keyPress = '0'; break; |
| 309 | case Qt::Key_1: keyPress = '1'; break; |
| 310 | case Qt::Key_2: keyPress = '2'; break; |
| 311 | case Qt::Key_3: keyPress = '3'; break; |
| 312 | case Qt::Key_4: keyPress = '4'; break; |
| 313 | case Qt::Key_5: keyPress = '5'; break; |
| 314 | case Qt::Key_6: keyPress = '6'; break; |
| 315 | case Qt::Key_7: keyPress = '7'; break; |
| 316 | case Qt::Key_8: keyPress = '8'; break; |
| 317 | case Qt::Key_9: keyPress = '9'; break; |
| 318 | case Qt::Key_A: keyPress = 'a'; break; |
| 319 | case Qt::Key_B: keyPress = 'b'; break; |
| 320 | case Qt::Key_C: keyPress = 'c'; break; |
| 321 | case Qt::Key_D: keyPress = 'd'; break; |
| 322 | case Qt::Key_E: keyPress = 'e'; break; |
| 323 | case Qt::Key_F: keyPress = 'f'; break; |
| 324 | default: |
| 325 | return QWidget::keyPressEvent(event); |
| 326 | } |
| 327 | |
| 328 | m_view->set_cursor_visible(true); |
| 329 | m_view->process_char(keyPress); |
| 330 | |
| 331 | // Catch the view up with the cursor |
| 332 | verticalScrollBar()->setValue(m_view->visible_position().y); |
| 333 | |
| 334 | viewport()->update(); |
| 335 | update(); |
| 336 | } |
| 337 | |
| 338 | |
| 339 | void DebuggerView::mousePressEvent(QMouseEvent* event) |
| 340 | { |
| 341 | if (m_view == NULL) |
| 342 | return; |
| 343 | |
| 344 | if (event->button() == Qt::LeftButton) |
| 345 | { |
| 346 | QFontMetrics actualFont = fontMetrics(); |
| 347 | const double fontWidth = actualFont.width(QString(100, '_')) / 100.; |
| 348 | const int fontHeight = MAX(1, actualFont.height()); |
| 349 | |
| 350 | debug_view_xy topLeft = m_view->visible_position(); |
| 351 | debug_view_xy clickViewPosition; |
| 352 | clickViewPosition.x = topLeft.x + (event->x() / fontWidth); |
| 353 | clickViewPosition.y = topLeft.y + (event->y() / fontHeight); |
| 354 | m_view->process_click(DCK_LEFT_CLICK, clickViewPosition); |
| 355 | |
| 356 | viewport()->update(); |
| 357 | update(); |
| 358 | } |
| 359 | } |
| 360 | |
| 361 | |
| 362 | void DebuggerView::verticalScrollSlot(int value) |
| 363 | { |
| 364 | m_view->set_visible_position(debug_view_xy(horizontalScrollBar()->value(), value)); |
| 365 | } |
| 366 | |
| 367 | |
| 368 | void DebuggerView::horizontalScrollSlot(int value) |
| 369 | { |
| 370 | m_view->set_visible_position(debug_view_xy(value, verticalScrollBar()->value())); |
| 371 | } |
| 372 | |
| 373 | |
| 374 | void DebuggerView::debuggerViewUpdate(debug_view& debugView, void* osdPrivate) |
| 375 | { |
| 376 | // Get a handle to the DebuggerView being updated & redraw |
| 377 | DebuggerView* dView = (DebuggerView*)osdPrivate; |
| 378 | dView->verticalScrollBar()->setValue(dView->view()->visible_position().y); |
| 379 | dView->horizontalScrollBar()->setValue(dView->view()->visible_position().x); |
| 380 | dView->viewport()->update(); |
| 381 | dView->update(); |
| 382 | } |
trunk/src/osd/modules/debugger/qt/debugqtwindow.c
| r0 | r243602 | |
| 1 | #define NO_MEM_TRACKING |
| 2 | |
| 3 | #include "debugqtwindow.h" |
| 4 | #include "debugqtlogwindow.h" |
| 5 | #include "debugqtdasmwindow.h" |
| 6 | #include "debugqtmemorywindow.h" |
| 7 | #include "debugqtbreakpointswindow.h" |
| 8 | #include "debugqtdeviceswindow.h" |
| 9 | |
| 10 | bool WindowQt::s_refreshAll = false; |
| 11 | bool WindowQt::s_hideAll = false; |
| 12 | |
| 13 | |
| 14 | // Since all debug windows are intended to be top-level, this inherited |
| 15 | // constructor is always called with a NULL parent. The passed-in parent widget, |
| 16 | // however, is often used to place each child window & the code to do this can |
| 17 | // be found in most of the inherited classes. |
| 18 | |
| 19 | WindowQt::WindowQt(running_machine* machine, QWidget* parent) : |
| 20 | QMainWindow(parent), |
| 21 | m_machine(machine) |
| 22 | { |
| 23 | setAttribute(Qt::WA_DeleteOnClose, true); |
| 24 | |
| 25 | // The Debug menu bar |
| 26 | QAction* debugActOpenMemory = new QAction("New &Memory Window", this); |
| 27 | debugActOpenMemory->setShortcut(QKeySequence("Ctrl+M")); |
| 28 | connect(debugActOpenMemory, SIGNAL(triggered()), this, SLOT(debugActOpenMemory())); |
| 29 | |
| 30 | QAction* debugActOpenDasm = new QAction("New &Dasm Window", this); |
| 31 | debugActOpenDasm->setShortcut(QKeySequence("Ctrl+D")); |
| 32 | connect(debugActOpenDasm, SIGNAL(triggered()), this, SLOT(debugActOpenDasm())); |
| 33 | |
| 34 | QAction* debugActOpenLog = new QAction("New &Log Window", this); |
| 35 | debugActOpenLog->setShortcut(QKeySequence("Ctrl+L")); |
| 36 | connect(debugActOpenLog, SIGNAL(triggered()), this, SLOT(debugActOpenLog())); |
| 37 | |
| 38 | QAction* debugActOpenPoints = new QAction("New &Break|Watchpoints Window", this); |
| 39 | debugActOpenPoints->setShortcut(QKeySequence("Ctrl+B")); |
| 40 | connect(debugActOpenPoints, SIGNAL(triggered()), this, SLOT(debugActOpenPoints())); |
| 41 | |
| 42 | QAction* debugActOpenDevices = new QAction("New D&evices Window", this); |
| 43 | debugActOpenDevices->setShortcut(QKeySequence("Shift+Ctrl+D")); |
| 44 | connect(debugActOpenDevices, SIGNAL(triggered()), this, SLOT(debugActOpenDevices())); |
| 45 | |
| 46 | QAction* dbgActRun = new QAction("Run", this); |
| 47 | dbgActRun->setShortcut(Qt::Key_F5); |
| 48 | connect(dbgActRun, SIGNAL(triggered()), this, SLOT(debugActRun())); |
| 49 | |
| 50 | QAction* dbgActRunAndHide = new QAction("Run And Hide Debugger", this); |
| 51 | dbgActRunAndHide->setShortcut(Qt::Key_F12); |
| 52 | connect(dbgActRunAndHide, SIGNAL(triggered()), this, SLOT(debugActRunAndHide())); |
| 53 | |
| 54 | QAction* dbgActRunToNextCpu = new QAction("Run to Next CPU", this); |
| 55 | dbgActRunToNextCpu->setShortcut(Qt::Key_F6); |
| 56 | connect(dbgActRunToNextCpu, SIGNAL(triggered()), this, SLOT(debugActRunToNextCpu())); |
| 57 | |
| 58 | QAction* dbgActRunNextInt = new QAction("Run to Next Interrupt on This CPU", this); |
| 59 | dbgActRunNextInt->setShortcut(Qt::Key_F7); |
| 60 | connect(dbgActRunNextInt, SIGNAL(triggered()), this, SLOT(debugActRunNextInt())); |
| 61 | |
| 62 | QAction* dbgActRunNextVBlank = new QAction("Run to Next VBlank", this); |
| 63 | dbgActRunNextVBlank->setShortcut(Qt::Key_F8); |
| 64 | connect(dbgActRunNextVBlank, SIGNAL(triggered()), this, SLOT(debugActRunNextVBlank())); |
| 65 | |
| 66 | QAction* dbgActStepInto = new QAction("Step Into", this); |
| 67 | dbgActStepInto->setShortcut(Qt::Key_F11); |
| 68 | connect(dbgActStepInto, SIGNAL(triggered()), this, SLOT(debugActStepInto())); |
| 69 | |
| 70 | QAction* dbgActStepOver = new QAction("Step Over", this); |
| 71 | dbgActStepOver->setShortcut(Qt::Key_F10); |
| 72 | connect(dbgActStepOver, SIGNAL(triggered()), this, SLOT(debugActStepOver())); |
| 73 | |
| 74 | QAction* dbgActStepOut = new QAction("Step Out", this); |
| 75 | dbgActStepOut->setShortcut(QKeySequence("Shift+F11")); |
| 76 | connect(dbgActStepOut, SIGNAL(triggered()), this, SLOT(debugActStepOut())); |
| 77 | |
| 78 | QAction* dbgActSoftReset = new QAction("Soft Reset", this); |
| 79 | dbgActSoftReset->setShortcut(Qt::Key_F3); |
| 80 | connect(dbgActSoftReset, SIGNAL(triggered()), this, SLOT(debugActSoftReset())); |
| 81 | |
| 82 | QAction* dbgActHardReset = new QAction("Hard Reset", this); |
| 83 | dbgActHardReset->setShortcut(QKeySequence("Shift+F3")); |
| 84 | connect(dbgActHardReset, SIGNAL(triggered()), this, SLOT(debugActHardReset())); |
| 85 | |
| 86 | QAction* dbgActClose = new QAction("Close &Window", this); |
| 87 | dbgActClose->setShortcut(QKeySequence::Close); |
| 88 | connect(dbgActClose, SIGNAL(triggered()), this, SLOT(debugActClose())); |
| 89 | |
| 90 | QAction* dbgActQuit = new QAction("&Quit", this); |
| 91 | dbgActQuit->setShortcut(QKeySequence::Quit); |
| 92 | connect(dbgActQuit, SIGNAL(triggered()), this, SLOT(debugActQuit())); |
| 93 | |
| 94 | // Construct the menu |
| 95 | QMenu* debugMenu = menuBar()->addMenu("&Debug"); |
| 96 | debugMenu->addAction(debugActOpenMemory); |
| 97 | debugMenu->addAction(debugActOpenDasm); |
| 98 | debugMenu->addAction(debugActOpenLog); |
| 99 | debugMenu->addAction(debugActOpenPoints); |
| 100 | debugMenu->addAction(debugActOpenDevices); |
| 101 | debugMenu->addSeparator(); |
| 102 | debugMenu->addAction(dbgActRun); |
| 103 | debugMenu->addAction(dbgActRunAndHide); |
| 104 | debugMenu->addAction(dbgActRunToNextCpu); |
| 105 | debugMenu->addAction(dbgActRunNextInt); |
| 106 | debugMenu->addAction(dbgActRunNextVBlank); |
| 107 | debugMenu->addSeparator(); |
| 108 | debugMenu->addAction(dbgActStepInto); |
| 109 | debugMenu->addAction(dbgActStepOver); |
| 110 | debugMenu->addAction(dbgActStepOut); |
| 111 | debugMenu->addSeparator(); |
| 112 | debugMenu->addAction(dbgActSoftReset); |
| 113 | debugMenu->addAction(dbgActHardReset); |
| 114 | debugMenu->addSeparator(); |
| 115 | debugMenu->addAction(dbgActClose); |
| 116 | debugMenu->addAction(dbgActQuit); |
| 117 | } |
| 118 | |
| 119 | |
| 120 | WindowQt::~WindowQt() |
| 121 | { |
| 122 | } |
| 123 | |
| 124 | void WindowQt::debugActOpenMemory() |
| 125 | { |
| 126 | MemoryWindow* foo = new MemoryWindow(m_machine, this); |
| 127 | // A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon |
| 128 | // foo->setWindowFlags(Qt::Dialog); |
| 129 | // foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint); |
| 130 | foo->show(); |
| 131 | } |
| 132 | |
| 133 | |
| 134 | void WindowQt::debugActOpenDasm() |
| 135 | { |
| 136 | DasmWindow* foo = new DasmWindow(m_machine, this); |
| 137 | // A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon |
| 138 | // foo->setWindowFlags(Qt::Dialog); |
| 139 | // foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint); |
| 140 | foo->show(); |
| 141 | } |
| 142 | |
| 143 | |
| 144 | void WindowQt::debugActOpenLog() |
| 145 | { |
| 146 | LogWindow* foo = new LogWindow(m_machine, this); |
| 147 | // A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon |
| 148 | // foo->setWindowFlags(Qt::Dialog); |
| 149 | // foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint); |
| 150 | foo->show(); |
| 151 | } |
| 152 | |
| 153 | |
| 154 | void WindowQt::debugActOpenPoints() |
| 155 | { |
| 156 | BreakpointsWindow* foo = new BreakpointsWindow(m_machine, this); |
| 157 | // A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon |
| 158 | // foo->setWindowFlags(Qt::Dialog); |
| 159 | // foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint); |
| 160 | foo->show(); |
| 161 | } |
| 162 | |
| 163 | |
| 164 | void WindowQt::debugActOpenDevices() |
| 165 | { |
| 166 | DevicesWindow* foo = new DevicesWindow(m_machine, this); |
| 167 | // A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon |
| 168 | // foo->setWindowFlags(Qt::Dialog); |
| 169 | // foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint); |
| 170 | foo->show(); |
| 171 | } |
| 172 | |
| 173 | |
| 174 | void WindowQt::debugActRun() |
| 175 | { |
| 176 | debug_cpu_get_visible_cpu(*m_machine)->debug()->go(); |
| 177 | } |
| 178 | |
| 179 | void WindowQt::debugActRunAndHide() |
| 180 | { |
| 181 | debug_cpu_get_visible_cpu(*m_machine)->debug()->go(); |
| 182 | hideAll(); |
| 183 | } |
| 184 | |
| 185 | void WindowQt::debugActRunToNextCpu() |
| 186 | { |
| 187 | debug_cpu_get_visible_cpu(*m_machine)->debug()->go_next_device(); |
| 188 | } |
| 189 | |
| 190 | void WindowQt::debugActRunNextInt() |
| 191 | { |
| 192 | debug_cpu_get_visible_cpu(*m_machine)->debug()->go_interrupt(); |
| 193 | } |
| 194 | |
| 195 | void WindowQt::debugActRunNextVBlank() |
| 196 | { |
| 197 | debug_cpu_get_visible_cpu(*m_machine)->debug()->go_vblank(); |
| 198 | } |
| 199 | |
| 200 | void WindowQt::debugActStepInto() |
| 201 | { |
| 202 | debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step(); |
| 203 | } |
| 204 | |
| 205 | void WindowQt::debugActStepOver() |
| 206 | { |
| 207 | debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step_over(); |
| 208 | } |
| 209 | |
| 210 | void WindowQt::debugActStepOut() |
| 211 | { |
| 212 | debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step_out(); |
| 213 | } |
| 214 | |
| 215 | void WindowQt::debugActSoftReset() |
| 216 | { |
| 217 | m_machine->schedule_soft_reset(); |
| 218 | debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step(); |
| 219 | } |
| 220 | |
| 221 | void WindowQt::debugActHardReset() |
| 222 | { |
| 223 | m_machine->schedule_hard_reset(); |
| 224 | } |
| 225 | |
| 226 | void WindowQt::debugActClose() |
| 227 | { |
| 228 | close(); |
| 229 | } |
| 230 | |
| 231 | void WindowQt::debugActQuit() |
| 232 | { |
| 233 | m_machine->schedule_exit(); |
| 234 | } |
| 235 | |
| 236 | |
| 237 | //========================================================================= |
| 238 | // WindowQtConfig |
| 239 | //========================================================================= |
| 240 | void WindowQtConfig::buildFromQWidget(QWidget* widget) |
| 241 | { |
| 242 | m_position.setX(widget->geometry().topLeft().x()); |
| 243 | m_position.setY(widget->geometry().topLeft().y()); |
| 244 | m_size.setX(widget->size().width()); |
| 245 | m_size.setY(widget->size().height()); |
| 246 | } |
| 247 | |
| 248 | |
| 249 | void WindowQtConfig::applyToQWidget(QWidget* widget) |
| 250 | { |
| 251 | widget->setGeometry(m_position.x(), m_position.y(), m_size.x(), m_size.y()); |
| 252 | } |
| 253 | |
| 254 | |
| 255 | void WindowQtConfig::addToXmlDataNode(xml_data_node* node) const |
| 256 | { |
| 257 | xml_set_attribute_int(node, "type", m_type); |
| 258 | xml_set_attribute_int(node, "position_x", m_position.x()); |
| 259 | xml_set_attribute_int(node, "position_y", m_position.y()); |
| 260 | xml_set_attribute_int(node, "size_x", m_size.x()); |
| 261 | xml_set_attribute_int(node, "size_y", m_size.y()); |
| 262 | } |
| 263 | |
| 264 | |
| 265 | void WindowQtConfig::recoverFromXmlNode(xml_data_node* node) |
| 266 | { |
| 267 | m_size.setX(xml_get_attribute_int(node, "size_x", m_size.x())); |
| 268 | m_size.setY(xml_get_attribute_int(node, "size_y", m_size.y())); |
| 269 | m_position.setX(xml_get_attribute_int(node, "position_x", m_position.x())); |
| 270 | m_position.setY(xml_get_attribute_int(node, "position_y", m_position.y())); |
| 271 | m_type = (WindowQtConfig::WindowType)xml_get_attribute_int(node, "type", m_type); |
| 272 | } |
trunk/src/osd/modules/debugger/qt/deviceinformationwindow.c
| r243601 | r243602 | |
| 1 | | #define NO_MEM_TRACKING |
| 2 | | |
| 3 | | #include "deviceinformationwindow.h" |
| 4 | | |
| 5 | | |
| 6 | | DeviceInformationWindow::DeviceInformationWindow(running_machine* machine, device_t* device, QWidget* parent) : |
| 7 | | WindowQt(machine, NULL) |
| 8 | | { |
| 9 | | m_device = device; |
| 10 | | |
| 11 | | if (parent != NULL) |
| 12 | | { |
| 13 | | QPoint parentPos = parent->pos(); |
| 14 | | setGeometry(parentPos.x()+100, parentPos.y()+100, 600, 400); |
| 15 | | } |
| 16 | | |
| 17 | | if(m_device) |
| 18 | | fill_device_information(); |
| 19 | | } |
| 20 | | |
| 21 | | |
| 22 | | DeviceInformationWindow::~DeviceInformationWindow() |
| 23 | | { |
| 24 | | } |
| 25 | | |
| 26 | | void DeviceInformationWindow::fill_device_information() |
| 27 | | { |
| 28 | | char title[4069]; |
| 29 | | sprintf(title, "Debug: Device %s", m_device->tag()); |
| 30 | | setWindowTitle(title); |
| 31 | | |
| 32 | | |
| 33 | | QFrame *mainWindowFrame = new QFrame(this); |
| 34 | | QVBoxLayout *vLayout = new QVBoxLayout(mainWindowFrame); |
| 35 | | vLayout->setObjectName("vlayout"); |
| 36 | | vLayout->setSpacing(3); |
| 37 | | vLayout->setContentsMargins(2,2,2,2); |
| 38 | | |
| 39 | | QFrame *primaryFrame = new QFrame(mainWindowFrame); |
| 40 | | primaryFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); |
| 41 | | QGridLayout *gl1 = new QGridLayout(primaryFrame); |
| 42 | | gl1->addWidget(new QLabel(QString("Tag"), primaryFrame), 0, 0); |
| 43 | | gl1->addWidget(new QLabel(QString(m_device->tag()), primaryFrame), 0, 1); |
| 44 | | gl1->addWidget(new QLabel(QString("Name"), primaryFrame), 1, 0); |
| 45 | | gl1->addWidget(new QLabel(QString(m_device->name()), primaryFrame), 1, 1); |
| 46 | | gl1->addWidget(new QLabel(QString("Shortname"), primaryFrame), 2, 0); |
| 47 | | gl1->addWidget(new QLabel(QString(m_device->shortname()), primaryFrame), 2, 1); |
| 48 | | |
| 49 | | int cpos = 3; |
| 50 | | device_interface *intf = m_device->first_interface(); |
| 51 | | if(intf) { |
| 52 | | gl1->addWidget(new QLabel(QString("Interfaces"), primaryFrame), cpos, 0); |
| 53 | | while(intf) { |
| 54 | | gl1->addWidget(new QLabel(QString(intf->interface_type()), primaryFrame), cpos, 1); |
| 55 | | cpos++; |
| 56 | | intf = intf->interface_next(); |
| 57 | | } |
| 58 | | } |
| 59 | | |
| 60 | | vLayout->addWidget(primaryFrame); |
| 61 | | |
| 62 | | device_memory_interface *d_memory; |
| 63 | | if(m_device->interface(d_memory)) { |
| 64 | | QFrame *f = new QFrame(mainWindowFrame); |
| 65 | | f->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); |
| 66 | | QVBoxLayout *vb = new QVBoxLayout(f); |
| 67 | | bool first = true; |
| 68 | | for(address_spacenum i=AS_0; i<ADDRESS_SPACES; i++) |
| 69 | | if(d_memory->has_space(i)) { |
| 70 | | QFrame *ff = new QFrame(f); |
| 71 | | QHBoxLayout *hb = new QHBoxLayout(ff); |
| 72 | | if(first) { |
| 73 | | hb->addWidget(new QLabel("Memory maps")); |
| 74 | | first = false; |
| 75 | | } |
| 76 | | hb->addStretch(); |
| 77 | | hb->addWidget(new QLabel(d_memory->space_config(i)->name())); |
| 78 | | vb->addWidget(ff); |
| 79 | | } |
| 80 | | vLayout->addWidget(f); |
| 81 | | } |
| 82 | | |
| 83 | | vLayout->addStretch(); |
| 84 | | |
| 85 | | setCentralWidget(mainWindowFrame); |
| 86 | | } |
| 87 | | |
| 88 | | void DeviceInformationWindow::set_device(const char *tag) |
| 89 | | { |
| 90 | | m_device = m_machine->device(tag); |
| 91 | | if(!m_device) |
| 92 | | m_device = &m_machine->root_device(); |
| 93 | | fill_device_information(); |
| 94 | | } |
| 95 | | |
| 96 | | const char *DeviceInformationWindow::device_tag() const |
| 97 | | { |
| 98 | | return m_device->tag(); |
| 99 | | } |
| 100 | | |
| 101 | | |
| 102 | | //========================================================================= |
| 103 | | // DeviceInformationWindowQtConfig |
| 104 | | //========================================================================= |
| 105 | | void DeviceInformationWindowQtConfig::buildFromQWidget(QWidget* widget) |
| 106 | | { |
| 107 | | WindowQtConfig::buildFromQWidget(widget); |
| 108 | | DeviceInformationWindow* window = dynamic_cast<DeviceInformationWindow*>(widget); |
| 109 | | m_device_tag = window->device_tag(); |
| 110 | | } |
| 111 | | |
| 112 | | |
| 113 | | void DeviceInformationWindowQtConfig::applyToQWidget(QWidget* widget) |
| 114 | | { |
| 115 | | WindowQtConfig::applyToQWidget(widget); |
| 116 | | DeviceInformationWindow* window = dynamic_cast<DeviceInformationWindow*>(widget); |
| 117 | | window->set_device(m_device_tag.cstr()); |
| 118 | | } |
| 119 | | |
| 120 | | |
| 121 | | void DeviceInformationWindowQtConfig::addToXmlDataNode(xml_data_node* node) const |
| 122 | | { |
| 123 | | WindowQtConfig::addToXmlDataNode(node); |
| 124 | | xml_set_attribute(node, "device-tag", m_device_tag); |
| 125 | | } |
| 126 | | |
| 127 | | |
| 128 | | void DeviceInformationWindowQtConfig::recoverFromXmlNode(xml_data_node* node) |
| 129 | | { |
| 130 | | WindowQtConfig::recoverFromXmlNode(node); |
| 131 | | m_device_tag = xml_get_attribute_string(node, "device-tag", ":"); |
| 132 | | } |
trunk/src/osd/modules/debugger/qt/deviceswindow.c
| r243601 | r243602 | |
| 1 | | #define NO_MEM_TRACKING |
| 2 | | |
| 3 | | #include "deviceswindow.h" |
| 4 | | #include "deviceinformationwindow.h" |
| 5 | | |
| 6 | | DevicesWindowModel::DevicesWindowModel(running_machine *machine, QObject *parent) |
| 7 | | { |
| 8 | | m_machine = machine; |
| 9 | | } |
| 10 | | |
| 11 | | DevicesWindowModel::~DevicesWindowModel() |
| 12 | | { |
| 13 | | } |
| 14 | | |
| 15 | | QVariant DevicesWindowModel::data(const QModelIndex &index, int role) const |
| 16 | | { |
| 17 | | if(!index.isValid() || role != Qt::DisplayRole) |
| 18 | | return QVariant(); |
| 19 | | |
| 20 | | device_t *dev = static_cast<device_t *>(index.internalPointer()); |
| 21 | | switch(index.column()) { |
| 22 | | case 0: return dev == &m_machine->root_device() ? QString("<root>") : QString(dev->basetag()); |
| 23 | | case 1: return QString(dev->name()); |
| 24 | | } |
| 25 | | |
| 26 | | return QVariant(); |
| 27 | | } |
| 28 | | |
| 29 | | Qt::ItemFlags DevicesWindowModel::flags(const QModelIndex &index) const |
| 30 | | { |
| 31 | | if(!index.isValid()) |
| 32 | | return 0; |
| 33 | | |
| 34 | | return QAbstractItemModel::flags(index); |
| 35 | | } |
| 36 | | |
| 37 | | QVariant DevicesWindowModel::headerData(int section, Qt::Orientation orientation, int role) const |
| 38 | | { |
| 39 | | if(role != Qt::DisplayRole || section < 0 || section >= 2) |
| 40 | | return QVariant(); |
| 41 | | return QString(section ? "Name" : "Tag"); |
| 42 | | } |
| 43 | | |
| 44 | | QModelIndex DevicesWindowModel::index(int row, int column, const QModelIndex &parent) const |
| 45 | | { |
| 46 | | if(!hasIndex(row, column, parent)) |
| 47 | | return QModelIndex(); |
| 48 | | |
| 49 | | device_t *target = NULL; |
| 50 | | |
| 51 | | if(!parent.isValid()) { |
| 52 | | if(row == 0) |
| 53 | | target = &m_machine->root_device(); |
| 54 | | |
| 55 | | } else { |
| 56 | | device_t *dparent = static_cast<device_t *>(parent.internalPointer()); |
| 57 | | int count = row; |
| 58 | | for(target = dparent->first_subdevice(); count && target; target = target->next()) |
| 59 | | count--; |
| 60 | | } |
| 61 | | |
| 62 | | if(target) |
| 63 | | return createIndex(row, column, target); |
| 64 | | |
| 65 | | return QModelIndex(); |
| 66 | | } |
| 67 | | |
| 68 | | QModelIndex DevicesWindowModel::parent(const QModelIndex &index) const |
| 69 | | { |
| 70 | | if(!index.isValid()) |
| 71 | | return QModelIndex(); |
| 72 | | |
| 73 | | device_t *dchild = static_cast<device_t *>(index.internalPointer()); |
| 74 | | device_t *dparent = dchild->owner(); |
| 75 | | |
| 76 | | if(!dparent) |
| 77 | | return QModelIndex(); |
| 78 | | |
| 79 | | device_t *dpp = dparent->owner(); |
| 80 | | int row = 0; |
| 81 | | if(dpp) { |
| 82 | | for(device_t *child = dpp->first_subdevice(); child && child != dparent; child = child->next()) |
| 83 | | row++; |
| 84 | | } |
| 85 | | return createIndex(row, 0, dparent); |
| 86 | | } |
| 87 | | |
| 88 | | int DevicesWindowModel::rowCount(const QModelIndex &parent) const |
| 89 | | { |
| 90 | | if(!parent.isValid()) |
| 91 | | return 1; |
| 92 | | |
| 93 | | device_t *dparent = static_cast<device_t *>(parent.internalPointer()); |
| 94 | | int count = 0; |
| 95 | | for(device_t *child = dparent->first_subdevice(); child; child = child->next()) |
| 96 | | count++; |
| 97 | | |
| 98 | | return count; |
| 99 | | } |
| 100 | | |
| 101 | | int DevicesWindowModel::columnCount(const QModelIndex &parent) const |
| 102 | | { |
| 103 | | return 2; |
| 104 | | } |
| 105 | | |
| 106 | | |
| 107 | | |
| 108 | | DevicesWindow::DevicesWindow(running_machine* machine, QWidget* parent) : |
| 109 | | WindowQt(machine, NULL), |
| 110 | | m_devices_model(machine) |
| 111 | | { |
| 112 | | m_selected_device = NULL; |
| 113 | | |
| 114 | | setWindowTitle("Debug: All Devices"); |
| 115 | | |
| 116 | | if (parent != NULL) |
| 117 | | { |
| 118 | | QPoint parentPos = parent->pos(); |
| 119 | | setGeometry(parentPos.x()+100, parentPos.y()+100, 600, 400); |
| 120 | | } |
| 121 | | |
| 122 | | // |
| 123 | | // The tree widget |
| 124 | | // |
| 125 | | m_devices_view = new QTreeView(this); |
| 126 | | m_devices_view->setModel(&m_devices_model); |
| 127 | | m_devices_view->expandAll(); |
| 128 | | m_devices_view->resizeColumnToContents(0); |
| 129 | | connect(m_devices_view->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &,const QModelIndex &)), this, SLOT(currentRowChanged(const QModelIndex &,const QModelIndex &))); |
| 130 | | connect(m_devices_view, SIGNAL(activated(const QModelIndex &)), this, SLOT(activated(const QModelIndex &))); |
| 131 | | setCentralWidget(m_devices_view); |
| 132 | | } |
| 133 | | |
| 134 | | |
| 135 | | DevicesWindow::~DevicesWindow() |
| 136 | | { |
| 137 | | } |
| 138 | | |
| 139 | | |
| 140 | | void DevicesWindow::currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous) |
| 141 | | { |
| 142 | | m_selected_device = static_cast<device_t *>(current.internalPointer()); |
| 143 | | } |
| 144 | | |
| 145 | | |
| 146 | | void DevicesWindow::activated(const QModelIndex &index) |
| 147 | | { |
| 148 | | device_t *dev = static_cast<device_t *>(index.internalPointer()); |
| 149 | | (new DeviceInformationWindow(m_machine, dev, this))->show(); |
| 150 | | } |
| 151 | | |
| 152 | | |
| 153 | | |
| 154 | | //========================================================================= |
| 155 | | // DevicesWindowQtConfig |
| 156 | | //========================================================================= |
| 157 | | void DevicesWindowQtConfig::buildFromQWidget(QWidget* widget) |
| 158 | | { |
| 159 | | WindowQtConfig::buildFromQWidget(widget); |
| 160 | | // DevicesWindow* window = dynamic_cast<DevicesWindow*>(widget); |
| 161 | | } |
| 162 | | |
| 163 | | |
| 164 | | void DevicesWindowQtConfig::applyToQWidget(QWidget* widget) |
| 165 | | { |
| 166 | | WindowQtConfig::applyToQWidget(widget); |
| 167 | | // DevicesWindow* window = dynamic_cast<DevicesWindow*>(widget); |
| 168 | | } |
| 169 | | |
| 170 | | |
| 171 | | void DevicesWindowQtConfig::addToXmlDataNode(xml_data_node* node) const |
| 172 | | { |
| 173 | | WindowQtConfig::addToXmlDataNode(node); |
| 174 | | } |
| 175 | | |
| 176 | | |
| 177 | | void DevicesWindowQtConfig::recoverFromXmlNode(xml_data_node* node) |
| 178 | | { |
| 179 | | WindowQtConfig::recoverFromXmlNode(node); |
| 180 | | } |
trunk/src/osd/modules/debugger/qt/mainwindow.c
| r243601 | r243602 | |
| 1 | | #define NO_MEM_TRACKING |
| 2 | | |
| 3 | | #include "mainwindow.h" |
| 4 | | |
| 5 | | #include "debug/debugcon.h" |
| 6 | | #include "debug/debugcpu.h" |
| 7 | | #include "debug/dvdisasm.h" |
| 8 | | |
| 9 | | |
| 10 | | MainWindow::MainWindow(running_machine* machine, QWidget* parent) : |
| 11 | | WindowQt(machine, NULL), |
| 12 | | m_historyIndex(0), |
| 13 | | m_inputHistory() |
| 14 | | { |
| 15 | | setGeometry(300, 300, 1000, 600); |
| 16 | | |
| 17 | | // |
| 18 | | // The main frame and its input and log widgets |
| 19 | | // |
| 20 | | QFrame* mainWindowFrame = new QFrame(this); |
| 21 | | |
| 22 | | // The input line |
| 23 | | m_inputEdit = new QLineEdit(mainWindowFrame); |
| 24 | | connect(m_inputEdit, SIGNAL(returnPressed()), this, SLOT(executeCommand())); |
| 25 | | m_inputEdit->installEventFilter(this); |
| 26 | | |
| 27 | | |
| 28 | | // The log view |
| 29 | | m_consoleView = new DebuggerView(DVT_CONSOLE, |
| 30 | | m_machine, |
| 31 | | mainWindowFrame); |
| 32 | | m_consoleView->setFocusPolicy(Qt::NoFocus); |
| 33 | | m_consoleView->setPreferBottom(true); |
| 34 | | |
| 35 | | QVBoxLayout* vLayout = new QVBoxLayout(mainWindowFrame); |
| 36 | | vLayout->addWidget(m_consoleView); |
| 37 | | vLayout->addWidget(m_inputEdit); |
| 38 | | vLayout->setSpacing(3); |
| 39 | | vLayout->setContentsMargins(4,0,4,2); |
| 40 | | |
| 41 | | setCentralWidget(mainWindowFrame); |
| 42 | | |
| 43 | | // |
| 44 | | // Options Menu |
| 45 | | // |
| 46 | | // Create two commands |
| 47 | | QAction* breakpointSetAct = new QAction("Toggle Breakpoint At Cursor", this); |
| 48 | | QAction* runToCursorAct = new QAction("Run To Cursor", this); |
| 49 | | breakpointSetAct->setShortcut(Qt::Key_F9); |
| 50 | | runToCursorAct->setShortcut(Qt::Key_F4); |
| 51 | | connect(breakpointSetAct, SIGNAL(triggered(bool)), this, SLOT(toggleBreakpointAtCursor(bool))); |
| 52 | | connect(runToCursorAct, SIGNAL(triggered(bool)), this, SLOT(runToCursor(bool))); |
| 53 | | |
| 54 | | // Right bar options |
| 55 | | QActionGroup* rightBarGroup = new QActionGroup(this); |
| 56 | | rightBarGroup->setObjectName("rightbargroup"); |
| 57 | | QAction* rightActRaw = new QAction("Raw Opcodes", this); |
| 58 | | QAction* rightActEncrypted = new QAction("Encrypted Opcodes", this); |
| 59 | | QAction* rightActComments = new QAction("Comments", this); |
| 60 | | rightActRaw->setCheckable(true); |
| 61 | | rightActEncrypted->setCheckable(true); |
| 62 | | rightActComments->setCheckable(true); |
| 63 | | rightActRaw->setActionGroup(rightBarGroup); |
| 64 | | rightActEncrypted->setActionGroup(rightBarGroup); |
| 65 | | rightActComments->setActionGroup(rightBarGroup); |
| 66 | | rightActRaw->setShortcut(QKeySequence("Ctrl+R")); |
| 67 | | rightActEncrypted->setShortcut(QKeySequence("Ctrl+E")); |
| 68 | | rightActComments->setShortcut(QKeySequence("Ctrl+C")); |
| 69 | | rightActRaw->setChecked(true); |
| 70 | | connect(rightBarGroup, SIGNAL(triggered(QAction*)), this, SLOT(rightBarChanged(QAction*))); |
| 71 | | |
| 72 | | // Assemble the options menu |
| 73 | | QMenu* optionsMenu = menuBar()->addMenu("&Options"); |
| 74 | | optionsMenu->addAction(breakpointSetAct); |
| 75 | | optionsMenu->addAction(runToCursorAct); |
| 76 | | optionsMenu->addSeparator(); |
| 77 | | optionsMenu->addActions(rightBarGroup->actions()); |
| 78 | | |
| 79 | | // |
| 80 | | // Images menu |
| 81 | | // |
| 82 | | image_interface_iterator imageIterTest(m_machine->root_device()); |
| 83 | | if (imageIterTest.first() != NULL) |
| 84 | | { |
| 85 | | createImagesMenu(); |
| 86 | | } |
| 87 | | |
| 88 | | // |
| 89 | | // Dock window menu |
| 90 | | // |
| 91 | | QMenu* dockMenu = menuBar()->addMenu("Doc&ks"); |
| 92 | | |
| 93 | | setCorner(Qt::TopRightCorner, Qt::TopDockWidgetArea); |
| 94 | | setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); |
| 95 | | |
| 96 | | // The processor dock |
| 97 | | QDockWidget* cpuDock = new QDockWidget("processor", this); |
| 98 | | cpuDock->setObjectName("cpudock"); |
| 99 | | cpuDock->setAllowedAreas(Qt::LeftDockWidgetArea); |
| 100 | | m_procFrame = new ProcessorDockWidget(m_machine, cpuDock); |
| 101 | | cpuDock->setWidget(dynamic_cast<QWidget*>(m_procFrame)); |
| 102 | | |
| 103 | | addDockWidget(Qt::LeftDockWidgetArea, cpuDock); |
| 104 | | dockMenu->addAction(cpuDock->toggleViewAction()); |
| 105 | | |
| 106 | | // The disassembly dock |
| 107 | | QDockWidget* dasmDock = new QDockWidget("dasm", this); |
| 108 | | dasmDock->setObjectName("dasmdock"); |
| 109 | | dasmDock->setAllowedAreas(Qt::TopDockWidgetArea); |
| 110 | | m_dasmFrame = new DasmDockWidget(m_machine, dasmDock); |
| 111 | | dasmDock->setWidget(m_dasmFrame); |
| 112 | | |
| 113 | | addDockWidget(Qt::TopDockWidgetArea, dasmDock); |
| 114 | | dockMenu->addAction(dasmDock->toggleViewAction()); |
| 115 | | } |
| 116 | | |
| 117 | | |
| 118 | | MainWindow::~MainWindow() |
| 119 | | { |
| 120 | | } |
| 121 | | |
| 122 | | |
| 123 | | void MainWindow::setProcessor(device_t* processor) |
| 124 | | { |
| 125 | | // Cpu swap |
| 126 | | m_procFrame->view()->view()->set_source(*m_procFrame->view()->view()->source_for_device(processor)); |
| 127 | | m_dasmFrame->view()->view()->set_source(*m_dasmFrame->view()->view()->source_for_device(processor)); |
| 128 | | |
| 129 | | // Scrollbar refresh - seems I should be able to do in the DebuggerView |
| 130 | | m_dasmFrame->view()->verticalScrollBar()->setValue(m_dasmFrame->view()->view()->visible_position().y); |
| 131 | | m_dasmFrame->view()->verticalScrollBar()->setValue(m_dasmFrame->view()->view()->visible_position().y); |
| 132 | | |
| 133 | | // Window title |
| 134 | | astring title; |
| 135 | | title.printf("Debug: %s - %s '%s'", m_machine->system().name, processor->name(), processor->tag()); |
| 136 | | setWindowTitle(title.cstr()); |
| 137 | | } |
| 138 | | |
| 139 | | |
| 140 | | // Used to intercept the user clicking 'X' in the upper corner |
| 141 | | void MainWindow::closeEvent(QCloseEvent* event) |
| 142 | | { |
| 143 | | debugActQuit(); |
| 144 | | |
| 145 | | // Insure the window doesn't disappear before we get a chance to save its parameters |
| 146 | | event->ignore(); |
| 147 | | } |
| 148 | | |
| 149 | | |
| 150 | | // Used to intercept the user hitting the up arrow in the input widget |
| 151 | | bool MainWindow::eventFilter(QObject* obj, QEvent* event) |
| 152 | | { |
| 153 | | // Only filter keypresses |
| 154 | | QKeyEvent* keyEvent = NULL; |
| 155 | | if (event->type() == QEvent::KeyPress) |
| 156 | | { |
| 157 | | keyEvent = static_cast<QKeyEvent*>(event); |
| 158 | | } |
| 159 | | else |
| 160 | | { |
| 161 | | return QObject::eventFilter(obj, event); |
| 162 | | } |
| 163 | | |
| 164 | | // Catch up & down keys |
| 165 | | if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down) |
| 166 | | { |
| 167 | | if (keyEvent->key() == Qt::Key_Up) |
| 168 | | { |
| 169 | | if (m_historyIndex > 0) |
| 170 | | m_historyIndex--; |
| 171 | | } |
| 172 | | else if (keyEvent->key() == Qt::Key_Down) |
| 173 | | { |
| 174 | | if (m_historyIndex < m_inputHistory.size()) |
| 175 | | m_historyIndex++; |
| 176 | | } |
| 177 | | |
| 178 | | // Populate the input edit or clear it if you're at the end |
| 179 | | if (m_historyIndex == m_inputHistory.size()) |
| 180 | | { |
| 181 | | m_inputEdit->setText(""); |
| 182 | | } |
| 183 | | else |
| 184 | | { |
| 185 | | m_inputEdit->setText(m_inputHistory[m_historyIndex]); |
| 186 | | } |
| 187 | | } |
| 188 | | else if (keyEvent->key() == Qt::Key_Enter) |
| 189 | | { |
| 190 | | executeCommand(false); |
| 191 | | } |
| 192 | | else |
| 193 | | { |
| 194 | | return QObject::eventFilter(obj, event); |
| 195 | | } |
| 196 | | |
| 197 | | return true; |
| 198 | | } |
| 199 | | |
| 200 | | |
| 201 | | void MainWindow::toggleBreakpointAtCursor(bool changedTo) |
| 202 | | { |
| 203 | | debug_view_disasm* dasmView = downcast<debug_view_disasm*>(m_dasmFrame->view()->view()); |
| 204 | | if (dasmView->cursor_visible()) |
| 205 | | { |
| 206 | | if (debug_cpu_get_visible_cpu(*m_machine) == dasmView->source()->device()) |
| 207 | | { |
| 208 | | offs_t address = downcast<debug_view_disasm *>(dasmView)->selected_address(); |
| 209 | | device_debug *cpuinfo = dasmView->source()->device()->debug(); |
| 210 | | |
| 211 | | // Find an existing breakpoint at this address |
| 212 | | INT32 bpindex = -1; |
| 213 | | for (device_debug::breakpoint* bp = cpuinfo->breakpoint_first(); |
| 214 | | bp != NULL; |
| 215 | | bp = bp->next()) |
| 216 | | { |
| 217 | | if (address == bp->address()) |
| 218 | | { |
| 219 | | bpindex = bp->index(); |
| 220 | | break; |
| 221 | | } |
| 222 | | } |
| 223 | | |
| 224 | | // If none exists, add a new one |
| 225 | | astring command; |
| 226 | | if (bpindex == -1) |
| 227 | | { |
| 228 | | command.printf("bpset 0x%X", address); |
| 229 | | } |
| 230 | | else |
| 231 | | { |
| 232 | | command.printf("bpclear 0x%X", bpindex); |
| 233 | | } |
| 234 | | debug_console_execute_command(*m_machine, command, 1); |
| 235 | | } |
| 236 | | } |
| 237 | | |
| 238 | | refreshAll(); |
| 239 | | } |
| 240 | | |
| 241 | | |
| 242 | | void MainWindow::runToCursor(bool changedTo) |
| 243 | | { |
| 244 | | debug_view_disasm* dasmView = downcast<debug_view_disasm*>(m_dasmFrame->view()->view()); |
| 245 | | if (dasmView->cursor_visible()) |
| 246 | | { |
| 247 | | if (debug_cpu_get_visible_cpu(*m_machine) == dasmView->source()->device()) |
| 248 | | { |
| 249 | | offs_t address = downcast<debug_view_disasm*>(dasmView)->selected_address(); |
| 250 | | astring command; |
| 251 | | command.printf("go 0x%X", address); |
| 252 | | debug_console_execute_command(*m_machine, command, 1); |
| 253 | | } |
| 254 | | } |
| 255 | | } |
| 256 | | |
| 257 | | |
| 258 | | void MainWindow::rightBarChanged(QAction* changedTo) |
| 259 | | { |
| 260 | | debug_view_disasm* dasmView = downcast<debug_view_disasm*>(m_dasmFrame->view()->view()); |
| 261 | | if (changedTo->text() == "Raw Opcodes") |
| 262 | | { |
| 263 | | dasmView->set_right_column(DASM_RIGHTCOL_RAW); |
| 264 | | } |
| 265 | | else if (changedTo->text() == "Encrypted Opcodes") |
| 266 | | { |
| 267 | | dasmView->set_right_column(DASM_RIGHTCOL_ENCRYPTED); |
| 268 | | } |
| 269 | | else if (changedTo->text() == "Comments") |
| 270 | | { |
| 271 | | dasmView->set_right_column(DASM_RIGHTCOL_COMMENTS); |
| 272 | | } |
| 273 | | m_dasmFrame->view()->viewport()->update(); |
| 274 | | } |
| 275 | | |
| 276 | | |
| 277 | | void MainWindow::executeCommand(bool withClear) |
| 278 | | { |
| 279 | | QString command = m_inputEdit->text(); |
| 280 | | |
| 281 | | // A blank command is a "silent step" |
| 282 | | if (command == "") |
| 283 | | { |
| 284 | | debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step(); |
| 285 | | return; |
| 286 | | } |
| 287 | | |
| 288 | | // Send along the command |
| 289 | | debug_console_execute_command(*m_machine, |
| 290 | | command.toLocal8Bit().data(), |
| 291 | | true); |
| 292 | | |
| 293 | | // Add history & set the index to be the top of the stack |
| 294 | | addToHistory(command); |
| 295 | | |
| 296 | | // Clear out the text and reset the history pointer only if asked |
| 297 | | if (withClear) |
| 298 | | { |
| 299 | | m_inputEdit->clear(); |
| 300 | | m_historyIndex = m_inputHistory.size(); |
| 301 | | } |
| 302 | | |
| 303 | | // Refresh |
| 304 | | m_consoleView->viewport()->update(); |
| 305 | | refreshAll(); |
| 306 | | } |
| 307 | | |
| 308 | | |
| 309 | | void MainWindow::mountImage(bool changedTo) |
| 310 | | { |
| 311 | | // The image interface index was assigned to the QAction's data memeber |
| 312 | | const int imageIndex = dynamic_cast<QAction*>(sender())->data().toInt(); |
| 313 | | image_interface_iterator iter(m_machine->root_device()); |
| 314 | | device_image_interface *img = iter.byindex(imageIndex); |
| 315 | | if (img == NULL) |
| 316 | | { |
| 317 | | debug_console_printf(*m_machine, "Something is wrong with the mount menu.\n"); |
| 318 | | refreshAll(); |
| 319 | | return; |
| 320 | | } |
| 321 | | |
| 322 | | // File dialog |
| 323 | | QString filename = QFileDialog::getOpenFileName(this, |
| 324 | | "Select an image file", |
| 325 | | QDir::currentPath(), |
| 326 | | tr("All files (*.*)")); |
| 327 | | |
| 328 | | if (img->load(filename.toUtf8().data()) != IMAGE_INIT_PASS) |
| 329 | | { |
| 330 | | debug_console_printf(*m_machine, "Image could not be mounted.\n"); |
| 331 | | refreshAll(); |
| 332 | | return; |
| 333 | | } |
| 334 | | |
| 335 | | // Activate the unmount menu option |
| 336 | | QAction* unmountAct = sender()->parent()->findChild<QAction*>("unmount"); |
| 337 | | unmountAct->setEnabled(true); |
| 338 | | |
| 339 | | // Set the mount name |
| 340 | | QMenu* parentMenuItem = dynamic_cast<QMenu*>(sender()->parent()); |
| 341 | | QString baseString = parentMenuItem->title(); |
| 342 | | baseString.truncate(baseString.lastIndexOf(QString(" : "))); |
| 343 | | const QString newTitle = baseString + QString(" : ") + QString(img->filename()); |
| 344 | | parentMenuItem->setTitle(newTitle); |
| 345 | | |
| 346 | | debug_console_printf(*m_machine, "Image %s mounted successfully.\n", filename.toUtf8().data()); |
| 347 | | refreshAll(); |
| 348 | | } |
| 349 | | |
| 350 | | |
| 351 | | void MainWindow::unmountImage(bool changedTo) |
| 352 | | { |
| 353 | | // The image interface index was assigned to the QAction's data memeber |
| 354 | | const int imageIndex = dynamic_cast<QAction*>(sender())->data().toInt(); |
| 355 | | image_interface_iterator iter(m_machine->root_device()); |
| 356 | | device_image_interface *img = iter.byindex(imageIndex); |
| 357 | | |
| 358 | | img->unload(); |
| 359 | | |
| 360 | | // Deactivate the unmount menu option |
| 361 | | dynamic_cast<QAction*>(sender())->setEnabled(false); |
| 362 | | |
| 363 | | // Set the mount name |
| 364 | | QMenu* parentMenuItem = dynamic_cast<QMenu*>(sender()->parent()); |
| 365 | | QString baseString = parentMenuItem->title(); |
| 366 | | baseString.truncate(baseString.lastIndexOf(QString(" : "))); |
| 367 | | const QString newTitle = baseString + QString(" : ") + QString("[empty slot]"); |
| 368 | | parentMenuItem->setTitle(newTitle); |
| 369 | | |
| 370 | | debug_console_printf(*m_machine, "Image successfully unmounted.\n"); |
| 371 | | refreshAll(); |
| 372 | | } |
| 373 | | |
| 374 | | |
| 375 | | void MainWindow::debugActClose() |
| 376 | | { |
| 377 | | m_machine->schedule_exit(); |
| 378 | | } |
| 379 | | |
| 380 | | |
| 381 | | void MainWindow::addToHistory(const QString& command) |
| 382 | | { |
| 383 | | if (command == "") |
| 384 | | return; |
| 385 | | |
| 386 | | // Always push back when there is no previous history |
| 387 | | if (m_inputHistory.size() == 0) |
| 388 | | { |
| 389 | | m_inputHistory.push_back(m_inputEdit->text()); |
| 390 | | return; |
| 391 | | } |
| 392 | | |
| 393 | | // If there is previous history, make sure it's not what you just executed |
| 394 | | if (m_inputHistory.back() != m_inputEdit->text()) |
| 395 | | { |
| 396 | | m_inputHistory.push_back(m_inputEdit->text()); |
| 397 | | } |
| 398 | | } |
| 399 | | |
| 400 | | |
| 401 | | void MainWindow::createImagesMenu() |
| 402 | | { |
| 403 | | QMenu* imagesMenu = menuBar()->addMenu("&Images"); |
| 404 | | |
| 405 | | int interfaceIndex = 0; |
| 406 | | image_interface_iterator iter(m_machine->root_device()); |
| 407 | | for (device_image_interface *img = iter.first(); img != NULL; img = iter.next()) |
| 408 | | { |
| 409 | | astring menuName; |
| 410 | | menuName.format("%s : %s", img->device().name(), img->exists() ? img->filename() : "[empty slot]"); |
| 411 | | |
| 412 | | QMenu* interfaceMenu = imagesMenu->addMenu(menuName.cstr()); |
| 413 | | interfaceMenu->setObjectName(img->device().name()); |
| 414 | | |
| 415 | | QAction* mountAct = new QAction("Mount...", interfaceMenu); |
| 416 | | QAction* unmountAct = new QAction("Unmount", interfaceMenu); |
| 417 | | mountAct->setObjectName("mount"); |
| 418 | | mountAct->setData(QVariant(interfaceIndex)); |
| 419 | | unmountAct->setObjectName("unmount"); |
| 420 | | unmountAct->setData(QVariant(interfaceIndex)); |
| 421 | | connect(mountAct, SIGNAL(triggered(bool)), this, SLOT(mountImage(bool))); |
| 422 | | connect(unmountAct, SIGNAL(triggered(bool)), this, SLOT(unmountImage(bool))); |
| 423 | | |
| 424 | | if (!img->exists()) |
| 425 | | unmountAct->setEnabled(false); |
| 426 | | |
| 427 | | interfaceMenu->addAction(mountAct); |
| 428 | | interfaceMenu->addAction(unmountAct); |
| 429 | | |
| 430 | | // TODO: Cassette operations |
| 431 | | |
| 432 | | interfaceIndex++; |
| 433 | | } |
| 434 | | } |
| 435 | | |
| 436 | | |
| 437 | | //========================================================================= |
| 438 | | // MainWindowQtConfig |
| 439 | | //========================================================================= |
| 440 | | void MainWindowQtConfig::buildFromQWidget(QWidget* widget) |
| 441 | | { |
| 442 | | WindowQtConfig::buildFromQWidget(widget); |
| 443 | | MainWindow* window = dynamic_cast<MainWindow*>(widget); |
| 444 | | m_windowState = window->saveState(); |
| 445 | | |
| 446 | | QActionGroup* rightBarGroup = window->findChild<QActionGroup*>("rightbargroup"); |
| 447 | | if (rightBarGroup->checkedAction()->text() == "Raw Opcodes") |
| 448 | | m_rightBar = 0; |
| 449 | | else if (rightBarGroup->checkedAction()->text() == "Encrypted Opcodes") |
| 450 | | m_rightBar = 1; |
| 451 | | else if (rightBarGroup->checkedAction()->text() == "Comments") |
| 452 | | m_rightBar = 2; |
| 453 | | } |
| 454 | | |
| 455 | | |
| 456 | | void MainWindowQtConfig::applyToQWidget(QWidget* widget) |
| 457 | | { |
| 458 | | WindowQtConfig::applyToQWidget(widget); |
| 459 | | MainWindow* window = dynamic_cast<MainWindow*>(widget); |
| 460 | | window->restoreState(m_windowState); |
| 461 | | |
| 462 | | QActionGroup* rightBarGroup = window->findChild<QActionGroup*>("rightbargroup"); |
| 463 | | rightBarGroup->actions()[m_rightBar]->trigger(); |
| 464 | | } |
| 465 | | |
| 466 | | |
| 467 | | void MainWindowQtConfig::addToXmlDataNode(xml_data_node* node) const |
| 468 | | { |
| 469 | | WindowQtConfig::addToXmlDataNode(node); |
| 470 | | xml_set_attribute_int(node, "rightbar", m_rightBar); |
| 471 | | xml_set_attribute(node, "qtwindowstate", m_windowState.toPercentEncoding().data()); |
| 472 | | } |
| 473 | | |
| 474 | | |
| 475 | | void MainWindowQtConfig::recoverFromXmlNode(xml_data_node* node) |
| 476 | | { |
| 477 | | WindowQtConfig::recoverFromXmlNode(node); |
| 478 | | const char* state = xml_get_attribute_string(node, "qtwindowstate", ""); |
| 479 | | m_windowState = QByteArray::fromPercentEncoding(state); |
| 480 | | m_rightBar = xml_get_attribute_int(node, "rightbar", m_rightBar); |
| 481 | | } |
| 482 | | |
| 483 | | DasmDockWidget::~DasmDockWidget() |
| 484 | | { |
| 485 | | } |
| 486 | | |
| 487 | | ProcessorDockWidget::~ProcessorDockWidget() |
| 488 | | { |
| 489 | | } |
trunk/src/osd/modules/debugger/qt/mainwindow.h
| r243601 | r243602 | |
| 1 | | #ifndef __DEBUG_QT_MAIN_WINDOW_H__ |
| 2 | | #define __DEBUG_QT_MAIN_WINDOW_H__ |
| 3 | | |
| 4 | | #include <QtGui/QtGui> |
| 5 | | #include <vector> |
| 6 | | |
| 7 | | #include "debug/dvdisasm.h" |
| 8 | | |
| 9 | | #include "debuggerview.h" |
| 10 | | #include "windowqt.h" |
| 11 | | |
| 12 | | class DasmDockWidget; |
| 13 | | class ProcessorDockWidget; |
| 14 | | |
| 15 | | |
| 16 | | //============================================================ |
| 17 | | // The Main Window. Contains processor and dasm docks. |
| 18 | | //============================================================ |
| 19 | | class MainWindow : public WindowQt |
| 20 | | { |
| 21 | | Q_OBJECT |
| 22 | | |
| 23 | | public: |
| 24 | | MainWindow(running_machine* machine, QWidget* parent=NULL); |
| 25 | | virtual ~MainWindow(); |
| 26 | | |
| 27 | | void setProcessor(device_t* processor); |
| 28 | | |
| 29 | | |
| 30 | | protected: |
| 31 | | // Used to intercept the user clicking 'X' in the upper corner |
| 32 | | void closeEvent(QCloseEvent* event); |
| 33 | | |
| 34 | | // Used to intercept the user hitting the up arrow in the input widget |
| 35 | | bool eventFilter(QObject* obj, QEvent* event); |
| 36 | | |
| 37 | | |
| 38 | | private slots: |
| 39 | | void toggleBreakpointAtCursor(bool changedTo); |
| 40 | | void runToCursor(bool changedTo); |
| 41 | | void rightBarChanged(QAction* changedTo); |
| 42 | | |
| 43 | | void executeCommand(bool withClear=true); |
| 44 | | |
| 45 | | void mountImage(bool changedTo); |
| 46 | | void unmountImage(bool changedTo); |
| 47 | | |
| 48 | | // Closing the main window actually exits the program |
| 49 | | void debugActClose(); |
| 50 | | |
| 51 | | |
| 52 | | private: |
| 53 | | // Widgets and docks |
| 54 | | QLineEdit* m_inputEdit; |
| 55 | | DebuggerView* m_consoleView; |
| 56 | | ProcessorDockWidget* m_procFrame; |
| 57 | | DasmDockWidget* m_dasmFrame; |
| 58 | | |
| 59 | | // Terminal history |
| 60 | | int m_historyIndex; |
| 61 | | std::vector<QString> m_inputHistory; |
| 62 | | void addToHistory(const QString& command); |
| 63 | | |
| 64 | | void createImagesMenu(); |
| 65 | | }; |
| 66 | | |
| 67 | | |
| 68 | | //============================================================ |
| 69 | | // Docks with the Main Window. Disassembly. |
| 70 | | //============================================================ |
| 71 | | class DasmDockWidget : public QWidget |
| 72 | | { |
| 73 | | Q_OBJECT |
| 74 | | |
| 75 | | public: |
| 76 | | DasmDockWidget(running_machine* machine, QWidget* parent=NULL) : |
| 77 | | QWidget(parent), |
| 78 | | m_machine(machine) |
| 79 | | { |
| 80 | | m_dasmView = new DebuggerView(DVT_DISASSEMBLY, |
| 81 | | m_machine, |
| 82 | | this); |
| 83 | | |
| 84 | | // Force a recompute of the disassembly region |
| 85 | | downcast<debug_view_disasm*>(m_dasmView->view())->set_expression("curpc"); |
| 86 | | |
| 87 | | QVBoxLayout* dvLayout = new QVBoxLayout(this); |
| 88 | | dvLayout->addWidget(m_dasmView); |
| 89 | | dvLayout->setContentsMargins(4,0,4,0); |
| 90 | | } |
| 91 | | |
| 92 | | |
| 93 | | virtual ~DasmDockWidget(); |
| 94 | | |
| 95 | | |
| 96 | | DebuggerView* view() { return m_dasmView; } |
| 97 | | |
| 98 | | |
| 99 | | QSize minimumSizeHint() const |
| 100 | | { |
| 101 | | return QSize(150,150); |
| 102 | | } |
| 103 | | |
| 104 | | |
| 105 | | QSize sizeHint() const |
| 106 | | { |
| 107 | | return QSize(150,200); |
| 108 | | } |
| 109 | | |
| 110 | | |
| 111 | | private: |
| 112 | | DebuggerView* m_dasmView; |
| 113 | | |
| 114 | | running_machine* m_machine; |
| 115 | | }; |
| 116 | | |
| 117 | | |
| 118 | | //============================================================ |
| 119 | | // Docks with the Main Window. Processor information. |
| 120 | | //============================================================ |
| 121 | | class ProcessorDockWidget : public QWidget |
| 122 | | { |
| 123 | | Q_OBJECT |
| 124 | | |
| 125 | | public: |
| 126 | | ProcessorDockWidget(running_machine* machine, |
| 127 | | QWidget* parent=NULL) : |
| 128 | | QWidget(parent), |
| 129 | | m_processorView(NULL), |
| 130 | | m_machine(machine) |
| 131 | | { |
| 132 | | m_processorView = new DebuggerView(DVT_STATE, |
| 133 | | m_machine, |
| 134 | | this); |
| 135 | | m_processorView->setFocusPolicy(Qt::NoFocus); |
| 136 | | |
| 137 | | QVBoxLayout* cvLayout = new QVBoxLayout(this); |
| 138 | | cvLayout->addWidget(m_processorView); |
| 139 | | cvLayout->setContentsMargins(4,0,4,2); |
| 140 | | } |
| 141 | | |
| 142 | | |
| 143 | | virtual ~ProcessorDockWidget(); |
| 144 | | |
| 145 | | |
| 146 | | DebuggerView* view() { return m_processorView; } |
| 147 | | |
| 148 | | |
| 149 | | QSize minimumSizeHint() const |
| 150 | | { |
| 151 | | return QSize(150,300); |
| 152 | | } |
| 153 | | |
| 154 | | |
| 155 | | QSize sizeHint() const |
| 156 | | { |
| 157 | | return QSize(200,300); |
| 158 | | } |
| 159 | | |
| 160 | | |
| 161 | | private: |
| 162 | | DebuggerView* m_processorView; |
| 163 | | |
| 164 | | running_machine* m_machine; |
| 165 | | }; |
| 166 | | |
| 167 | | |
| 168 | | //========================================================================= |
| 169 | | // A way to store the configuration of a window long enough to read/write. |
| 170 | | //========================================================================= |
| 171 | | class MainWindowQtConfig : public WindowQtConfig |
| 172 | | { |
| 173 | | public: |
| 174 | | MainWindowQtConfig() : |
| 175 | | WindowQtConfig(WIN_TYPE_MAIN), |
| 176 | | m_rightBar(0), |
| 177 | | m_windowState() |
| 178 | | {} |
| 179 | | |
| 180 | | ~MainWindowQtConfig() {} |
| 181 | | |
| 182 | | // Settings |
| 183 | | int m_rightBar; |
| 184 | | QByteArray m_windowState; |
| 185 | | |
| 186 | | void buildFromQWidget(QWidget* widget); |
| 187 | | void applyToQWidget(QWidget* widget); |
| 188 | | void addToXmlDataNode(xml_data_node* node) const; |
| 189 | | void recoverFromXmlNode(xml_data_node* node); |
| 190 | | }; |
| 191 | | |
| 192 | | |
| 193 | | |
| 194 | | #endif |
trunk/src/osd/modules/debugger/qt/memorywindow.c
| r243601 | r243602 | |
| 1 | | #define NO_MEM_TRACKING |
| 2 | | |
| 3 | | #include "memorywindow.h" |
| 4 | | |
| 5 | | #include "debug/dvmemory.h" |
| 6 | | #include "debug/debugcon.h" |
| 7 | | #include "debug/debugcpu.h" |
| 8 | | |
| 9 | | |
| 10 | | MemoryWindow::MemoryWindow(running_machine* machine, QWidget* parent) : |
| 11 | | WindowQt(machine, NULL) |
| 12 | | { |
| 13 | | setWindowTitle("Debug: Memory View"); |
| 14 | | |
| 15 | | if (parent != NULL) |
| 16 | | { |
| 17 | | QPoint parentPos = parent->pos(); |
| 18 | | setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400); |
| 19 | | } |
| 20 | | |
| 21 | | // |
| 22 | | // The main frame and its input and log widgets |
| 23 | | // |
| 24 | | QFrame* mainWindowFrame = new QFrame(this); |
| 25 | | |
| 26 | | // The top frame & groupbox that contains the input widgets |
| 27 | | QFrame* topSubFrame = new QFrame(mainWindowFrame); |
| 28 | | |
| 29 | | // The input edit |
| 30 | | m_inputEdit = new QLineEdit(topSubFrame); |
| 31 | | connect(m_inputEdit, SIGNAL(returnPressed()), this, SLOT(expressionSubmitted())); |
| 32 | | |
| 33 | | // The memory space combo box |
| 34 | | m_memoryComboBox = new QComboBox(topSubFrame); |
| 35 | | m_memoryComboBox->setObjectName("memoryregion"); |
| 36 | | m_memoryComboBox->setMinimumWidth(300); |
| 37 | | connect(m_memoryComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(memoryRegionChanged(int))); |
| 38 | | |
| 39 | | // The main memory window |
| 40 | | m_memTable = new DebuggerMemView(DVT_MEMORY, m_machine, this); |
| 41 | | |
| 42 | | // Layout |
| 43 | | QHBoxLayout* subLayout = new QHBoxLayout(topSubFrame); |
| 44 | | subLayout->addWidget(m_inputEdit); |
| 45 | | subLayout->addWidget(m_memoryComboBox); |
| 46 | | subLayout->setSpacing(3); |
| 47 | | subLayout->setContentsMargins(2,2,2,2); |
| 48 | | |
| 49 | | QVBoxLayout* vLayout = new QVBoxLayout(mainWindowFrame); |
| 50 | | vLayout->setSpacing(3); |
| 51 | | vLayout->setContentsMargins(2,2,2,2); |
| 52 | | vLayout->addWidget(topSubFrame); |
| 53 | | vLayout->addWidget(m_memTable); |
| 54 | | |
| 55 | | setCentralWidget(mainWindowFrame); |
| 56 | | |
| 57 | | // |
| 58 | | // Menu bars |
| 59 | | // |
| 60 | | // Create a byte-chunk group |
| 61 | | QActionGroup* chunkGroup = new QActionGroup(this); |
| 62 | | chunkGroup->setObjectName("chunkgroup"); |
| 63 | | QAction* chunkActOne = new QAction("1-byte chunks", this); |
| 64 | | chunkActOne->setObjectName("chunkActOne"); |
| 65 | | QAction* chunkActTwo = new QAction("2-byte chunks", this); |
| 66 | | chunkActTwo->setObjectName("chunkActTwo"); |
| 67 | | QAction* chunkActFour = new QAction("4-byte chunks", this); |
| 68 | | chunkActFour->setObjectName("chunkActFour"); |
| 69 | | chunkActOne->setCheckable(true); |
| 70 | | chunkActTwo->setCheckable(true); |
| 71 | | chunkActFour->setCheckable(true); |
| 72 | | chunkActOne->setActionGroup(chunkGroup); |
| 73 | | chunkActTwo->setActionGroup(chunkGroup); |
| 74 | | chunkActFour->setActionGroup(chunkGroup); |
| 75 | | chunkActOne->setShortcut(QKeySequence("Ctrl+1")); |
| 76 | | chunkActTwo->setShortcut(QKeySequence("Ctrl+2")); |
| 77 | | chunkActFour->setShortcut(QKeySequence("Ctrl+4")); |
| 78 | | chunkActOne->setChecked(true); |
| 79 | | connect(chunkGroup, SIGNAL(triggered(QAction*)), this, SLOT(chunkChanged(QAction*))); |
| 80 | | |
| 81 | | // Create a address display group |
| 82 | | QActionGroup* addressGroup = new QActionGroup(this); |
| 83 | | addressGroup->setObjectName("addressgroup"); |
| 84 | | QAction* addressActLogical = new QAction("Logical Addresses", this); |
| 85 | | QAction* addressActPhysical = new QAction("Physical Addresses", this); |
| 86 | | addressActLogical->setCheckable(true); |
| 87 | | addressActPhysical->setCheckable(true); |
| 88 | | addressActLogical->setActionGroup(addressGroup); |
| 89 | | addressActPhysical->setActionGroup(addressGroup); |
| 90 | | addressActLogical->setShortcut(QKeySequence("Ctrl+G")); |
| 91 | | addressActPhysical->setShortcut(QKeySequence("Ctrl+Y")); |
| 92 | | addressActLogical->setChecked(true); |
| 93 | | connect(addressGroup, SIGNAL(triggered(QAction*)), this, SLOT(addressChanged(QAction*))); |
| 94 | | |
| 95 | | // Create a reverse view radio |
| 96 | | QAction* reverseAct = new QAction("Reverse View", this); |
| 97 | | reverseAct->setObjectName("reverse"); |
| 98 | | reverseAct->setCheckable(true); |
| 99 | | reverseAct->setShortcut(QKeySequence("Ctrl+R")); |
| 100 | | connect(reverseAct, SIGNAL(toggled(bool)), this, SLOT(reverseChanged(bool))); |
| 101 | | |
| 102 | | // Create increase and decrease bytes-per-line actions |
| 103 | | QAction* increaseBplAct = new QAction("Increase Bytes Per Line", this); |
| 104 | | QAction* decreaseBplAct = new QAction("Decrease Bytes Per Line", this); |
| 105 | | increaseBplAct->setShortcut(QKeySequence("Ctrl+P")); |
| 106 | | decreaseBplAct->setShortcut(QKeySequence("Ctrl+O")); |
| 107 | | connect(increaseBplAct, SIGNAL(triggered(bool)), this, SLOT(increaseBytesPerLine(bool))); |
| 108 | | connect(decreaseBplAct, SIGNAL(triggered(bool)), this, SLOT(decreaseBytesPerLine(bool))); |
| 109 | | |
| 110 | | // Assemble the options menu |
| 111 | | QMenu* optionsMenu = menuBar()->addMenu("&Options"); |
| 112 | | optionsMenu->addActions(chunkGroup->actions()); |
| 113 | | optionsMenu->addSeparator(); |
| 114 | | optionsMenu->addActions(addressGroup->actions()); |
| 115 | | optionsMenu->addSeparator(); |
| 116 | | optionsMenu->addAction(reverseAct); |
| 117 | | optionsMenu->addSeparator(); |
| 118 | | optionsMenu->addAction(increaseBplAct); |
| 119 | | optionsMenu->addAction(decreaseBplAct); |
| 120 | | |
| 121 | | |
| 122 | | // |
| 123 | | // Initialize |
| 124 | | // |
| 125 | | populateComboBox(); |
| 126 | | |
| 127 | | // Set to the current CPU's memory view |
| 128 | | setToCurrentCpu(); |
| 129 | | } |
| 130 | | |
| 131 | | |
| 132 | | MemoryWindow::~MemoryWindow() |
| 133 | | { |
| 134 | | } |
| 135 | | |
| 136 | | |
| 137 | | void MemoryWindow::memoryRegionChanged(int index) |
| 138 | | { |
| 139 | | m_memTable->view()->set_source(*m_memTable->view()->source_list().find(index)); |
| 140 | | m_memTable->viewport()->update(); |
| 141 | | |
| 142 | | // Update the chunk size radio buttons to the memory region's default |
| 143 | | debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view()); |
| 144 | | switch(memView->bytes_per_chunk()) |
| 145 | | { |
| 146 | | case 1: chunkSizeMenuItem("chunkActOne")->setChecked(true); break; |
| 147 | | case 2: chunkSizeMenuItem("chunkActTwo")->setChecked(true); break; |
| 148 | | case 4: chunkSizeMenuItem("chunkActFour")->setChecked(true); break; |
| 149 | | default: break; |
| 150 | | } |
| 151 | | } |
| 152 | | |
| 153 | | |
| 154 | | void MemoryWindow::expressionSubmitted() |
| 155 | | { |
| 156 | | const QString expression = m_inputEdit->text(); |
| 157 | | downcast<debug_view_memory*>(m_memTable->view())->set_expression(expression.toLocal8Bit().data()); |
| 158 | | |
| 159 | | // Make the cursor pop |
| 160 | | m_memTable->view()->set_cursor_visible(true); |
| 161 | | |
| 162 | | // Check where the cursor is and adjust the scroll accordingly |
| 163 | | debug_view_xy cursorPosition = m_memTable->view()->cursor_position(); |
| 164 | | // TODO: check if the region is already visible? |
| 165 | | m_memTable->verticalScrollBar()->setValue(cursorPosition.y); |
| 166 | | |
| 167 | | m_memTable->update(); |
| 168 | | m_memTable->viewport()->update(); |
| 169 | | } |
| 170 | | |
| 171 | | |
| 172 | | void MemoryWindow::chunkChanged(QAction* changedTo) |
| 173 | | { |
| 174 | | debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view()); |
| 175 | | if (changedTo->text() == "1-byte chunks") |
| 176 | | { |
| 177 | | memView->set_bytes_per_chunk(1); |
| 178 | | } |
| 179 | | else if (changedTo->text() == "2-byte chunks") |
| 180 | | { |
| 181 | | memView->set_bytes_per_chunk(2); |
| 182 | | } |
| 183 | | else if (changedTo->text() == "4-byte chunks") |
| 184 | | { |
| 185 | | memView->set_bytes_per_chunk(4); |
| 186 | | } |
| 187 | | m_memTable->viewport()->update(); |
| 188 | | } |
| 189 | | |
| 190 | | |
| 191 | | void MemoryWindow::addressChanged(QAction* changedTo) |
| 192 | | { |
| 193 | | debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view()); |
| 194 | | if (changedTo->text() == "Logical Addresses") |
| 195 | | { |
| 196 | | memView->set_physical(false); |
| 197 | | } |
| 198 | | else if (changedTo->text() == "Physical Addresses") |
| 199 | | { |
| 200 | | memView->set_physical(true); |
| 201 | | } |
| 202 | | m_memTable->viewport()->update(); |
| 203 | | } |
| 204 | | |
| 205 | | |
| 206 | | void MemoryWindow::reverseChanged(bool changedTo) |
| 207 | | { |
| 208 | | debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view()); |
| 209 | | memView->set_reverse(changedTo); |
| 210 | | m_memTable->viewport()->update(); |
| 211 | | } |
| 212 | | |
| 213 | | |
| 214 | | void MemoryWindow::increaseBytesPerLine(bool changedTo) |
| 215 | | { |
| 216 | | debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view()); |
| 217 | | memView->set_chunks_per_row(memView->chunks_per_row() + 1); |
| 218 | | m_memTable->viewport()->update(); |
| 219 | | } |
| 220 | | |
| 221 | | |
| 222 | | void MemoryWindow::decreaseBytesPerLine(bool checked) |
| 223 | | { |
| 224 | | debug_view_memory* memView = downcast<debug_view_memory*>(m_memTable->view()); |
| 225 | | memView->set_chunks_per_row(memView->chunks_per_row() - 1); |
| 226 | | m_memTable->viewport()->update(); |
| 227 | | } |
| 228 | | |
| 229 | | |
| 230 | | void MemoryWindow::populateComboBox() |
| 231 | | { |
| 232 | | if (m_memTable == NULL) |
| 233 | | return; |
| 234 | | |
| 235 | | m_memoryComboBox->clear(); |
| 236 | | for (const debug_view_source* source = m_memTable->view()->first_source(); |
| 237 | | source != NULL; |
| 238 | | source = source->next()) |
| 239 | | { |
| 240 | | m_memoryComboBox->addItem(source->name()); |
| 241 | | } |
| 242 | | } |
| 243 | | |
| 244 | | |
| 245 | | void MemoryWindow::setToCurrentCpu() |
| 246 | | { |
| 247 | | device_t* curCpu = debug_cpu_get_visible_cpu(*m_machine); |
| 248 | | const debug_view_source *source = m_memTable->view()->source_for_device(curCpu); |
| 249 | | const int listIndex = m_memTable->view()->source_list().indexof(*source); |
| 250 | | m_memoryComboBox->setCurrentIndex(listIndex); |
| 251 | | } |
| 252 | | |
| 253 | | |
| 254 | | // I have a hard time storing QActions as class members. This is a substitute. |
| 255 | | QAction* MemoryWindow::chunkSizeMenuItem(const QString& itemName) |
| 256 | | { |
| 257 | | QList<QMenu*> menus = menuBar()->findChildren<QMenu*>(); |
| 258 | | for (int i = 0; i < menus.length(); i++) |
| 259 | | { |
| 260 | | if (menus[i]->title() != "&Options") continue; |
| 261 | | QList<QAction*> actions = menus[i]->actions(); |
| 262 | | for (int j = 0; j < actions.length(); j++) |
| 263 | | { |
| 264 | | if (actions[j]->objectName() == itemName) |
| 265 | | return actions[j]; |
| 266 | | } |
| 267 | | } |
| 268 | | return NULL; |
| 269 | | } |
| 270 | | |
| 271 | | |
| 272 | | //========================================================================= |
| 273 | | // DebuggerMemView |
| 274 | | //========================================================================= |
| 275 | | void DebuggerMemView::mousePressEvent(QMouseEvent* event) |
| 276 | | { |
| 277 | | const bool leftClick = event->button() == Qt::LeftButton; |
| 278 | | const bool rightClick = event->button() == Qt::RightButton; |
| 279 | | |
| 280 | | if (leftClick || rightClick) |
| 281 | | { |
| 282 | | QFontMetrics actualFont = fontMetrics(); |
| 283 | | const double fontWidth = actualFont.width(QString(100, '_')) / 100.; |
| 284 | | const int fontHeight = MAX(1, actualFont.height()); |
| 285 | | |
| 286 | | debug_view_xy topLeft = view()->visible_position(); |
| 287 | | debug_view_xy clickViewPosition; |
| 288 | | clickViewPosition.x = topLeft.x + (event->x() / fontWidth); |
| 289 | | clickViewPosition.y = topLeft.y + (event->y() / fontHeight); |
| 290 | | if (leftClick) |
| 291 | | { |
| 292 | | view()->process_click(DCK_LEFT_CLICK, clickViewPosition); |
| 293 | | } |
| 294 | | else if (rightClick) |
| 295 | | { |
| 296 | | // Display the last known PC to write to this memory location & copy it onto the clipboard |
| 297 | | debug_view_memory* memView = downcast<debug_view_memory*>(view()); |
| 298 | | const offs_t address = memView->addressAtCursorPosition(clickViewPosition); |
| 299 | | const debug_view_memory_source* source = downcast<const debug_view_memory_source*>(memView->source()); |
| 300 | | address_space* addressSpace = source->space(); |
| 301 | | const int nativeDataWidth = addressSpace->data_width() / 8; |
| 302 | | const UINT64 memValue = debug_read_memory(*addressSpace, |
| 303 | | addressSpace->address_to_byte(address), |
| 304 | | nativeDataWidth, |
| 305 | | true); |
| 306 | | const offs_t pc = source->device()->debug()->track_mem_pc_from_space_address_data(addressSpace->spacenum(), |
| 307 | | address, |
| 308 | | memValue); |
| 309 | | if (pc != (offs_t)(-1)) |
| 310 | | { |
| 311 | | // TODO: You can specify a box that the tooltip stays alive within - might be good? |
| 312 | | const QString addressAndPc = QString("Address %1 written at PC=%2").arg(address, 2, 16).arg(pc, 2, 16); |
| 313 | | QToolTip::showText(QCursor::pos(), addressAndPc, NULL); |
| 314 | | |
| 315 | | // Copy the PC into the clipboard as well |
| 316 | | QClipboard *clipboard = QApplication::clipboard(); |
| 317 | | clipboard->setText(QString("%1").arg(pc, 2, 16)); |
| 318 | | } |
| 319 | | else |
| 320 | | { |
| 321 | | QToolTip::showText(QCursor::pos(), "UNKNOWN PC", NULL); |
| 322 | | } |
| 323 | | } |
| 324 | | |
| 325 | | viewport()->update(); |
| 326 | | update(); |
| 327 | | } |
| 328 | | } |
| 329 | | |
| 330 | | |
| 331 | | //========================================================================= |
| 332 | | // MemoryWindowQtConfig |
| 333 | | //========================================================================= |
| 334 | | void MemoryWindowQtConfig::buildFromQWidget(QWidget* widget) |
| 335 | | { |
| 336 | | WindowQtConfig::buildFromQWidget(widget); |
| 337 | | MemoryWindow* window = dynamic_cast<MemoryWindow*>(widget); |
| 338 | | QComboBox* memoryRegion = window->findChild<QComboBox*>("memoryregion"); |
| 339 | | m_memoryRegion = memoryRegion->currentIndex(); |
| 340 | | |
| 341 | | QAction* reverse = window->findChild<QAction*>("reverse"); |
| 342 | | m_reverse = reverse->isChecked(); |
| 343 | | |
| 344 | | QActionGroup* addressGroup = window->findChild<QActionGroup*>("addressgroup"); |
| 345 | | if (addressGroup->checkedAction()->text() == "Logical Addresses") |
| 346 | | m_addressMode = 0; |
| 347 | | else if (addressGroup->checkedAction()->text() == "Physical Addresses") |
| 348 | | m_addressMode = 1; |
| 349 | | |
| 350 | | QActionGroup* chunkGroup = window->findChild<QActionGroup*>("chunkgroup"); |
| 351 | | if (chunkGroup->checkedAction()->text() == "1-byte chunks") |
| 352 | | m_chunkSize = 0; |
| 353 | | else if (chunkGroup->checkedAction()->text() == "2-byte chunks") |
| 354 | | m_chunkSize = 1; |
| 355 | | else if (chunkGroup->checkedAction()->text() == "4-byte chunks") |
| 356 | | m_chunkSize = 2; |
| 357 | | } |
| 358 | | |
| 359 | | |
| 360 | | void MemoryWindowQtConfig::applyToQWidget(QWidget* widget) |
| 361 | | { |
| 362 | | WindowQtConfig::applyToQWidget(widget); |
| 363 | | MemoryWindow* window = dynamic_cast<MemoryWindow*>(widget); |
| 364 | | QComboBox* memoryRegion = window->findChild<QComboBox*>("memoryregion"); |
| 365 | | memoryRegion->setCurrentIndex(m_memoryRegion); |
| 366 | | |
| 367 | | QAction* reverse = window->findChild<QAction*>("reverse"); |
| 368 | | if (m_reverse) reverse->trigger(); |
| 369 | | |
| 370 | | QActionGroup* addressGroup = window->findChild<QActionGroup*>("addressgroup"); |
| 371 | | addressGroup->actions()[m_addressMode]->trigger(); |
| 372 | | |
| 373 | | QActionGroup* chunkGroup = window->findChild<QActionGroup*>("chunkgroup"); |
| 374 | | chunkGroup->actions()[m_chunkSize]->trigger(); |
| 375 | | } |
| 376 | | |
| 377 | | |
| 378 | | void MemoryWindowQtConfig::addToXmlDataNode(xml_data_node* node) const |
| 379 | | { |
| 380 | | WindowQtConfig::addToXmlDataNode(node); |
| 381 | | xml_set_attribute_int(node, "memoryregion", m_memoryRegion); |
| 382 | | xml_set_attribute_int(node, "reverse", m_reverse); |
| 383 | | xml_set_attribute_int(node, "addressmode", m_addressMode); |
| 384 | | xml_set_attribute_int(node, "chunksize", m_chunkSize); |
| 385 | | } |
| 386 | | |
| 387 | | |
| 388 | | void MemoryWindowQtConfig::recoverFromXmlNode(xml_data_node* node) |
| 389 | | { |
| 390 | | WindowQtConfig::recoverFromXmlNode(node); |
| 391 | | m_memoryRegion = xml_get_attribute_int(node, "memoryregion", m_memoryRegion); |
| 392 | | m_reverse = xml_get_attribute_int(node, "reverse", m_reverse); |
| 393 | | m_addressMode = xml_get_attribute_int(node, "addressmode", m_addressMode); |
| 394 | | m_chunkSize = xml_get_attribute_int(node, "chunksize", m_chunkSize); |
| 395 | | } |
trunk/src/osd/modules/debugger/qt/windowqt.c
| r243601 | r243602 | |
| 1 | | #define NO_MEM_TRACKING |
| 2 | | |
| 3 | | #include "windowqt.h" |
| 4 | | #include "logwindow.h" |
| 5 | | #include "dasmwindow.h" |
| 6 | | #include "memorywindow.h" |
| 7 | | #include "breakpointswindow.h" |
| 8 | | #include "deviceswindow.h" |
| 9 | | |
| 10 | | bool WindowQt::s_refreshAll = false; |
| 11 | | bool WindowQt::s_hideAll = false; |
| 12 | | |
| 13 | | |
| 14 | | // Since all debug windows are intended to be top-level, this inherited |
| 15 | | // constructor is always called with a NULL parent. The passed-in parent widget, |
| 16 | | // however, is often used to place each child window & the code to do this can |
| 17 | | // be found in most of the inherited classes. |
| 18 | | |
| 19 | | WindowQt::WindowQt(running_machine* machine, QWidget* parent) : |
| 20 | | QMainWindow(parent), |
| 21 | | m_machine(machine) |
| 22 | | { |
| 23 | | setAttribute(Qt::WA_DeleteOnClose, true); |
| 24 | | |
| 25 | | // The Debug menu bar |
| 26 | | QAction* debugActOpenMemory = new QAction("New &Memory Window", this); |
| 27 | | debugActOpenMemory->setShortcut(QKeySequence("Ctrl+M")); |
| 28 | | connect(debugActOpenMemory, SIGNAL(triggered()), this, SLOT(debugActOpenMemory())); |
| 29 | | |
| 30 | | QAction* debugActOpenDasm = new QAction("New &Dasm Window", this); |
| 31 | | debugActOpenDasm->setShortcut(QKeySequence("Ctrl+D")); |
| 32 | | connect(debugActOpenDasm, SIGNAL(triggered()), this, SLOT(debugActOpenDasm())); |
| 33 | | |
| 34 | | QAction* debugActOpenLog = new QAction("New &Log Window", this); |
| 35 | | debugActOpenLog->setShortcut(QKeySequence("Ctrl+L")); |
| 36 | | connect(debugActOpenLog, SIGNAL(triggered()), this, SLOT(debugActOpenLog())); |
| 37 | | |
| 38 | | QAction* debugActOpenPoints = new QAction("New &Break|Watchpoints Window", this); |
| 39 | | debugActOpenPoints->setShortcut(QKeySequence("Ctrl+B")); |
| 40 | | connect(debugActOpenPoints, SIGNAL(triggered()), this, SLOT(debugActOpenPoints())); |
| 41 | | |
| 42 | | QAction* debugActOpenDevices = new QAction("New D&evices Window", this); |
| 43 | | debugActOpenDevices->setShortcut(QKeySequence("Shift+Ctrl+D")); |
| 44 | | connect(debugActOpenDevices, SIGNAL(triggered()), this, SLOT(debugActOpenDevices())); |
| 45 | | |
| 46 | | QAction* dbgActRun = new QAction("Run", this); |
| 47 | | dbgActRun->setShortcut(Qt::Key_F5); |
| 48 | | connect(dbgActRun, SIGNAL(triggered()), this, SLOT(debugActRun())); |
| 49 | | |
| 50 | | QAction* dbgActRunAndHide = new QAction("Run And Hide Debugger", this); |
| 51 | | dbgActRunAndHide->setShortcut(Qt::Key_F12); |
| 52 | | connect(dbgActRunAndHide, SIGNAL(triggered()), this, SLOT(debugActRunAndHide())); |
| 53 | | |
| 54 | | QAction* dbgActRunToNextCpu = new QAction("Run to Next CPU", this); |
| 55 | | dbgActRunToNextCpu->setShortcut(Qt::Key_F6); |
| 56 | | connect(dbgActRunToNextCpu, SIGNAL(triggered()), this, SLOT(debugActRunToNextCpu())); |
| 57 | | |
| 58 | | QAction* dbgActRunNextInt = new QAction("Run to Next Interrupt on This CPU", this); |
| 59 | | dbgActRunNextInt->setShortcut(Qt::Key_F7); |
| 60 | | connect(dbgActRunNextInt, SIGNAL(triggered()), this, SLOT(debugActRunNextInt())); |
| 61 | | |
| 62 | | QAction* dbgActRunNextVBlank = new QAction("Run to Next VBlank", this); |
| 63 | | dbgActRunNextVBlank->setShortcut(Qt::Key_F8); |
| 64 | | connect(dbgActRunNextVBlank, SIGNAL(triggered()), this, SLOT(debugActRunNextVBlank())); |
| 65 | | |
| 66 | | QAction* dbgActStepInto = new QAction("Step Into", this); |
| 67 | | dbgActStepInto->setShortcut(Qt::Key_F11); |
| 68 | | connect(dbgActStepInto, SIGNAL(triggered()), this, SLOT(debugActStepInto())); |
| 69 | | |
| 70 | | QAction* dbgActStepOver = new QAction("Step Over", this); |
| 71 | | dbgActStepOver->setShortcut(Qt::Key_F10); |
| 72 | | connect(dbgActStepOver, SIGNAL(triggered()), this, SLOT(debugActStepOver())); |
| 73 | | |
| 74 | | QAction* dbgActStepOut = new QAction("Step Out", this); |
| 75 | | dbgActStepOut->setShortcut(QKeySequence("Shift+F11")); |
| 76 | | connect(dbgActStepOut, SIGNAL(triggered()), this, SLOT(debugActStepOut())); |
| 77 | | |
| 78 | | QAction* dbgActSoftReset = new QAction("Soft Reset", this); |
| 79 | | dbgActSoftReset->setShortcut(Qt::Key_F3); |
| 80 | | connect(dbgActSoftReset, SIGNAL(triggered()), this, SLOT(debugActSoftReset())); |
| 81 | | |
| 82 | | QAction* dbgActHardReset = new QAction("Hard Reset", this); |
| 83 | | dbgActHardReset->setShortcut(QKeySequence("Shift+F3")); |
| 84 | | connect(dbgActHardReset, SIGNAL(triggered()), this, SLOT(debugActHardReset())); |
| 85 | | |
| 86 | | QAction* dbgActClose = new QAction("Close &Window", this); |
| 87 | | dbgActClose->setShortcut(QKeySequence::Close); |
| 88 | | connect(dbgActClose, SIGNAL(triggered()), this, SLOT(debugActClose())); |
| 89 | | |
| 90 | | QAction* dbgActQuit = new QAction("&Quit", this); |
| 91 | | dbgActQuit->setShortcut(QKeySequence::Quit); |
| 92 | | connect(dbgActQuit, SIGNAL(triggered()), this, SLOT(debugActQuit())); |
| 93 | | |
| 94 | | // Construct the menu |
| 95 | | QMenu* debugMenu = menuBar()->addMenu("&Debug"); |
| 96 | | debugMenu->addAction(debugActOpenMemory); |
| 97 | | debugMenu->addAction(debugActOpenDasm); |
| 98 | | debugMenu->addAction(debugActOpenLog); |
| 99 | | debugMenu->addAction(debugActOpenPoints); |
| 100 | | debugMenu->addAction(debugActOpenDevices); |
| 101 | | debugMenu->addSeparator(); |
| 102 | | debugMenu->addAction(dbgActRun); |
| 103 | | debugMenu->addAction(dbgActRunAndHide); |
| 104 | | debugMenu->addAction(dbgActRunToNextCpu); |
| 105 | | debugMenu->addAction(dbgActRunNextInt); |
| 106 | | debugMenu->addAction(dbgActRunNextVBlank); |
| 107 | | debugMenu->addSeparator(); |
| 108 | | debugMenu->addAction(dbgActStepInto); |
| 109 | | debugMenu->addAction(dbgActStepOver); |
| 110 | | debugMenu->addAction(dbgActStepOut); |
| 111 | | debugMenu->addSeparator(); |
| 112 | | debugMenu->addAction(dbgActSoftReset); |
| 113 | | debugMenu->addAction(dbgActHardReset); |
| 114 | | debugMenu->addSeparator(); |
| 115 | | debugMenu->addAction(dbgActClose); |
| 116 | | debugMenu->addAction(dbgActQuit); |
| 117 | | } |
| 118 | | |
| 119 | | |
| 120 | | WindowQt::~WindowQt() |
| 121 | | { |
| 122 | | } |
| 123 | | |
| 124 | | void WindowQt::debugActOpenMemory() |
| 125 | | { |
| 126 | | MemoryWindow* foo = new MemoryWindow(m_machine, this); |
| 127 | | // A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon |
| 128 | | // foo->setWindowFlags(Qt::Dialog); |
| 129 | | // foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint); |
| 130 | | foo->show(); |
| 131 | | } |
| 132 | | |
| 133 | | |
| 134 | | void WindowQt::debugActOpenDasm() |
| 135 | | { |
| 136 | | DasmWindow* foo = new DasmWindow(m_machine, this); |
| 137 | | // A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon |
| 138 | | // foo->setWindowFlags(Qt::Dialog); |
| 139 | | // foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint); |
| 140 | | foo->show(); |
| 141 | | } |
| 142 | | |
| 143 | | |
| 144 | | void WindowQt::debugActOpenLog() |
| 145 | | { |
| 146 | | LogWindow* foo = new LogWindow(m_machine, this); |
| 147 | | // A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon |
| 148 | | // foo->setWindowFlags(Qt::Dialog); |
| 149 | | // foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint); |
| 150 | | foo->show(); |
| 151 | | } |
| 152 | | |
| 153 | | |
| 154 | | void WindowQt::debugActOpenPoints() |
| 155 | | { |
| 156 | | BreakpointsWindow* foo = new BreakpointsWindow(m_machine, this); |
| 157 | | // A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon |
| 158 | | // foo->setWindowFlags(Qt::Dialog); |
| 159 | | // foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint); |
| 160 | | foo->show(); |
| 161 | | } |
| 162 | | |
| 163 | | |
| 164 | | void WindowQt::debugActOpenDevices() |
| 165 | | { |
| 166 | | DevicesWindow* foo = new DevicesWindow(m_machine, this); |
| 167 | | // A valiant effort, but it just doesn't wanna' hide behind the main window & not make a new toolbar icon |
| 168 | | // foo->setWindowFlags(Qt::Dialog); |
| 169 | | // foo->setWindowFlags(foo->windowFlags() & ~Qt::WindowStaysOnTopHint); |
| 170 | | foo->show(); |
| 171 | | } |
| 172 | | |
| 173 | | |
| 174 | | void WindowQt::debugActRun() |
| 175 | | { |
| 176 | | debug_cpu_get_visible_cpu(*m_machine)->debug()->go(); |
| 177 | | } |
| 178 | | |
| 179 | | void WindowQt::debugActRunAndHide() |
| 180 | | { |
| 181 | | debug_cpu_get_visible_cpu(*m_machine)->debug()->go(); |
| 182 | | hideAll(); |
| 183 | | } |
| 184 | | |
| 185 | | void WindowQt::debugActRunToNextCpu() |
| 186 | | { |
| 187 | | debug_cpu_get_visible_cpu(*m_machine)->debug()->go_next_device(); |
| 188 | | } |
| 189 | | |
| 190 | | void WindowQt::debugActRunNextInt() |
| 191 | | { |
| 192 | | debug_cpu_get_visible_cpu(*m_machine)->debug()->go_interrupt(); |
| 193 | | } |
| 194 | | |
| 195 | | void WindowQt::debugActRunNextVBlank() |
| 196 | | { |
| 197 | | debug_cpu_get_visible_cpu(*m_machine)->debug()->go_vblank(); |
| 198 | | } |
| 199 | | |
| 200 | | void WindowQt::debugActStepInto() |
| 201 | | { |
| 202 | | debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step(); |
| 203 | | } |
| 204 | | |
| 205 | | void WindowQt::debugActStepOver() |
| 206 | | { |
| 207 | | debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step_over(); |
| 208 | | } |
| 209 | | |
| 210 | | void WindowQt::debugActStepOut() |
| 211 | | { |
| 212 | | debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step_out(); |
| 213 | | } |
| 214 | | |
| 215 | | void WindowQt::debugActSoftReset() |
| 216 | | { |
| 217 | | m_machine->schedule_soft_reset(); |
| 218 | | debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step(); |
| 219 | | } |
| 220 | | |
| 221 | | void WindowQt::debugActHardReset() |
| 222 | | { |
| 223 | | m_machine->schedule_hard_reset(); |
| 224 | | } |
| 225 | | |
| 226 | | void WindowQt::debugActClose() |
| 227 | | { |
| 228 | | close(); |
| 229 | | } |
| 230 | | |
| 231 | | void WindowQt::debugActQuit() |
| 232 | | { |
| 233 | | m_machine->schedule_exit(); |
| 234 | | } |
| 235 | | |
| 236 | | |
| 237 | | //========================================================================= |
| 238 | | // WindowQtConfig |
| 239 | | //========================================================================= |
| 240 | | void WindowQtConfig::buildFromQWidget(QWidget* widget) |
| 241 | | { |
| 242 | | m_position.setX(widget->geometry().topLeft().x()); |
| 243 | | m_position.setY(widget->geometry().topLeft().y()); |
| 244 | | m_size.setX(widget->size().width()); |
| 245 | | m_size.setY(widget->size().height()); |
| 246 | | } |
| 247 | | |
| 248 | | |
| 249 | | void WindowQtConfig::applyToQWidget(QWidget* widget) |
| 250 | | { |
| 251 | | widget->setGeometry(m_position.x(), m_position.y(), m_size.x(), m_size.y()); |
| 252 | | } |
| 253 | | |
| 254 | | |
| 255 | | void WindowQtConfig::addToXmlDataNode(xml_data_node* node) const |
| 256 | | { |
| 257 | | xml_set_attribute_int(node, "type", m_type); |
| 258 | | xml_set_attribute_int(node, "position_x", m_position.x()); |
| 259 | | xml_set_attribute_int(node, "position_y", m_position.y()); |
| 260 | | xml_set_attribute_int(node, "size_x", m_size.x()); |
| 261 | | xml_set_attribute_int(node, "size_y", m_size.y()); |
| 262 | | } |
| 263 | | |
| 264 | | |
| 265 | | void WindowQtConfig::recoverFromXmlNode(xml_data_node* node) |
| 266 | | { |
| 267 | | m_size.setX(xml_get_attribute_int(node, "size_x", m_size.x())); |
| 268 | | m_size.setY(xml_get_attribute_int(node, "size_y", m_size.y())); |
| 269 | | m_position.setX(xml_get_attribute_int(node, "position_x", m_position.x())); |
| 270 | | m_position.setY(xml_get_attribute_int(node, "position_y", m_position.y())); |
| 271 | | m_type = (WindowQtConfig::WindowType)xml_get_attribute_int(node, "type", m_type); |
| 272 | | } |
trunk/src/osd/sdl/sdl.mak
| r243601 | r243602 | |
| 289 | 289 | |
| 290 | 290 | DEBUGOBJS = \ |
| 291 | 291 | $(OSDOBJ)/modules/debugger/debugosx.o \ |
| 292 | | $(OSDOBJ)/modules/debugger/osx/breakpointsview.o \ |
| 293 | | $(OSDOBJ)/modules/debugger/osx/consoleview.o \ |
| 294 | | $(OSDOBJ)/modules/debugger/osx/debugcommandhistory.o \ |
| 295 | | $(OSDOBJ)/modules/debugger/osx/debugconsole.o \ |
| 296 | | $(OSDOBJ)/modules/debugger/osx/debugview.o \ |
| 297 | | $(OSDOBJ)/modules/debugger/osx/debugwindowhandler.o \ |
| 298 | | $(OSDOBJ)/modules/debugger/osx/devicesviewer.o \ |
| 299 | | $(OSDOBJ)/modules/debugger/osx/disassemblyview.o \ |
| 300 | | $(OSDOBJ)/modules/debugger/osx/disassemblyviewer.o \ |
| 301 | | $(OSDOBJ)/modules/debugger/osx/errorlogview.o \ |
| 302 | | $(OSDOBJ)/modules/debugger/osx/errorlogviewer.o \ |
| 303 | | $(OSDOBJ)/modules/debugger/osx/memoryview.o \ |
| 304 | | $(OSDOBJ)/modules/debugger/osx/memoryviewer.o \ |
| 305 | | $(OSDOBJ)/modules/debugger/osx/pointsviewer.o \ |
| 306 | | $(OSDOBJ)/modules/debugger/osx/registersview.o \ |
| 307 | | $(OSDOBJ)/modules/debugger/osx/watchpointsview.o |
| 292 | $(OSDOBJ)/modules/debugger/osx/debugosxbreakpointsview.o \ |
| 293 | $(OSDOBJ)/modules/debugger/osx/debugosxconsoleview.o \ |
| 294 | $(OSDOBJ)/modules/debugger/osx/debugosxdebugcommandhistory.o \ |
| 295 | $(OSDOBJ)/modules/debugger/osx/debugosxdebugconsole.o \ |
| 296 | $(OSDOBJ)/modules/debugger/osx/debugosxdebugview.o \ |
| 297 | $(OSDOBJ)/modules/debugger/osx/debugosxdebugwindowhandler.o \ |
| 298 | $(OSDOBJ)/modules/debugger/osx/debugosxdisassemblyview.o \ |
| 299 | $(OSDOBJ)/modules/debugger/osx/debugosxdisassemblyviewer.o \ |
| 300 | $(OSDOBJ)/modules/debugger/osx/debugosxerrorlogview.o \ |
| 301 | $(OSDOBJ)/modules/debugger/osx/debugosxerrorlogviewer.o \ |
| 302 | $(OSDOBJ)/modules/debugger/osx/debugosxmemoryview.o \ |
| 303 | $(OSDOBJ)/modules/debugger/osx/debugosxmemoryviewer.o \ |
| 304 | $(OSDOBJ)/modules/debugger/osx/debugosxpointsviewer.o \ |
| 305 | $(OSDOBJ)/modules/debugger/osx/debugosxregistersview.o \ |
| 306 | $(OSDOBJ)/modules/debugger/osx/debugosxwatchpointsview.o |
| 308 | 307 | |
| 309 | 308 | endif |
| 310 | 309 | |
| r243601 | r243602 | |
| 730 | 729 | $(MOC) $(MOCINCPATH) $(DEFS) $< -o $@ |
| 731 | 730 | |
| 732 | 731 | DEBUGOBJS = \ |
| 733 | | $(OSDOBJ)/modules/debugger/qt/debuggerview.o \ |
| 734 | | $(OSDOBJ)/modules/debugger/qt/windowqt.o \ |
| 735 | | $(OSDOBJ)/modules/debugger/qt/logwindow.o \ |
| 736 | | $(OSDOBJ)/modules/debugger/qt/dasmwindow.o \ |
| 737 | | $(OSDOBJ)/modules/debugger/qt/mainwindow.o \ |
| 738 | | $(OSDOBJ)/modules/debugger/qt/memorywindow.o \ |
| 739 | | $(OSDOBJ)/modules/debugger/qt/breakpointswindow.o \ |
| 740 | | $(OSDOBJ)/modules/debugger/qt/deviceswindow.o \ |
| 741 | | $(OSDOBJ)/modules/debugger/qt/deviceinformationwindow.o \ |
| 742 | | $(OSDOBJ)/modules/debugger/qt/debuggerview.moc.o \ |
| 743 | | $(OSDOBJ)/modules/debugger/qt/windowqt.moc.o \ |
| 744 | | $(OSDOBJ)/modules/debugger/qt/logwindow.moc.o \ |
| 745 | | $(OSDOBJ)/modules/debugger/qt/dasmwindow.moc.o \ |
| 746 | | $(OSDOBJ)/modules/debugger/qt/mainwindow.moc.o \ |
| 747 | | $(OSDOBJ)/modules/debugger/qt/memorywindow.moc.o \ |
| 748 | | $(OSDOBJ)/modules/debugger/qt/breakpointswindow.moc.o \ |
| 749 | | $(OSDOBJ)/modules/debugger/qt/deviceswindow.moc.o \ |
| 750 | | $(OSDOBJ)/modules/debugger/qt/deviceinformationwindow.moc.o |
| 732 | $(OSDOBJ)/modules/debugger/qt/debugqtview.o \ |
| 733 | $(OSDOBJ)/modules/debugger/qt/debugqtwindow.o \ |
| 734 | $(OSDOBJ)/modules/debugger/qt/debugqtlogwindow.o \ |
| 735 | $(OSDOBJ)/modules/debugger/qt/debugqtdasmwindow.o \ |
| 736 | $(OSDOBJ)/modules/debugger/qt/debugqtmainwindow.o \ |
| 737 | $(OSDOBJ)/modules/debugger/qt/debugqtmemorywindow.o \ |
| 738 | $(OSDOBJ)/modules/debugger/qt/debugqtbreakpointswindow.o \ |
| 739 | $(OSDOBJ)/modules/debugger/qt/debugqtdeviceswindow.o \ |
| 740 | $(OSDOBJ)/modules/debugger/qt/debugqtdeviceinformationwindow.o \ |
| 741 | $(OSDOBJ)/modules/debugger/qt/debugqtview.moc.o \ |
| 742 | $(OSDOBJ)/modules/debugger/qt/debugqtwindow.moc.o \ |
| 743 | $(OSDOBJ)/modules/debugger/qt/debugqtlogwindow.moc.o \ |
| 744 | $(OSDOBJ)/modules/debugger/qt/debugqtdasmwindow.moc.o \ |
| 745 | $(OSDOBJ)/modules/debugger/qt/debugqtmainwindow.moc.o \ |
| 746 | $(OSDOBJ)/modules/debugger/qt/debugqtmemorywindow.moc.o \ |
| 747 | $(OSDOBJ)/modules/debugger/qt/debugqtbreakpointswindow.moc.o \ |
| 748 | $(OSDOBJ)/modules/debugger/qt/debugqtdeviceswindow.moc.o \ |
| 749 | $(OSDOBJ)/modules/debugger/qt/debugqtdeviceinformationwindow.moc.o |
| 751 | 750 | |
| 752 | 751 | DEFS += -DUSE_QTDEBUG=1 |
| 753 | 752 | |