Add cheats UI to Cocoa
This commit is contained in:
parent
337e74352d
commit
852a6997ed
@ -33,6 +33,7 @@
|
||||
@property (strong) IBOutlet NSTextView *debuggerSideView;
|
||||
@property (strong) IBOutlet GBSplitView *debuggerSplitView;
|
||||
@property (strong) IBOutlet NSBox *debuggerVerticalLine;
|
||||
@property (strong) IBOutlet NSPanel *cheatsWindow;
|
||||
|
||||
-(uint8_t) readMemory:(uint16_t) addr;
|
||||
-(void) writeMemory:(uint16_t) addr value:(uint8_t)value;
|
||||
|
@ -706,6 +706,9 @@ static void audioCallback(GB_gameboy_t *gb, GB_sample_t *sample)
|
||||
else if ([anItem action] == @selector(connectPrinter:)) {
|
||||
[(NSMenuItem*)anItem setState:accessory == GBAccessoryPrinter];
|
||||
}
|
||||
else if ([anItem action] == @selector(toggleCheats:)) {
|
||||
[(NSMenuItem*)anItem setState:GB_cheats_enabled(&gb)];
|
||||
}
|
||||
return [super validateUserInterfaceItem:anItem];
|
||||
}
|
||||
|
||||
@ -1699,4 +1702,14 @@ static void audioCallback(GB_gameboy_t *gb, GB_sample_t *sample)
|
||||
self.debuggerVerticalLine.frame = rect;
|
||||
}
|
||||
|
||||
- (IBAction)showCheats:(id)sender
|
||||
{
|
||||
[self.cheatsWindow makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
- (IBAction)toggleCheats:(id)sender
|
||||
{
|
||||
GB_set_cheats_enabled(&gb, !GB_cheats_enabled(&gb));
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -9,6 +9,7 @@
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="Document">
|
||||
<connections>
|
||||
<outlet property="TilemapSetButton" destination="k4c-Vg-MBu" id="Ak1-6d-B1N"/>
|
||||
<outlet property="cheatsWindow" destination="4Yb-Np-JrF" id="YCZ-cj-gn5"/>
|
||||
<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"/>
|
||||
@ -44,8 +45,7 @@
|
||||
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="xOd-HO-29H" userLabel="Window">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowCollectionBehavior key="collectionBehavior" fullScreenPrimary="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="133" y="235" width="160" height="144"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="160" height="144"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<value key="minSize" type="size" width="160" height="144"/>
|
||||
<view key="contentView" id="gIp-Ho-8D9">
|
||||
@ -69,11 +69,10 @@
|
||||
</connections>
|
||||
<point key="canvasLocation" x="293" y="347"/>
|
||||
</window>
|
||||
<window title="Debug Console" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="21F-Ah-yHX" customClass="NSPanel">
|
||||
<window title="Debug Console" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="21F-Ah-yHX" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES" utility="YES" HUD="YES"/>
|
||||
<windowCollectionBehavior key="collectionBehavior" fullScreenAuxiliary="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="272" y="172" width="921" height="400"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="921" height="400"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<value key="minSize" type="size" width="921" height="400"/>
|
||||
<view key="contentView" id="dCP-E5-7Fi">
|
||||
@ -103,7 +102,7 @@
|
||||
<rect key="frame" x="590" y="25" width="5" height="376"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
</box>
|
||||
<splitView arrangesAllSubviews="NO" dividerStyle="thin" vertical="YES" id="pUc-ZN-vl5" customClass="GBSplitView">
|
||||
<splitView dividerStyle="thin" vertical="YES" id="pUc-ZN-vl5" customClass="GBSplitView">
|
||||
<rect key="frame" x="0.0" y="25" width="921" height="376"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
@ -228,11 +227,10 @@
|
||||
</view>
|
||||
<point key="canvasLocation" x="347.5" y="-29"/>
|
||||
</window>
|
||||
<window title="Memory" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="mRm-dL-mCj" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<window title="Memory" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="mRm-dL-mCj" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES"/>
|
||||
<windowCollectionBehavior key="collectionBehavior" fullScreenAuxiliary="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="272" y="172" width="528" height="320"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="528" height="320"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<view key="contentView" id="8hr-8o-3rN">
|
||||
<rect key="frame" x="0.0" y="0.0" width="528" height="320"/>
|
||||
@ -312,11 +310,10 @@
|
||||
<point key="canvasLocation" x="-185" y="61"/>
|
||||
</window>
|
||||
<menuItem title="Cartridge RAM" id="ylM-ah-PNQ"/>
|
||||
<window title="VRAM Viewer" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="mbr-db-iZh" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
|
||||
<window title="VRAM Viewer" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="mbr-db-iZh" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES"/>
|
||||
<windowCollectionBehavior key="collectionBehavior" fullScreenAuxiliary="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="283" y="305" width="512" height="432"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="512" height="432"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<view key="contentView" id="GYW-dv-Um1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="512" height="432"/>
|
||||
@ -784,10 +781,9 @@
|
||||
<contentBorderThickness minY="24"/>
|
||||
<point key="canvasLocation" x="182" y="760"/>
|
||||
</window>
|
||||
<window title="Printer Feed" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="NdE-0B-WCf" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="272" y="172" width="320" height="288"/>
|
||||
<window title="Printer Feed" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" hidesOnDeactivate="YES" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="NdE-0B-WCf" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="320" height="288"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<view key="contentView" id="RRS-aa-bPT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="288"/>
|
||||
@ -803,7 +799,7 @@
|
||||
<point key="canvasLocation" x="-159" y="356"/>
|
||||
</window>
|
||||
<button verticalHuggingPriority="750" id="RLc-0I-sYZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="48" height="25"/>
|
||||
<rect key="frame" x="0.5" y="0.0" width="48" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="roundTextured" title="Save" bezelStyle="texturedRounded" alignment="center" controlSize="mini" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="shw-MJ-B3T">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
@ -814,5 +810,264 @@
|
||||
</connections>
|
||||
<point key="canvasLocation" x="-507" y="397"/>
|
||||
</button>
|
||||
<window title="Cheats" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="4Yb-Np-JrF" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="692" height="272"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<view key="contentView" id="gBP-5p-BTh">
|
||||
<rect key="frame" x="0.0" y="0.0" width="692" height="272"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<view id="fWr-0i-K1d" customClass="GBOptionalVisualEffectView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="294" height="272"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="hqi-ob-NW9">
|
||||
<rect key="frame" x="16" y="174" width="154" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="To value:" id="Ycx-oE-aA4">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Kq8-6F-9GK">
|
||||
<rect key="frame" x="16" y="142" width="154" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" title="Only if old value was: " bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="LkB-WQ-9Qd">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="updateCheat:" target="v7q-gT-jHT" id="kNc-cj-bmF"/>
|
||||
</connections>
|
||||
</button>
|
||||
<box verticalHuggingPriority="750" boxType="separator" id="D6k-Pe-23u">
|
||||
<rect key="frame" x="10" y="129" width="274" height="5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
</box>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="r5T-ol-Dod">
|
||||
<rect key="frame" x="16" y="107" width="270" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Import GameShark or GameGenie cheat:" id="0mf-EN-cKc">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="X7K-nJ-alF">
|
||||
<rect key="frame" x="39" y="78" width="233" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" focusRingType="none" placeholderString="Code" drawsBackground="YES" usesSingleLineMode="YES" id="2bz-dT-7Fi">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<allowedInputSourceLocales>
|
||||
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
|
||||
</allowedInputSourceLocales>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<action selector="selectText:" target="KHj-uX-Wbk" id="11z-0U-tMA"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KHj-uX-Wbk">
|
||||
<rect key="frame" x="39" y="47" width="233" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" borderStyle="bezel" focusRingType="none" placeholderString="Description" drawsBackground="YES" usesSingleLineMode="YES" id="50d-va-Cen">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<action selector="performClick:" target="C3V-Ep-bMj" id="kIN-jl-A8d"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="C6E-oI-hDC">
|
||||
<rect key="frame" x="20" y="233" width="252" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" focusRingType="none" placeholderString="Description" drawsBackground="YES" usesSingleLineMode="YES" id="2uR-9N-hBb">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="v7q-gT-jHT" id="zyw-h0-hRP"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" id="C3V-Ep-bMj">
|
||||
<rect key="frame" x="202.5" y="12" width="82" height="23"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="roundTextured" title="Import" bezelStyle="texturedRounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="mMP-KW-YNy">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="importCheat:" target="v7q-gT-jHT" id="lkX-N5-wD1"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" mirrorLayoutDirectionWhenInternationalizing="never" translatesAutoresizingMaskIntoConstraints="NO" id="qHx-1z-daR">
|
||||
<rect key="frame" x="176" y="204" width="96" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" focusRingType="none" drawsBackground="YES" usesSingleLineMode="YES" id="edq-46-JeP" customClass="GBCheatTextFieldCell">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<allowedInputSourceLocales>
|
||||
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
|
||||
</allowedInputSourceLocales>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<action selector="consoleInput:" target="-2" id="sMf-aM-OvR"/>
|
||||
<outlet property="delegate" destination="v7q-gT-jHT" id="79v-33-R1X"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" mirrorLayoutDirectionWhenInternationalizing="never" translatesAutoresizingMaskIntoConstraints="NO" id="N3I-PP-X85">
|
||||
<rect key="frame" x="176" y="174" width="96" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" focusRingType="none" drawsBackground="YES" usesSingleLineMode="YES" id="CV2-D9-WsB" customClass="GBCheatTextFieldCell">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<allowedInputSourceLocales>
|
||||
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
|
||||
</allowedInputSourceLocales>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<action selector="consoleInput:" target="-2" id="SYC-cW-RjC"/>
|
||||
<outlet property="delegate" destination="v7q-gT-jHT" id="P69-nT-oOt"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" mirrorLayoutDirectionWhenInternationalizing="never" translatesAutoresizingMaskIntoConstraints="NO" id="S6O-LB-gSj">
|
||||
<rect key="frame" x="176" y="144" width="96" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" focusRingType="none" drawsBackground="YES" usesSingleLineMode="YES" id="tpM-ys-MEO" customClass="GBCheatTextFieldCell">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<allowedInputSourceLocales>
|
||||
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
|
||||
</allowedInputSourceLocales>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<action selector="consoleInput:" target="-2" id="io6-ha-QNb"/>
|
||||
<outlet property="delegate" destination="v7q-gT-jHT" id="6RH-dg-SL7"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="uFo-ly-Veq">
|
||||
<rect key="frame" x="16" y="204" width="152" height="19"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Change byte at address:" id="xwa-TF-eY1">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
</view>
|
||||
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="6rU-Xg-KHc">
|
||||
<rect key="frame" x="293" y="-1" width="400" height="275"/>
|
||||
<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"/>
|
||||
<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="249"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableColumns>
|
||||
<tableColumn width="32" minWidth="32" maxWidth="1000" id="JNd-HW-LvS">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<buttonCell key="dataCell" type="bevel" bezelStyle="regularSquare" image="NSStopProgressFreestandingTemplate" imagePosition="only" inset="2" id="5xh-hN-jHH">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn width="50" minWidth="40" maxWidth="1000" id="9DZ-oW-Scx">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Enabled">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<buttonCell key="dataCell" type="check" bezelStyle="regularSquare" imagePosition="only" inset="2" id="SdJ-Xw-UAG">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn editable="NO" width="160" minWidth="40" maxWidth="1000" id="4Qa-FQ-QWY">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Description">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Description" id="1hX-Sr-bGz">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
<tableColumn editable="NO" width="144" minWidth="40" maxWidth="1000" id="ACq-gU-K36">
|
||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Action">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||
</tableHeaderCell>
|
||||
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Action" id="8Sq-h9-eV7">
|
||||
<font key="font" metaFont="fixedUser" size="11"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||
</tableColumn>
|
||||
</tableColumns>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="v7q-gT-jHT" id="3ns-bk-yQI"/>
|
||||
<outlet property="delegate" destination="v7q-gT-jHT" id="fVI-Z9-gTJ"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
</clipView>
|
||||
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="3Hg-LL-VqH">
|
||||
<rect key="frame" x="1" y="258" width="398" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="zET-KH-qF4">
|
||||
<rect key="frame" x="224" y="17" width="15" height="102"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<tableHeaderView key="headerView" id="pvX-uJ-qK5">
|
||||
<rect key="frame" x="0.0" y="0.0" width="398" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableHeaderView>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
</view>
|
||||
<point key="canvasLocation" x="254" y="-463"/>
|
||||
</window>
|
||||
<customObject id="v7q-gT-jHT" customClass="GBCheatWindowController">
|
||||
<connections>
|
||||
<outlet property="addressField" destination="qHx-1z-daR" id="FWo-4u-Qse"/>
|
||||
<outlet property="cheatsTable" destination="tA3-8T-bxb" id="n7v-rn-TOg"/>
|
||||
<outlet property="descriptionField" destination="C6E-oI-hDC" id="tc0-gI-FBa"/>
|
||||
<outlet property="document" destination="-2" id="5NX-N4-5Rt"/>
|
||||
<outlet property="importCodeField" destination="X7K-nJ-alF" id="ni0-zH-XDU"/>
|
||||
<outlet property="importDescriptionField" destination="KHj-uX-Wbk" id="W0E-ec-BXk"/>
|
||||
<outlet property="oldValueCheckbox" destination="Kq8-6F-9GK" id="A4a-nz-KMN"/>
|
||||
<outlet property="oldValueField" destination="S6O-LB-gSj" id="fAc-OW-ZC9"/>
|
||||
<outlet property="valueField" destination="N3I-PP-X85" id="0zP-9x-4LQ"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="NSStopProgressFreestandingTemplate" width="14" height="14"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
5
Cocoa/GBCheatTextFieldCell.h
Normal file
5
Cocoa/GBCheatTextFieldCell.h
Normal file
@ -0,0 +1,5 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface GBCheatTextFieldCell : NSTextFieldCell
|
||||
@property bool usesAddressFormat;
|
||||
@end
|
121
Cocoa/GBCheatTextFieldCell.m
Normal file
121
Cocoa/GBCheatTextFieldCell.m
Normal file
@ -0,0 +1,121 @@
|
||||
#import "GBCheatTextFieldCell.h"
|
||||
|
||||
@interface GBCheatTextView : NSTextView
|
||||
@property bool usesAddressFormat;
|
||||
@end
|
||||
|
||||
@implementation GBCheatTextView
|
||||
|
||||
- (bool)_insertText:(NSString *)string replacementRange:(NSRange)range
|
||||
{
|
||||
if (range.location == NSNotFound) {
|
||||
range = self.selectedRange;
|
||||
}
|
||||
|
||||
NSString *new = [self.string stringByReplacingCharactersInRange:range withString:string];
|
||||
if (!self.usesAddressFormat) {
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^(\\$[0-9A-Fa-f]{1,2}|[0-9]{1,3})$" options:0 error:NULL];
|
||||
if ([regex numberOfMatchesInString:new options:0 range:NSMakeRange(0, new.length)]) {
|
||||
[super insertText:string replacementRange:range];
|
||||
return true;
|
||||
}
|
||||
if ([regex numberOfMatchesInString:[@"$" stringByAppendingString:new] options:0 range:NSMakeRange(0, new.length + 1)]) {
|
||||
[super insertText:string replacementRange:range];
|
||||
[super insertText:@"$" replacementRange:NSMakeRange(0, 0)];
|
||||
return true;
|
||||
}
|
||||
if ([new isEqualToString:@"$"] || [string length] == 0) {
|
||||
self.string = @"$00";
|
||||
self.selectedRange = NSMakeRange(1, 2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^(\\$[0-9A-Fa-f]{1,3}:)?\\$[0-9a-fA-F]{1,4}$" options:0 error:NULL];
|
||||
if ([regex numberOfMatchesInString:new options:0 range:NSMakeRange(0, new.length)]) {
|
||||
[super insertText:string replacementRange:range];
|
||||
return true;
|
||||
}
|
||||
if ([string length] == 0) {
|
||||
NSUInteger index = [new rangeOfString:@":"].location;
|
||||
if (index != NSNotFound) {
|
||||
if (range.location > index) {
|
||||
self.string = [[new componentsSeparatedByString:@":"] firstObject];
|
||||
self.selectedRange = NSMakeRange(self.string.length, 0);
|
||||
return true;
|
||||
}
|
||||
self.string = [[new componentsSeparatedByString:@":"] lastObject];
|
||||
self.selectedRange = NSMakeRange(0, 0);
|
||||
return true;
|
||||
}
|
||||
else if ([[self.string substringWithRange:range] isEqualToString:@":"]) {
|
||||
self.string = [[self.string componentsSeparatedByString:@":"] lastObject];
|
||||
self.selectedRange = NSMakeRange(0, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ([new isEqualToString:@"$"] || [string length] == 0) {
|
||||
self.string = @"$0000";
|
||||
self.selectedRange = NSMakeRange(1, 4);
|
||||
return true;
|
||||
}
|
||||
if (([string isEqualToString:@"$"] || [string isEqualToString:@":"]) && range.length == 0 && range.location == 0) {
|
||||
if ([self _insertText:@"$00:" replacementRange:range]) {
|
||||
self.selectedRange = NSMakeRange(1, 2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ([string isEqualToString:@":"] && range.length + range.location == self.string.length) {
|
||||
if ([self _insertText:@":$0" replacementRange:range]) {
|
||||
self.selectedRange = NSMakeRange(self.string.length - 2, 2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ([string isEqualToString:@"$"]) {
|
||||
if ([self _insertText:@"$0" replacementRange:range]) {
|
||||
self.selectedRange = NSMakeRange(range.location + 1, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
- (NSUndoManager *)undoManager
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
|
||||
{
|
||||
if (![self _insertText:string replacementRange:replacementRange]) {
|
||||
NSBeep();
|
||||
}
|
||||
}
|
||||
|
||||
/* Private API, don't tell the police! */
|
||||
- (void)_userReplaceRange:(NSRange)range withString:(NSString *)string
|
||||
{
|
||||
[self insertText:string replacementRange:range];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation GBCheatTextFieldCell
|
||||
{
|
||||
bool _drawing, _editing;
|
||||
GBCheatTextView *_fieldEditor;
|
||||
}
|
||||
|
||||
- (NSTextView *)fieldEditorForView:(NSView *)controlView
|
||||
{
|
||||
if (_fieldEditor) {
|
||||
_fieldEditor.usesAddressFormat = self.usesAddressFormat;
|
||||
return _fieldEditor;
|
||||
}
|
||||
_fieldEditor = [[GBCheatTextView alloc] initWithFrame:controlView.frame];
|
||||
_fieldEditor.fieldEditor = YES;
|
||||
_fieldEditor.usesAddressFormat = self.usesAddressFormat;
|
||||
return _fieldEditor;
|
||||
}
|
||||
@end
|
17
Cocoa/GBCheatWindowController.h
Normal file
17
Cocoa/GBCheatWindowController.h
Normal file
@ -0,0 +1,17 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#import "Document.h"
|
||||
|
||||
@interface GBCheatWindowController : NSObject <NSTableViewDelegate, NSTableViewDataSource, NSTextFieldDelegate>
|
||||
@property (weak) IBOutlet NSTableView *cheatsTable;
|
||||
@property (weak) IBOutlet NSTextField *addressField;
|
||||
@property (weak) IBOutlet NSTextField *valueField;
|
||||
@property (weak) IBOutlet NSTextField *oldValueField;
|
||||
@property (weak) IBOutlet NSButton *oldValueCheckbox;
|
||||
@property (weak) IBOutlet NSTextField *descriptionField;
|
||||
@property (weak) IBOutlet NSTextField *importCodeField;
|
||||
@property (weak) IBOutlet NSTextField *importDescriptionField;
|
||||
@property (weak) IBOutlet Document *document;
|
||||
|
||||
@end
|
||||
|
234
Cocoa/GBCheatWindowController.m
Normal file
234
Cocoa/GBCheatWindowController.m
Normal file
@ -0,0 +1,234 @@
|
||||
#import "GBCheatWindowController.h"
|
||||
#import "GBWarningPopover.h"
|
||||
#import "GBCheatTextFieldCell.h"
|
||||
|
||||
@implementation GBCheatWindowController
|
||||
|
||||
+ (NSString *)addressStringFromCheat:(const GB_cheat_t *)cheat
|
||||
{
|
||||
if (cheat->bank != GB_CHEAT_ANY_BANK) {
|
||||
return [NSString stringWithFormat:@"$%x:$%04x", cheat->bank, cheat->address];
|
||||
}
|
||||
return [NSString stringWithFormat:@"$%04x", cheat->address];
|
||||
}
|
||||
|
||||
+ (NSString *)actionDescriptionForCheat:(const GB_cheat_t *)cheat
|
||||
{
|
||||
if (cheat->use_old_value) {
|
||||
return [NSString stringWithFormat:@"[%@]($%02x) = $%02x", [self addressStringFromCheat:cheat], cheat->old_value, cheat->value];
|
||||
}
|
||||
return [NSString stringWithFormat:@"[%@] = $%02x", [self addressStringFromCheat:cheat], cheat->value];
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
|
||||
{
|
||||
GB_gameboy_t *gb = self.document.gameboy;
|
||||
if (!gb) return 0;
|
||||
size_t cheatCount;
|
||||
GB_get_cheats(gb, &cheatCount);
|
||||
return cheatCount + 1;
|
||||
}
|
||||
|
||||
- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
{
|
||||
GB_gameboy_t *gb = self.document.gameboy;
|
||||
if (!gb) return nil;
|
||||
size_t cheatCount;
|
||||
GB_get_cheats(gb, &cheatCount);
|
||||
NSUInteger columnIndex = [[tableView tableColumns] indexOfObject:tableColumn];
|
||||
if (row >= cheatCount && columnIndex == 0) {
|
||||
return [[NSCell alloc] init];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (nullable id)tableView:(NSTableView *)tableView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
{
|
||||
size_t cheatCount;
|
||||
GB_gameboy_t *gb = self.document.gameboy;
|
||||
if (!gb) return nil;
|
||||
const GB_cheat_t *const *cheats = GB_get_cheats(gb, &cheatCount);
|
||||
NSUInteger columnIndex = [[tableView tableColumns] indexOfObject:tableColumn];
|
||||
if (row >= cheatCount) {
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return @(YES);
|
||||
|
||||
case 1:
|
||||
return @NO;
|
||||
|
||||
case 2:
|
||||
return @"Add Cheat...";
|
||||
|
||||
case 3:
|
||||
return @"";
|
||||
}
|
||||
}
|
||||
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
return @(NO);
|
||||
|
||||
case 1:
|
||||
return @(cheats[row]->enabled);
|
||||
|
||||
case 2:
|
||||
return @(cheats[row]->description);
|
||||
|
||||
case 3:
|
||||
return [GBCheatWindowController actionDescriptionForCheat:cheats[row]];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (IBAction)importCheat:(id)sender
|
||||
{
|
||||
GB_gameboy_t *gb = self.document.gameboy;
|
||||
if (!gb) return;
|
||||
|
||||
[self.document performAtomicBlock:^{
|
||||
if (GB_import_cheat(gb,
|
||||
self.importCodeField.stringValue.UTF8String,
|
||||
self.importDescriptionField.stringValue.UTF8String,
|
||||
true)) {
|
||||
self.importCodeField.stringValue = @"";
|
||||
self.importDescriptionField.stringValue = @"";
|
||||
[self.cheatsTable reloadData];
|
||||
[self tableViewSelectionDidChange:nil];
|
||||
}
|
||||
else {
|
||||
NSBeep();
|
||||
[GBWarningPopover popoverWithContents:@"This code is not a valid GameShark or GameGenie code" onView:self.importCodeField];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
|
||||
{
|
||||
GB_gameboy_t *gb = self.document.gameboy;
|
||||
if (!gb) return;
|
||||
size_t cheatCount;
|
||||
const GB_cheat_t *const *cheats = GB_get_cheats(gb, &cheatCount);
|
||||
NSUInteger columnIndex = [[tableView tableColumns] indexOfObject:tableColumn];
|
||||
[self.document performAtomicBlock:^{
|
||||
if (columnIndex == 1) {
|
||||
if (row >= cheatCount) {
|
||||
GB_add_cheat(gb, "New Cheat", 0, 0, 0, 0, false, true);
|
||||
}
|
||||
else {
|
||||
GB_update_cheat(gb, cheats[row], cheats[row]->description, cheats[row]->address, cheats[row]->bank, cheats[row]->value, cheats[row]->old_value, cheats[row]->use_old_value, !cheats[row]->enabled);
|
||||
}
|
||||
}
|
||||
else if (row < cheatCount) {
|
||||
GB_remove_cheat(gb, cheats[row]);
|
||||
}
|
||||
}];
|
||||
[self.cheatsTable reloadData];
|
||||
[self tableViewSelectionDidChange:nil];
|
||||
}
|
||||
|
||||
- (void)tableViewSelectionDidChange:(NSNotification *)notification
|
||||
{
|
||||
GB_gameboy_t *gb = self.document.gameboy;
|
||||
if (!gb) return;
|
||||
|
||||
size_t cheatCount;
|
||||
const GB_cheat_t *const *cheats = GB_get_cheats(gb, &cheatCount);
|
||||
unsigned row = self.cheatsTable.selectedRow;
|
||||
const GB_cheat_t *cheat = NULL;
|
||||
if (row >= cheatCount) {
|
||||
static const GB_cheat_t template = {
|
||||
.address = 0,
|
||||
.bank = 0,
|
||||
.value = 0,
|
||||
.old_value = 0,
|
||||
.use_old_value = false,
|
||||
.enabled = false,
|
||||
.description = "New Cheat",
|
||||
};
|
||||
cheat = &template;
|
||||
}
|
||||
else {
|
||||
cheat = cheats[row];
|
||||
}
|
||||
|
||||
self.addressField.stringValue = [GBCheatWindowController addressStringFromCheat:cheat];
|
||||
self.valueField.stringValue = [NSString stringWithFormat:@"$%02x", cheat->value];
|
||||
self.oldValueField.stringValue = [NSString stringWithFormat:@"$%02x", cheat->old_value];
|
||||
self.oldValueCheckbox.state = cheat->use_old_value;
|
||||
self.descriptionField.stringValue = @(cheat->description);
|
||||
}
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
[self tableViewSelectionDidChange:nil];
|
||||
((GBCheatTextFieldCell *)self.addressField.cell).usesAddressFormat = true;
|
||||
}
|
||||
|
||||
- (void)controlTextDidChange:(NSNotification *)obj
|
||||
{
|
||||
[self updateCheat:nil];
|
||||
}
|
||||
|
||||
- (IBAction)updateCheat:(id)sender
|
||||
{
|
||||
GB_gameboy_t *gb = self.document.gameboy;
|
||||
if (!gb) return;
|
||||
|
||||
uint16_t address = 0;
|
||||
uint16_t bank = GB_CHEAT_ANY_BANK;
|
||||
if ([self.addressField.stringValue rangeOfString:@":"].location != NSNotFound) {
|
||||
sscanf(self.addressField.stringValue.UTF8String, "$%hx:$%hx", &bank, &address);
|
||||
}
|
||||
else {
|
||||
sscanf(self.addressField.stringValue.UTF8String, "$%hx", &address);
|
||||
}
|
||||
|
||||
uint8_t value = 0;
|
||||
if ([self.valueField.stringValue characterAtIndex:0] == '$') {
|
||||
sscanf(self.valueField.stringValue.UTF8String, "$%02hhx", &value);
|
||||
}
|
||||
else {
|
||||
sscanf(self.valueField.stringValue.UTF8String, "%hhd", &value);
|
||||
}
|
||||
|
||||
uint8_t oldValue = 0;
|
||||
if ([self.oldValueField.stringValue characterAtIndex:0] == '$') {
|
||||
sscanf(self.oldValueField.stringValue.UTF8String, "$%02hhx", &oldValue);
|
||||
}
|
||||
else {
|
||||
sscanf(self.oldValueField.stringValue.UTF8String, "%hhd", &oldValue);
|
||||
}
|
||||
|
||||
size_t cheatCount;
|
||||
const GB_cheat_t *const *cheats = GB_get_cheats(gb, &cheatCount);
|
||||
unsigned row = self.cheatsTable.selectedRow;
|
||||
|
||||
[self.document performAtomicBlock:^{
|
||||
if (row >= cheatCount) {
|
||||
GB_add_cheat(gb,
|
||||
self.descriptionField.stringValue.UTF8String,
|
||||
address,
|
||||
bank,
|
||||
value,
|
||||
oldValue,
|
||||
self.oldValueCheckbox.state,
|
||||
false);
|
||||
}
|
||||
else {
|
||||
GB_update_cheat(gb,
|
||||
cheats[row],
|
||||
self.descriptionField.stringValue.UTF8String,
|
||||
address,
|
||||
bank,
|
||||
value,
|
||||
oldValue,
|
||||
self.oldValueCheckbox.state,
|
||||
cheats[row]->enabled);
|
||||
}
|
||||
}];
|
||||
[self.cheatsTable reloadData];
|
||||
}
|
||||
|
||||
@end
|
@ -3,7 +3,7 @@
|
||||
@implementation GBImageCell
|
||||
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
|
||||
{
|
||||
CGContextRef context = [[NSGraphicsContext currentContext] CGContext];
|
||||
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
|
||||
CGContextSetInterpolationQuality(context, kCGInterpolationNone);
|
||||
[super drawWithFrame:cellFrame inView:controlView];
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
}
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
{
|
||||
CGContextRef context = [[NSGraphicsContext currentContext] CGContext];
|
||||
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
|
||||
CGContextSetInterpolationQuality(context, kCGInterpolationNone);
|
||||
[super drawRect:dirtyRect];
|
||||
CGFloat y_ratio = self.frame.size.height / self.image.size.height;
|
||||
|
6
Cocoa/GBOptionalVisualEffectView.h
Normal file
6
Cocoa/GBOptionalVisualEffectView.h
Normal file
@ -0,0 +1,6 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
/* Fake interface so the compiler assumes it conforms to NSVisualEffectView */
|
||||
@interface GBOptionalVisualEffectView : NSVisualEffectView
|
||||
|
||||
@end
|
18
Cocoa/GBOptionalVisualEffectView.m
Normal file
18
Cocoa/GBOptionalVisualEffectView.m
Normal file
@ -0,0 +1,18 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface GBOptionalVisualEffectView : NSView
|
||||
|
||||
@end
|
||||
|
||||
@implementation GBOptionalVisualEffectView
|
||||
|
||||
+ (instancetype)allocWithZone:(struct _NSZone *)zone
|
||||
{
|
||||
Class NSVisualEffectView = NSClassFromString(@"NSVisualEffectView");
|
||||
if (NSVisualEffectView) {
|
||||
return (id)[NSVisualEffectView alloc];
|
||||
}
|
||||
return [super allocWithZone:zone];
|
||||
}
|
||||
|
||||
@end
|
@ -345,6 +345,24 @@
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Cheats" id="8ld-Ad-nvc">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Cheats" id="Ucc-Hm-TVA">
|
||||
<items>
|
||||
<menuItem title="Enable Cheats" keyEquivalent="C" id="vtx-LG-v6y">
|
||||
<connections>
|
||||
<action selector="toggleCheats:" target="-1" id="gsw-UY-fhu"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Show Cheats" id="LZV-QK-YXi">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="showCheats:" target="-1" id="tfr-qM-q8X"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Connectivity" id="IcW-ZC-4wb">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Connectivity" id="BDM-Cv-BOm">
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "gb.h"
|
||||
#include "cheats.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
static inline uint8_t hash_addr(uint16_t addr)
|
||||
{
|
||||
@ -30,6 +31,8 @@ static uint16_t bank_for_addr(GB_gameboy_t *gb, uint16_t addr)
|
||||
|
||||
void GB_apply_cheat(GB_gameboy_t *gb, uint16_t address, uint8_t *value)
|
||||
{
|
||||
if (!gb->cheat_enabled) return;
|
||||
if (!gb->boot_rom_finished) return;
|
||||
const GB_cheat_hash_t *hash = gb->cheat_hash[hash_addr(address)];
|
||||
if (hash) {
|
||||
for (unsigned i = 0; i < hash->size; i++) {
|
||||
@ -44,6 +47,16 @@ void GB_apply_cheat(GB_gameboy_t *gb, uint16_t address, uint8_t *value)
|
||||
}
|
||||
}
|
||||
|
||||
bool GB_cheats_enabled(GB_gameboy_t *gb)
|
||||
{
|
||||
return gb->cheat_enabled;
|
||||
}
|
||||
|
||||
void GB_set_cheats_enabled(GB_gameboy_t *gb, bool enabled)
|
||||
{
|
||||
gb->cheat_enabled = enabled;
|
||||
}
|
||||
|
||||
void GB_add_cheat(GB_gameboy_t *gb, const char *description, uint16_t address, uint16_t bank, uint8_t value, uint8_t old_value, bool use_old_value, bool enabled)
|
||||
{
|
||||
GB_cheat_t *cheat = malloc(sizeof(*cheat));
|
||||
@ -66,7 +79,7 @@ void GB_add_cheat(GB_gameboy_t *gb, const char *description, uint16_t address, u
|
||||
}
|
||||
else {
|
||||
(*hash)->size++;
|
||||
*hash = malloc(sizeof(GB_cheat_hash_t) + sizeof(cheat) * (*hash)->size);
|
||||
*hash = realloc(*hash, sizeof(GB_cheat_hash_t) + sizeof(cheat) * (*hash)->size);
|
||||
(*hash)->cheats[(*hash)->size - 1] = cheat;
|
||||
}
|
||||
}
|
||||
@ -171,3 +184,57 @@ bool GB_import_cheat(GB_gameboy_t *gb, const char *cheat, const char *descriptio
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GB_update_cheat(GB_gameboy_t *gb, const GB_cheat_t *_cheat, const char *description, uint16_t address, uint16_t bank, uint8_t value, uint8_t old_value, bool use_old_value, bool enabled)
|
||||
{
|
||||
GB_cheat_t *cheat = NULL;
|
||||
for (unsigned i = 0; i < gb->cheat_count; i++) {
|
||||
if (gb->cheats[i] == _cheat) {
|
||||
cheat = gb->cheats[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(cheat);
|
||||
|
||||
if (cheat->address != address) {
|
||||
/* Remove from old bucket */
|
||||
GB_cheat_hash_t **hash = &gb->cheat_hash[hash_addr(cheat->address)];
|
||||
for (unsigned i = 0; i < (*hash)->size; i++) {
|
||||
if ((*hash)->cheats[i] == cheat) {
|
||||
(*hash)->cheats[i] = (*hash)->cheats[(*hash)->size--];
|
||||
if ((*hash)->size == 0) {
|
||||
free(*hash);
|
||||
*hash = NULL;
|
||||
}
|
||||
else {
|
||||
*hash = malloc(sizeof(GB_cheat_hash_t) + sizeof(cheat) * (*hash)->size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
cheat->address = address;
|
||||
|
||||
/* Add to new bucket */
|
||||
hash = &gb->cheat_hash[hash_addr(address)];
|
||||
if (!*hash) {
|
||||
*hash = malloc(sizeof(GB_cheat_hash_t) + sizeof(cheat));
|
||||
(*hash)->size = 1;
|
||||
(*hash)->cheats[0] = cheat;
|
||||
}
|
||||
else {
|
||||
(*hash)->size++;
|
||||
*hash = malloc(sizeof(GB_cheat_hash_t) + sizeof(cheat) * (*hash)->size);
|
||||
(*hash)->cheats[(*hash)->size - 1] = cheat;
|
||||
}
|
||||
}
|
||||
cheat->bank = bank;
|
||||
cheat->value = value;
|
||||
cheat->old_value = old_value;
|
||||
cheat->use_old_value = use_old_value;
|
||||
cheat->enabled = enabled;
|
||||
if (description != cheat->description) {
|
||||
strncpy(cheat->description, description, sizeof(cheat->description));
|
||||
cheat->description[sizeof(cheat->description) - 1] = 0;
|
||||
}
|
||||
}
|
||||
|
@ -7,9 +7,12 @@
|
||||
typedef struct GB_cheat_s GB_cheat_t;
|
||||
|
||||
void GB_add_cheat(GB_gameboy_t *gb, const char *description, uint16_t address, uint16_t bank, uint8_t value, uint8_t old_value, bool use_old_value, bool enabled);
|
||||
void GB_update_cheat(GB_gameboy_t *gb, const GB_cheat_t *cheat, const char *description, uint16_t address, uint16_t bank, uint8_t value, uint8_t old_value, bool use_old_value, bool enabled);
|
||||
bool GB_import_cheat(GB_gameboy_t *gb, const char *cheat, const char *description, bool enabled);
|
||||
const GB_cheat_t *const *GB_get_cheats(GB_gameboy_t *gb, size_t *size);
|
||||
void GB_remove_cheat(GB_gameboy_t *gb, const GB_cheat_t *cheat);
|
||||
bool GB_cheats_enabled(GB_gameboy_t *gb);
|
||||
void GB_set_cheats_enabled(GB_gameboy_t *gb, bool enabled);
|
||||
|
||||
#ifdef GB_INTERNAL
|
||||
void GB_apply_cheat(GB_gameboy_t *gb, uint16_t address, uint8_t *value);
|
||||
|
@ -647,6 +647,7 @@ struct GB_gameboy_internal_s {
|
||||
double sgb_intro_sweep_previous_sample;
|
||||
|
||||
/* Cheats */
|
||||
bool cheat_enabled;
|
||||
size_t cheat_count;
|
||||
GB_cheat_t **cheats;
|
||||
GB_cheat_hash_t *cheat_hash[256];
|
||||
|
2
Makefile
2
Makefile
@ -88,7 +88,7 @@ OPEN_DIALOG = OpenDialog/cocoa.m
|
||||
endif
|
||||
|
||||
|
||||
CFLAGS += -Werror -Wall -Wno-unused-result -Wno-strict-aliasing -Wno-unknown-warning -Wno-unknown-warning-option -Wno-multichar -Wno-int-in-bool-context -std=gnu11 -D_GNU_SOURCE -DVERSION="$(VERSION)" -I. -D_USE_MATH_DEFINES
|
||||
CFLAGS += -Werror -Wall -Wno-nonnull -Wno-unused-result -Wno-strict-aliasing -Wno-unknown-warning -Wno-unknown-warning-option -Wno-multichar -Wno-int-in-bool-context -std=gnu11 -D_GNU_SOURCE -DVERSION="$(VERSION)" -I. -D_USE_MATH_DEFINES
|
||||
ifeq (,$(PKG_CONFIG))
|
||||
SDL_CFLAGS := $(shell sdl2-config --cflags)
|
||||
SDL_LDFLAGS := $(shell sdl2-config --libs)
|
||||
|
Loading…
Reference in New Issue
Block a user