SameBoy | Accurate GB/GBC emulator |
| download: https://git.y1.nz/archives/sameboy.tar.gz | |
| README | Files | Log | Refs | LICENSE |
commit 36cf7782326800811f72f9354441542c6387bfed parent ecaa92f853edaad3bda08a41ba3dfb1168c153bb Author: Lior Halphon <LIJI32@gmail.com> Date: Sat, 1 Oct 2022 16:06:11 +0300 Update the Cocoa debugger interface with buttons, add an interrupt command Diffstat:
| A | Cocoa/ContinueTemplate.png | 0 | |
| A | Cocoa/ContinueTemplate@2x.png | 0 | |
| M | Cocoa/Document.h | 9 | +++++++++ |
| M | Cocoa/Document.m | 112 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------- |
| M | Cocoa/Document.xib | 163 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------- |
| A | Cocoa/FinishTemplate.png | 0 | |
| A | Cocoa/FinishTemplate@2x.png | 0 | |
| A | Cocoa/GBDebuggerButton.h | 7 | +++++++ |
| A | Cocoa/GBDebuggerButton.m | 48 | ++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | Cocoa/GBTerminalTextFieldCell.m | 23 | +++++++++++++++++++---- |
| A | Cocoa/HelpTemplate.png | 0 | |
| A | Cocoa/HelpTemplate@2x.png | 0 | |
| A | Cocoa/InterruptTemplate.png | 0 | |
| A | Cocoa/InterruptTemplate@2x.png | 0 | |
| A | Cocoa/NSTextFieldCell+Inset.h | 6 | ++++++ |
| A | Cocoa/NSTextFieldCell+Inset.m | 39 | +++++++++++++++++++++++++++++++++++++++ |
| A | Cocoa/NextTemplate.png | 0 | |
| A | Cocoa/NextTemplate@2x.png | 0 | |
| A | Cocoa/StepTemplate.png | 0 | |
| A | Cocoa/StepTemplate@2x.png | 0 | |
| M | Core/debugger.c | 21 | ++++++++++++++++++++- |
21 files changed, 358 insertions(+), 70 deletions(-)
diff --git a/Cocoa/ContinueTemplate.png b/Cocoa/ContinueTemplate.png Binary files differ. diff --git a/Cocoa/ContinueTemplate@2x.png b/Cocoa/ContinueTemplate@2x.png Binary files differ. diff --git a/Cocoa/Document.h b/Cocoa/Document.h @@ -4,6 +4,8 @@ #import "GBSplitView.h" #import "GBVisualizerView.h" #import "GBOSDView.h" +#import "GBOptionalVisualEffectView.h" +#import "GBDebuggerButton.h" @class GBCheatWindowController; @class GBPaletteView; @@ -58,6 +60,13 @@ @property uint8_t oamHeight; @property (strong) IBOutlet NSView *audioRecordingAccessoryView; @property (strong) IBOutlet NSPopUpButton *audioFormatButton; +@property (strong) IBOutlet GBOptionalVisualEffectView *debuggerSidebarEffectView; + +@property (strong) IBOutlet GBDebuggerButton *debuggerContinueButton; +@property (strong) IBOutlet GBDebuggerButton *debuggerNextButton; +@property (strong) IBOutlet GBDebuggerButton *debuggerStepButton; +@property (strong) IBOutlet GBDebuggerButton *debuggerFinishButton; + + (NSImage *) imageFromData:(NSData *)data width:(NSUInteger) width height:(NSUInteger) height scale:(double) scale; -(uint8_t) readMemory:(uint16_t) addr; diff --git a/Cocoa/Document.m b/Cocoa/Document.m @@ -74,7 +74,7 @@ enum model { bool fullScreen; bool in_sync_input; - bool _debuggerCommandWhilePaused; + NSString *_debuggerCommandWhilePaused; HFController *hex_controller; NSString *lastConsoleInput; @@ -549,6 +549,10 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) - (void) start { + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateDebuggerButtons]; + [slave updateDebuggerButtons]; + }); self.gbsPlayPauseButton.state = true; self.view.mouseHidingEnabled = (self.mainWindow.styleMask & NSWindowStyleMaskFullScreen) != 0; if (master) { @@ -562,6 +566,10 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency) - (void) stop { + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateDebuggerButtons]; + [slave updateDebuggerButtons]; + }); self.gbsPlayPauseButton.state = false; if (master) { if (!master->running) return; @@ -1151,16 +1159,21 @@ static bool is_path_writeable(const char *path) [[NSUserDefaults standardUserDefaults] setBool:!_audioClient.isPlaying forKey:@"Mute"]; } +- (bool) isPaused +{ + if (self.partner) { + return !self.partner->running || GB_debugger_is_stopped(&gb) || GB_debugger_is_stopped(&self.partner->gb); + } + return (!running) || GB_debugger_is_stopped(&gb); +} + - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)anItem { if ([anItem action] == @selector(mute:)) { [(NSMenuItem *)anItem setState:!_audioClient.isPlaying]; } else if ([anItem action] == @selector(togglePause:)) { - if (master) { - [(NSMenuItem *)anItem setState:(!master->running) || (GB_debugger_is_stopped(&gb)) || (GB_debugger_is_stopped(&gb))]; - } - [(NSMenuItem *)anItem setState:(!running) || (GB_debugger_is_stopped(&gb))]; + [(NSMenuItem *)anItem setState:self.isPaused]; return !GB_debugger_is_stopped(&gb); } else if ([anItem action] == @selector(reset:) && anItem.tag != MODEL_NONE) { @@ -1322,15 +1335,27 @@ static bool is_path_writeable(const char *path) [self.consoleWindow orderBack:nil]; } -- (IBAction)consoleInput:(NSTextField *)sender +- (void)queueDebuggerCommand:(NSString *)command { if (!master && !running && !GB_debugger_is_stopped(&gb)) { - _debuggerCommandWhilePaused = true; + _debuggerCommandWhilePaused = command; GB_debugger_break(&gb); [self start]; return; } - + + if (!in_sync_input) { + [self log:">"]; + } + [self log:[command UTF8String]]; + [self log:"\n"]; + [has_debugger_input lock]; + [debugger_input_queue addObject:command]; + [has_debugger_input unlockWithCondition:1]; +} + +- (IBAction)consoleInput:(NSTextField *)sender +{ NSString *line = [sender stringValue]; if ([line isEqualToString:@""] && lastConsoleInput) { line = lastConsoleInput; @@ -1341,15 +1366,8 @@ static bool is_path_writeable(const char *path) else { line = @""; } - - if (!in_sync_input) { - [self log:">"]; - } - [self log:[line UTF8String]]; - [self log:"\n"]; - [has_debugger_input lock]; - [debugger_input_queue addObject:line]; - [has_debugger_input unlockWithCondition:1]; + + [self queueDebuggerCommand: line]; [sender setStringValue:@""]; } @@ -1397,7 +1415,7 @@ static bool is_path_writeable(const char *path) [console_output_lock unlock]; } -- (char *) getDebuggerInput +- (char *)getDebuggerInput { bool isPlaying = _audioClient.isPlaying; if (isPlaying) { @@ -1408,11 +1426,16 @@ static bool is_path_writeable(const char *path) [audioLock unlock]; in_sync_input = true; [self updateSideView]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self updateDebuggerButtons]; + }); + [self.partner updateDebuggerButtons]; [self log:">"]; if (_debuggerCommandWhilePaused) { - _debuggerCommandWhilePaused = false; + NSString *command = _debuggerCommandWhilePaused; + _debuggerCommandWhilePaused = nil; dispatch_async(dispatch_get_main_queue(), ^{ - [self consoleInput:self.consoleInput]; + [self queueDebuggerCommand:command]; }); } [has_debugger_input lockWhenCondition:1]; @@ -1426,6 +1449,8 @@ static bool is_path_writeable(const char *path) shouldClearSideView = false; [self.debuggerSideView setString:@""]; } + [self updateDebuggerButtons]; + [self.partner updateDebuggerButtons]; }); if (isPlaying) { [_audioClient start]; @@ -2231,7 +2256,7 @@ static bool is_path_writeable(const char *path) /* NSSplitView renders its separator without the proper vibrancy, so we made it transparent and move an NSBox-based separator that renders properly so it acts like the split view's separator. */ NSRect rect = self.debuggerVerticalLine.frame; - rect.origin.x = [[[splitview arrangedSubviews] firstObject] frame].size.width - 1; + rect.origin.x = [[[splitview arrangedSubviews] firstObject] frame].size.width - 2; self.debuggerVerticalLine.frame = rect; } @@ -2573,4 +2598,49 @@ static bool is_path_writeable(const char *path) }]; } +- (void)updateDebuggerButtons +{ + bool updateContinue = false; + if (@available(macOS 10.10, *)) { + if ([self.consoleInput.placeholderAttributedString.string isEqualToString:self.debuggerContinueButton.alternateTitle]) { + [self.debuggerContinueButton mouseExited:nil]; + updateContinue = true; + } + } + if (self.isPaused) { + self.debuggerContinueButton.toolTip = self.debuggerContinueButton.title = @"Continue"; + self.debuggerContinueButton.alternateTitle = @"continue"; + self.debuggerContinueButton.imagePosition = NSImageOnly; + if (@available(macOS 10.14, *)) { + self.debuggerContinueButton.contentTintColor = nil; + } + self.debuggerContinueButton.image = [NSImage imageNamed:@"ContinueTemplate"]; + + self.debuggerNextButton.enabled = true; + self.debuggerStepButton.enabled = true; + self.debuggerFinishButton.enabled = true; + } + else { + self.debuggerContinueButton.toolTip = self.debuggerContinueButton.title = @"Interrupt"; + self.debuggerContinueButton.alternateTitle = @"interrupt"; + self.debuggerContinueButton.imagePosition = NSImageOnly; + if (@available(macOS 10.14, *)) { + self.debuggerContinueButton.contentTintColor = [NSColor controlAccentColor]; + } + self.debuggerContinueButton.image = [NSImage imageNamed:@"InterruptTemplate"]; + + self.debuggerNextButton.enabled = false; + self.debuggerStepButton.enabled = false; + self.debuggerFinishButton.enabled = false; + } + if (updateContinue) { + [self.debuggerContinueButton mouseEntered:nil]; + } +} + +- (IBAction)debuggerButtonPressed:(NSButton *)sender +{ + [self queueDebuggerCommand:sender.alternateTitle]; +} + @end diff --git a/Cocoa/Document.xib b/Cocoa/Document.xib @@ -3,6 +3,7 @@ <dependencies> <deployment identifier="macosx"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14868"/> + <capability name="System colors introduced in macOS 10.14" minToolsVersion="10.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <objects> @@ -14,9 +15,14 @@ <outlet property="consoleInput" destination="l22-S8-uji" id="Heu-am-YgB"/> <outlet property="consoleOutput" destination="doS-dM-hnl" id="Gn5-ju-Wb0"/> <outlet property="consoleWindow" destination="21F-Ah-yHX" id="eQ4-ug-LsT"/> + <outlet property="debuggerContinueButton" destination="G4h-KO-Z3g" id="Dad-5e-XYM"/> + <outlet property="debuggerFinishButton" destination="vtb-n5-Qlz" id="9vv-fJ-gxp"/> + <outlet property="debuggerNextButton" destination="cOi-Rs-9gS" id="Xjx-uM-D0u"/> <outlet property="debuggerSideView" destination="JgV-7E-iwp" id="RaA-fw-3i1"/> <outlet property="debuggerSideViewInput" destination="w0g-eK-jM4" id="GBf-WK-ryI"/> + <outlet property="debuggerSidebarEffectView" destination="4Z2-33-dYY" id="Ja6-bC-rQg"/> <outlet property="debuggerSplitView" destination="pUc-ZN-vl5" id="0sG-0D-cID"/> + <outlet property="debuggerStepButton" destination="DsN-Ce-QoH" id="Ts4-uK-pvI"/> <outlet property="debuggerVerticalLine" destination="7bR-gM-1At" id="rfy-7Z-388"/> <outlet property="feedImageView" destination="Ar0-nN-eop" id="wHa-St-o4G"/> <outlet property="gridButton" destination="fL6-2S-Rgd" id="jtV-jh-GHC"/> @@ -87,50 +93,31 @@ <rect key="frame" x="0.0" y="0.0" width="921" height="400"/> <autoresizingMask key="autoresizingMask"/> <subviews> - <textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" mirrorLayoutDirectionWhenInternationalizing="never" translatesAutoresizingMaskIntoConstraints="NO" id="l22-S8-uji"> - <rect key="frame" x="0.0" y="0.0" width="921" height="24"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> - <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" focusRingType="none" id="p3j-nS-44f" customClass="GBTerminalTextFieldCell"> - <font key="font" metaFont="fixedUser" size="11"/> - <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/> - <color key="backgroundColor" red="0.16470588235294117" green="0.16470588235294117" blue="0.16470588235294117" alpha="1" colorSpace="calibratedRGB"/> - <allowedInputSourceLocales> - <string>NSAllRomanInputSourcesLocaleIdentifier</string> - </allowedInputSourceLocales> - </textFieldCell> - <connections> - <action selector="consoleInput:" target="-2" id="ylQ-vw-ARS"/> - </connections> - </textField> - <box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="960-dL-7ZY"> - <rect key="frame" x="0.0" y="23" width="921" height="5"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> - </box> <box horizontalHuggingPriority="750" boxType="separator" id="7bR-gM-1At"> - <rect key="frame" x="590" y="25" width="5" height="376"/> + <rect key="frame" x="590" y="0.0" width="5" height="401"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" heightSizable="YES"/> </box> <splitView dividerStyle="thin" vertical="YES" id="pUc-ZN-vl5" customClass="GBSplitView"> - <rect key="frame" x="0.0" y="25" width="921" height="376"/> + <rect key="frame" x="0.0" y="0.0" width="921" height="401"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> - <customView fixedFrame="YES" id="2rj-7i-kxc"> - <rect key="frame" x="0.0" y="0.0" width="591" height="376"/> + <customView fixedFrame="YES" id="2rj-7i-kxc" customClass="GBOptionalVisualEffectView"> + <rect key="frame" x="0.0" y="0.0" width="591" height="401"/> <autoresizingMask key="autoresizingMask"/> <subviews> <scrollView fixedFrame="YES" borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="oTo-zx-o6N"> - <rect key="frame" x="0.0" y="0.0" width="591" height="376"/> + <rect key="frame" x="0.0" y="52" width="591" height="349"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <clipView key="contentView" ambiguous="YES" drawsBackground="NO" copiesOnScroll="NO" id="EQe-Ad-L7S"> - <rect key="frame" x="0.0" y="0.0" width="591" height="376"/> - <autoresizingMask key="autoresizingMask"/> + <rect key="frame" x="0.0" y="0.0" width="591" height="349"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> - <textView ambiguous="YES" editable="NO" drawsBackground="NO" importsGraphics="NO" richText="NO" verticallyResizable="YES" baseWritingDirection="leftToRight" findStyle="bar" allowsNonContiguousLayout="YES" id="doS-dM-hnl"> - <rect key="frame" x="0.0" y="0.0" width="591" height="376"/> + <textView ambiguous="YES" editable="NO" importsGraphics="NO" richText="NO" verticallyResizable="YES" baseWritingDirection="leftToRight" findStyle="bar" allowsNonContiguousLayout="YES" id="doS-dM-hnl"> + <rect key="frame" x="0.0" y="0.0" width="591" height="349"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> - <color key="backgroundColor" red="0.14901960784313725" green="0.14901960784313725" blue="0.14901960784313725" alpha="1" colorSpace="calibratedRGB"/> - <size key="minSize" width="591" height="376"/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.25" colorSpace="custom" customColorSpace="sRGB"/> + <size key="minSize" width="591" height="349"/> <size key="maxSize" width="1160" height="10000000"/> <color key="insertionPointColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> <allowedInputSourceLocales> @@ -138,29 +125,112 @@ </allowedInputSourceLocales> </textView> </subviews> - <color key="backgroundColor" red="0.16470588235294117" green="0.16470588235294117" blue="0.16470588235294117" alpha="1" colorSpace="calibratedRGB"/> </clipView> <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="YES" id="3fZ-tl-Zi7"> <rect key="frame" x="-100" y="-100" width="87" height="18"/> <autoresizingMask key="autoresizingMask"/> </scroller> <scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="cwi-6E-rbh"> - <rect key="frame" x="575" y="0.0" width="16" height="376"/> + <rect key="frame" x="575" y="0.0" width="16" height="349"/> <autoresizingMask key="autoresizingMask"/> </scroller> </scrollView> + <textField focusRingType="none" verticalHuggingPriority="750" mirrorLayoutDirectionWhenInternationalizing="never" id="l22-S8-uji"> + <rect key="frame" x="0.0" y="0.0" width="593" height="26"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> + <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" focusRingType="none" drawsBackground="YES" id="p3j-nS-44f" customClass="GBTerminalTextFieldCell"> + <font key="font" metaFont="fixedUser" size="11"/> + <color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/> + <color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.25" colorSpace="custom" customColorSpace="calibratedRGB"/> + <allowedInputSourceLocales> + <string>NSAllRomanInputSourcesLocaleIdentifier</string> + </allowedInputSourceLocales> + </textFieldCell> + <connections> + <action selector="consoleInput:" target="-2" id="ylQ-vw-ARS"/> + </connections> + </textField> + <box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="xJr-K6-B4B"> + <rect key="frame" x="0.0" y="49" width="591" height="4"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> + </box> + <box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="9DF-fj-a2v"> + <rect key="frame" x="0.0" y="24" width="591" height="4"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> + </box> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="G4h-KO-Z3g" customClass="GBDebuggerButton"> + <rect key="frame" x="0.0" y="26" width="26" height="26"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <buttonCell key="cell" type="bevel" title="Interrupt" alternateTitle="interrupt" bezelStyle="rounded" image="InterruptTemplate" imagePosition="only" alignment="center" imageScaling="proportionallyDown" inset="2" id="wfO-32-eG5"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <color key="contentTintColor" name="controlAccentColor" catalog="System" colorSpace="catalog"/> + <connections> + <action selector="debuggerButtonPressed:" target="-2" id="SjG-90-8dJ"/> + <outlet property="textField" destination="l22-S8-uji" id="NZ8-eJ-Uyd"/> + </connections> + </button> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cOi-Rs-9gS" customClass="GBDebuggerButton"> + <rect key="frame" x="26" y="26" width="26" height="26"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <buttonCell key="cell" type="bevel" title="Step Over" alternateTitle="next" bezelStyle="rounded" image="NextTemplate" imagePosition="only" alignment="center" enabled="NO" imageScaling="proportionallyDown" inset="2" id="buW-ke-lgF"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="debuggerButtonPressed:" target="-2" id="g7E-UM-SHV"/> + <outlet property="textField" destination="l22-S8-uji" id="1uM-AA-yHi"/> + </connections> + </button> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DsN-Ce-QoH" customClass="GBDebuggerButton"> + <rect key="frame" x="52" y="26" width="26" height="26"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <buttonCell key="cell" type="bevel" title="Step Into" alternateTitle="step" bezelStyle="rounded" image="StepTemplate" imagePosition="only" alignment="center" enabled="NO" imageScaling="proportionallyDown" inset="2" id="ATJ-Vx-zbo"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="debuggerButtonPressed:" target="-2" id="QMw-82-HKJ"/> + <outlet property="textField" destination="l22-S8-uji" id="qaF-TF-cwg"/> + </connections> + </button> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vtb-n5-Qlz" customClass="GBDebuggerButton"> + <rect key="frame" x="76" y="26" width="26" height="26"/> + <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> + <buttonCell key="cell" type="bevel" title="Step Out" alternateTitle="finish" bezelStyle="rounded" image="FinishTemplate" imagePosition="only" alignment="center" enabled="NO" imageScaling="proportionallyDown" inset="2" id="8mF-ii-5Hx"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="debuggerButtonPressed:" target="-2" id="krr-9m-Jfz"/> + <outlet property="textField" destination="l22-S8-uji" id="uYK-tU-BnO"/> + </connections> + </button> + <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oCa-UH-1mi" customClass="GBDebuggerButton"> + <rect key="frame" x="565" y="26" width="26" height="26"/> + <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/> + <buttonCell key="cell" type="bevel" title="Help" alternateTitle="help" bezelStyle="rounded" image="HelpTemplate" imagePosition="only" alignment="center" imageScaling="proportionallyDown" inset="2" id="tvn-kY-8FO"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + <connections> + <action selector="debuggerButtonPressed:" target="-2" id="PwN-rf-AcB"/> + <outlet property="textField" destination="l22-S8-uji" id="blK-B3-MWI"/> + </connections> + </button> </subviews> </customView> - <customView fixedFrame="YES" id="4Z2-33-dYY"> - <rect key="frame" x="592" y="0.0" width="329" height="376"/> + <customView fixedFrame="YES" id="4Z2-33-dYY" customClass="GBOptionalVisualEffectView"> + <rect key="frame" x="592" y="0.0" width="329" height="401"/> <autoresizingMask key="autoresizingMask"/> <subviews> <scrollView fixedFrame="YES" borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" scrollerKnobStyle="dark" translatesAutoresizingMaskIntoConstraints="NO" id="V9U-Ua-F4z"> - <rect key="frame" x="0.0" y="329" width="329" height="47"/> + <rect key="frame" x="0.0" y="354" width="329" height="47"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> <clipView key="contentView" ambiguous="YES" drawsBackground="NO" copiesOnScroll="NO" id="YHx-TM-zIC"> <rect key="frame" x="0.0" y="0.0" width="329" height="47"/> - <autoresizingMask key="autoresizingMask"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <textView ambiguous="YES" drawsBackground="NO" importsGraphics="NO" richText="NO" verticallyResizable="YES" allowsCharacterPickerTouchBarItem="NO" allowsUndo="YES" allowsNonContiguousLayout="YES" textCompletion="NO" spellingCorrection="YES" id="w0g-eK-jM4"> <rect key="frame" x="0.0" y="0.0" width="329" height="47"/> @@ -186,22 +256,22 @@ </scroller> </scrollView> <box verticalHuggingPriority="750" fixedFrame="YES" boxType="separator" translatesAutoresizingMaskIntoConstraints="NO" id="5qI-qZ-nkh"> - <rect key="frame" x="0.0" y="327" width="327" height="5"/> + <rect key="frame" x="0.0" y="352" width="329" height="5"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> </box> <scrollView fixedFrame="YES" borderType="none" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vts-CC-ZjQ"> - <rect key="frame" x="0.0" y="2" width="329" height="328"/> + <rect key="frame" x="0.0" y="0.0" width="329" height="354"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <clipView key="contentView" ambiguous="YES" drawsBackground="NO" copiesOnScroll="NO" id="Cs9-3x-ATg"> - <rect key="frame" x="0.0" y="0.0" width="329" height="328"/> - <autoresizingMask key="autoresizingMask"/> + <rect key="frame" x="0.0" y="0.0" width="329" height="354"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <textView ambiguous="YES" editable="NO" drawsBackground="NO" importsGraphics="NO" richText="NO" verticallyResizable="YES" baseWritingDirection="leftToRight" findStyle="bar" allowsNonContiguousLayout="YES" spellingCorrection="YES" id="JgV-7E-iwp"> - <rect key="frame" x="0.0" y="0.0" width="329" height="328"/> + <rect key="frame" x="0.0" y="0.0" width="329" height="354"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" red="0.14901960780000001" green="0.14901960780000001" blue="0.14901960780000001" alpha="1" colorSpace="calibratedRGB"/> - <size key="minSize" width="329" height="328"/> + <size key="minSize" width="329" height="354"/> <size key="maxSize" width="1160" height="10000000"/> <color key="insertionPointColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> <allowedInputSourceLocales> @@ -216,7 +286,7 @@ <autoresizingMask key="autoresizingMask"/> </scroller> <scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="4jm-Gm-D2R"> - <rect key="frame" x="313" y="0.0" width="16" height="328"/> + <rect key="frame" x="313" y="0.0" width="16" height="354"/> <autoresizingMask key="autoresizingMask"/> </scroller> </scrollView> @@ -778,7 +848,7 @@ <autoresizingMask key="autoresizingMask" flexibleMinX="YES" heightSizable="YES"/> <clipView key="contentView" id="mzf-yu-RID"> <rect key="frame" x="1" y="0.0" width="398" height="274"/> - <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <autoresizingMask key="autoresizingMask"/> <subviews> <tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="none" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" typeSelect="NO" headerView="pvX-uJ-qK5" id="tA3-8T-bxb"> <rect key="frame" x="0.0" y="0.0" width="398" height="257"/> @@ -877,7 +947,12 @@ </customObject> </objects> <resources> + <image name="FinishTemplate" width="14" height="14"/> + <image name="HelpTemplate" width="14" height="14"/> + <image name="InterruptTemplate" width="14" height="14"/> <image name="NSFolder" width="32" height="32"/> <image name="NSStopProgressFreestandingTemplate" width="14" height="14"/> + <image name="NextTemplate" width="14" height="14"/> + <image name="StepTemplate" width="14" height="14"/> </resources> </document> diff --git a/Cocoa/FinishTemplate.png b/Cocoa/FinishTemplate.png Binary files differ. diff --git a/Cocoa/FinishTemplate@2x.png b/Cocoa/FinishTemplate@2x.png Binary files differ. diff --git a/Cocoa/GBDebuggerButton.h b/Cocoa/GBDebuggerButton.h @@ -0,0 +1,7 @@ +#import <Cocoa/Cocoa.h> + +@class GBDocument; +@interface GBDebuggerButton : NSButton +@property (weak) IBOutlet NSTextField *textField; +@end + diff --git a/Cocoa/GBDebuggerButton.m b/Cocoa/GBDebuggerButton.m @@ -0,0 +1,48 @@ +#import "GBDebuggerButton.h" + +@implementation GBDebuggerButton +{ + NSTrackingArea *_trackingArea; +} +- (instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + self.toolTip = self.title; + return self; +} + +- (void)mouseEntered:(NSEvent *)event +{ + if (@available(macOS 10.10, *)) { + NSDictionary *attributes = @{ + NSForegroundColorAttributeName: [NSColor colorWithWhite:1.0 alpha:0.5], + NSFontAttributeName: self.textField.font + }; + self.textField.placeholderAttributedString = + [[NSAttributedString alloc] initWithString:self.alternateTitle attributes:attributes]; + } +} + +- (void)mouseExited:(NSEvent *)event +{ + if (@available(macOS 10.10, *)) { + if ([self.textField.placeholderAttributedString.string isEqualToString:self.alternateTitle]) { + self.textField.placeholderAttributedString = nil; + } + } +} + +-(void)updateTrackingAreas +{ + [super updateTrackingAreas]; + if (_trackingArea) { + [self removeTrackingArea:_trackingArea]; + } + + _trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds] + options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways + owner:self + userInfo:nil]; + [self addTrackingArea:_trackingArea]; +} +@end diff --git a/Cocoa/GBTerminalTextFieldCell.m b/Cocoa/GBTerminalTextFieldCell.m @@ -1,7 +1,11 @@ #import <Carbon/Carbon.h> #import "GBTerminalTextFieldCell.h" +#import "NSTextFieldCell+Inset.h" @interface GBTerminalTextView : NSTextView +{ + @public __weak NSTextField *_field; +} @property GB_gameboy_t *gb; @end @@ -10,7 +14,7 @@ GBTerminalTextView *field_editor; } -- (NSTextView *)fieldEditorForView:(NSView *)controlView +- (NSTextView *)fieldEditorForView:(NSTextField *)controlView { if (field_editor) { field_editor.gb = self.gb; @@ -19,6 +23,10 @@ field_editor = [[GBTerminalTextView alloc] init]; [field_editor setFieldEditor:true]; field_editor.gb = self.gb; + field_editor->_field = (NSTextField *)controlView; + ((NSTextFieldCell *)controlView.cell).textInset = + field_editor.textContainerInset = + NSMakeSize(0, 2); return field_editor; } @@ -185,14 +193,21 @@ return [super resignFirstResponder]; } --(void)drawRect:(NSRect)dirtyRect +- (NSColor *)backgroundColor +{ + return nil; +} + +- (void)drawRect:(NSRect)dirtyRect { - [super drawRect:dirtyRect]; if (reverse_search_mode && [super string].length == 0) { NSMutableDictionary *attributes = [self.typingAttributes mutableCopy]; NSColor *color = [attributes[NSForegroundColorAttributeName] colorWithAlphaComponent:0.5]; [attributes setObject:color forKey:NSForegroundColorAttributeName]; - [[[NSAttributedString alloc] initWithString:@"Reverse search..." attributes:attributes] drawAtPoint:NSMakePoint(2, 0)]; + [[[NSAttributedString alloc] initWithString:@"Reverse search..." attributes:attributes] drawAtPoint:NSMakePoint(2, 2)]; + } + else { + [super drawRect:dirtyRect]; } } diff --git a/Cocoa/HelpTemplate.png b/Cocoa/HelpTemplate.png Binary files differ. diff --git a/Cocoa/HelpTemplate@2x.png b/Cocoa/HelpTemplate@2x.png Binary files differ. diff --git a/Cocoa/InterruptTemplate.png b/Cocoa/InterruptTemplate.png Binary files differ. diff --git a/Cocoa/InterruptTemplate@2x.png b/Cocoa/InterruptTemplate@2x.png Binary files differ. diff --git a/Cocoa/NSTextFieldCell+Inset.h b/Cocoa/NSTextFieldCell+Inset.h @@ -0,0 +1,6 @@ +#import <AppKit/AppKit.h> +#import <Cocoa/Cocoa.h> + +@interface NSTextFieldCell (Inset) +@property NSSize textInset; +@end diff --git a/Cocoa/NSTextFieldCell+Inset.m b/Cocoa/NSTextFieldCell+Inset.m @@ -0,0 +1,39 @@ +#import "NSTextFieldCell+Inset.h" +#import <AppKit/AppKit.h> +#import <objc/runtime.h> + +@interface NSTextFieldCell () +- (CGRect)_textLayerDrawingRectForCellFrame:(CGRect)rect; +@property NSSize textInset; +@end + +@implementation NSTextFieldCell (Inset) + +- (void)setTextInset:(NSSize)textInset +{ + objc_setAssociatedObject(self, @selector(textInset), @(textInset), OBJC_ASSOCIATION_RETAIN); +} + +- (NSSize)textInset +{ + return [objc_getAssociatedObject(self, _cmd) sizeValue]; +} + +- (CGRect)_textLayerDrawingRectForCellFrameHook:(CGRect)rect +{ + CGRect ret = [self _textLayerDrawingRectForCellFrameHook:rect]; + NSSize inset = self.textInset; + ret.origin.x += inset.width; + ret.origin.y += inset.height; + ret.size.width -= inset.width; + ret.size.height -= inset.height; + return ret; +} + ++ (void)load +{ + method_exchangeImplementations(class_getInstanceMethod(self, @selector(_textLayerDrawingRectForCellFrame:)), + class_getInstanceMethod(self, @selector(_textLayerDrawingRectForCellFrameHook:))); +} + +@end diff --git a/Cocoa/NextTemplate.png b/Cocoa/NextTemplate.png Binary files differ. diff --git a/Cocoa/NextTemplate@2x.png b/Cocoa/NextTemplate@2x.png Binary files differ. diff --git a/Cocoa/StepTemplate.png b/Cocoa/StepTemplate.png Binary files differ. diff --git a/Cocoa/StepTemplate@2x.png b/Cocoa/StepTemplate@2x.png Binary files differ. diff --git a/Core/debugger.c b/Core/debugger.c @@ -710,7 +710,7 @@ static const char *lstrip(const char *str) #define STOPPED_ONLY \ if (!gb->debug_stopped) { \ -GB_log(gb, "Program is running. \n"); \ +GB_log(gb, "Program is running, use 'interrupt' to stop execution.\n"); \ return false; \ } @@ -749,6 +749,24 @@ static bool cont(GB_gameboy_t *gb, char *arguments, char *modifiers, const debug return false; } +static bool interrupt(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) +{ + NO_MODIFIERS + + if (strlen(lstrip(arguments))) { + print_usage(gb, command); + return true; + } + + if (gb->debug_stopped) { + GB_log(gb, "Program already stopped.\n"); + return true; + } + + gb->debug_stopped = true; + return true; +} + static bool next(GB_gameboy_t *gb, char *arguments, char *modifiers, const debugger_command_t *command) { NO_MODIFIERS @@ -1966,6 +1984,7 @@ static bool help(GB_gameboy_t *gb, char *arguments, char *modifiers, const debug /* Commands without implementations are aliases of the previous non-alias commands */ static const debugger_command_t commands[] = { {"continue", 1, cont, "Continue running until next stop"}, + {"interrupt", 1, interrupt, "Interrupt the program execution"}, {"next", 1, next, "Run the next instruction, skipping over function calls"}, {"step", 1, step, "Run the next instruction, stepping into function calls"}, {"finish", 1, finish, "Run until the current function returns"},
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.