mirror of
https://github.com/mauiaaron/apple2.git
synced 2024-09-27 09:56:08 +00:00
Initials changes
Added NSToolbar and French Localization
This commit is contained in:
parent
40129d9a14
commit
f4258ade45
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.deadc0de.Apple2Mac</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
@ -21,7 +21,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.9.2</string>
|
||||
<string>0.9.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
9
Apple2Mac/Apple2Mac/Apple2Mac-Prefix.pch
Normal file
9
Apple2Mac/Apple2Mac/Apple2Mac-Prefix.pch
Normal file
@ -0,0 +1,9 @@
|
||||
//
|
||||
// Prefix header
|
||||
//
|
||||
// The contents of this file are implicitly included at the beginning of every source file.
|
||||
//
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6245" systemVersion="13F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<deployment version="1060" identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6245"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||
@ -88,7 +88,7 @@
|
||||
<rect key="contentRect" x="196" y="240" width="480" height="270"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1178"/>
|
||||
<view key="contentView" id="6V4-fW-Bkm">
|
||||
<rect key="frame" x="7" y="11" width="480" height="270"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
</window>
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="8191" systemVersion="14F27" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<deployment version="1060" identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="8191"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||
@ -23,27 +23,6 @@
|
||||
<action selector="orderFrontStandardAboutPanel:" target="-2" id="142"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Reboot Emulator" id="FjO-UG-hG2" userLabel="Menu Item - Reboot">
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
CA
|
||||
</string>
|
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="reboot:" target="M8b-ga-iOS" id="AbH-Xq-1VZ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Disks" id="IU3-Bt-BuK" userLabel="Menu Item - Disks">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Disks" systemMenu="help" id="Wh3-tN-xkr">
|
||||
<items>
|
||||
<menuItem title="Insert..." keyEquivalent="D" id="Oj8-qO-A80" userLabel="Menu Item - Insert">
|
||||
<connections>
|
||||
<action selector="showDisksWindow:" target="M8b-ga-iOS" id="GVw-D1-gi0"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="236">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
@ -52,21 +31,6 @@ CA
|
||||
<action selector="showPreferences:" target="M8b-ga-iOS" id="oDD-g4-QEJ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Toggle Full Screen" keyEquivalent="F" id="rP9-cs-9dM">
|
||||
<connections>
|
||||
<action selector="toggleFullScreen:" target="M8b-ga-iOS" id="Xan-eQ-CRM"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Toggle CPU Speed" keyEquivalent="S" id="b9q-zr-oNh">
|
||||
<connections>
|
||||
<action selector="toggleCPUSpeed:" target="M8b-ga-iOS" id="fA3-dJ-wtg"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Pause Emulation" keyEquivalent="X" id="r9g-Ro-UwW">
|
||||
<connections>
|
||||
<action selector="togglePause:" target="M8b-ga-iOS" id="c65-mm-bIj"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="143">
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</menuItem>
|
||||
@ -103,6 +67,299 @@ CA
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="File" id="4dZ-4f-42V">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="File" id="ma8-CB-dnr">
|
||||
<items>
|
||||
<menuItem title="Reboot Emulator" id="Xr5-Y9-tRL" userLabel="Menu Item - Reboot">
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
CA
|
||||
</string>
|
||||
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="reboot:" target="M8b-ga-iOS" id="XtR-At-SSS"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Toggle CPU Speed" keyEquivalent="S" id="pJl-yR-ULm">
|
||||
<connections>
|
||||
<action selector="toggleCPUSpeed:" target="M8b-ga-iOS" id="JUd-Uf-yyX"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Pause Emulation" keyEquivalent="X" id="OKW-bt-a58">
|
||||
<connections>
|
||||
<action selector="togglePause:" target="M8b-ga-iOS" id="KLo-hL-5zu"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="Bp7-3g-GDj"/>
|
||||
<menuItem title="Disks" id="rp2-u6-d0B" userLabel="Menu Item - Disks">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Disks" systemMenu="help" id="8XK-7x-7hh">
|
||||
<items>
|
||||
<menuItem title="Insert..." keyEquivalent="D" id="JhN-ZL-f2O" userLabel="Menu Item - Insert">
|
||||
<connections>
|
||||
<action selector="showDisksWindow:" target="M8b-ga-iOS" id="EEd-WE-b9g"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="Mec-fL-Gcp"/>
|
||||
<menuItem title="Page Setup…" enabled="NO" keyEquivalent="P" id="0HU-OV-39A">
|
||||
<connections>
|
||||
<action selector="runPageLayout:" target="-1" id="GVI-mL-WRX"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Print…" enabled="NO" keyEquivalent="p" id="dXC-8t-bQ7">
|
||||
<connections>
|
||||
<action selector="print:" target="-1" id="MkR-UN-gGO"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Edit" id="ZKa-Nk-KCW">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Edit" id="WCv-04-9tQ">
|
||||
<items>
|
||||
<menuItem title="Undo" enabled="NO" keyEquivalent="z" id="7ji-O5-1oP">
|
||||
<connections>
|
||||
<action selector="undo:" target="-1" id="nTg-8e-qqX"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Redo" enabled="NO" keyEquivalent="Z" id="jYN-aO-Gse">
|
||||
<connections>
|
||||
<action selector="redo:" target="-1" id="3cC-fV-e1H"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="cRv-NN-CM3"/>
|
||||
<menuItem title="Cut" keyEquivalent="x" id="B9f-O6-lco">
|
||||
<connections>
|
||||
<action selector="cut:" target="-1" id="cEF-Mr-gEI"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Copy" keyEquivalent="c" id="BRV-TN-Pzv">
|
||||
<connections>
|
||||
<action selector="copy:" target="-1" id="xcu-og-fVt"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste" keyEquivalent="v" id="geM-qO-aZ2">
|
||||
<connections>
|
||||
<action selector="paste:" target="-1" id="uDP-lX-2QO"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Paste and Match Style" enabled="NO" keyEquivalent="V" id="gUM-x3-iEs">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="pasteAsPlainText:" target="-1" id="62M-Kk-7W0"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Delete" id="i2b-GO-OI0">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="delete:" target="-1" id="Ofc-Df-mrY"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Select All" keyEquivalent="a" id="l6c-o9-Lcb">
|
||||
<connections>
|
||||
<action selector="selectAll:" target="-1" id="hfq-sH-Hrd"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="gPI-YZ-Ej7"/>
|
||||
<menuItem title="Find" id="wpu-4I-0bh">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Find" id="Hm4-5s-n7i">
|
||||
<items>
|
||||
<menuItem title="Find…" tag="1" keyEquivalent="f" id="xx4-kU-rZA">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="-1" id="QjO-TQ-NTO"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="Mzr-n7-gii">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="-1" id="uJq-AO-zpb"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="EcB-rH-6Fn">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="-1" id="7oO-Bh-siN"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="cYe-Hg-XZ2">
|
||||
<connections>
|
||||
<action selector="performFindPanelAction:" target="-1" id="NLQ-EP-xeT"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Jump to Selection" keyEquivalent="j" id="VRT-xH-o4f">
|
||||
<connections>
|
||||
<action selector="centerSelectionInVisibleArea:" target="-1" id="hvL-8z-0XQ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Spelling and Grammar" id="lBL-48-NL8">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Spelling" id="7rr-yF-apD">
|
||||
<items>
|
||||
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="TxR-Iv-fxN">
|
||||
<connections>
|
||||
<action selector="showGuessPanel:" target="-1" id="Fi5-eF-xtd"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check Document Now" keyEquivalent=";" id="1NC-db-BRz">
|
||||
<connections>
|
||||
<action selector="checkSpelling:" target="-1" id="4Cb-VT-uRv"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="1VO-3p-hKr"/>
|
||||
<menuItem title="Check Spelling While Typing" id="R7T-Py-IUl">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleContinuousSpellChecking:" target="-1" id="fRX-Xn-i0s"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Check Grammar With Spelling" id="A2e-bf-a76">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleGrammarChecking:" target="-1" id="PYu-Cs-Nvn"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Correct Spelling Automatically" id="Z8h-ou-V7a">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="keB-gX-m3T"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Substitutions" id="jb7-2B-6xa">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Substitutions" id="iMe-LJ-g9B">
|
||||
<items>
|
||||
<menuItem title="Show Substitutions" id="Fa7-uJ-Naj">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="PoI-1s-Hjv"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="lQF-eK-0p9"/>
|
||||
<menuItem title="Smart Copy/Paste" id="KS0-Pe-biv">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleSmartInsertDelete:" target="-1" id="Rrf-F9-auF"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Quotes" id="uXJ-Bm-7aA">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="pZw-O8-1Q6"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Dashes" id="8KL-lT-U1f">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="EHC-04-hyV"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Smart Links" id="hq9-VC-W6c">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticLinkDetection:" target="-1" id="3BN-Bo-i7K"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Data Detectors" id="qeO-vj-7ge">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticDataDetection:" target="-1" id="fAF-LU-W4B"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Text Replacement" id="vGB-cx-gYU">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="toggleAutomaticTextReplacement:" target="-1" id="sQF-gF-l9g"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Transformations" id="898-0g-Oio">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Transformations" id="7Zl-6t-TqO">
|
||||
<items>
|
||||
<menuItem title="Make Upper Case" id="6C2-i8-KVq">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="uppercaseWord:" target="-1" id="pjO-OZ-Lwk"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Make Lower Case" id="ZZP-5z-YrA">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="lowercaseWord:" target="-1" id="4ZN-4K-BgR"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Capitalize" id="MIg-Ae-S5l">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="capitalizeWord:" target="-1" id="wNF-kk-YaV"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Speech" id="phA-NA-yWC">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Speech" id="voe-xv-aqn">
|
||||
<items>
|
||||
<menuItem title="Start Speaking" id="zfA-gc-OcH">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="startSpeaking:" target="-1" id="kdt-Em-BHj"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Stop Speaking" id="FHw-p7-luT">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="stopSpeaking:" target="-1" id="cAo-hP-Ubn"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Window" id="TP0-Ag-yPc">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Window" systemMenu="window" id="v0D-uE-mdE">
|
||||
<items>
|
||||
<menuItem title="Minimize" keyEquivalent="m" id="dq0-ap-hiO">
|
||||
<connections>
|
||||
<action selector="performMiniaturize:" target="-1" id="wuW-Cq-NVB"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Zoom" id="Kw3-wb-a0i">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="performZoom:" target="-1" id="Rab-bb-j9C"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Toggle Full Screen" keyEquivalent="F" id="Lem-uE-El9">
|
||||
<connections>
|
||||
<action selector="toggleFullScreen:" target="M8b-ga-iOS" id="0fX-bE-3MN"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="yFd-C5-chc"/>
|
||||
<menuItem title="Bring All to Front" id="Kwp-da-LVP">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="arrangeInFront:" target="-1" id="iee-gu-gae"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Help" id="490">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Help" systemMenu="help" id="491">
|
||||
@ -118,21 +375,56 @@ CA
|
||||
</items>
|
||||
</menu>
|
||||
<window title="Apple2Mac" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="371" userLabel="Window - Apple2Mac" customClass="EmulatorWindow">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" unifiedTitleAndToolbar="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="200" y="200" width="568" height="384"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1178"/>
|
||||
<view key="contentView" id="372" customClass="EmulatorGLView">
|
||||
<rect key="frame" x="0.0" y="-1" width="568" height="384"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="568" height="384"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</view>
|
||||
<point key="canvasLocation" x="-315" y="-1328"/>
|
||||
<toolbar key="toolbar" implicitIdentifier="8323D01A-4ECF-4973-8DC6-3BB0A67F10FD" allowsUserCustomization="NO" displayMode="iconAndLabel" sizeMode="small" id="gXM-1s-f0F">
|
||||
<allowedToolbarItems>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarShowColorsItem" id="oed-am-Cfb"/>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarPrintItem" id="sk6-41-C3g"/>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarSpaceItem" id="AoN-cv-QQ2"/>
|
||||
<toolbarItem implicitItemIdentifier="CBD2C3ED-B0AA-40F1-818F-B61B04F93E7F" label="Preferences" paletteLabel="Preferences" tag="-1" image="NSPreferencesGeneral" id="85b-WO-tks"/>
|
||||
<toolbarItem implicitItemIdentifier="1AF00BE2-1806-4F36-AA9B-EDCD8587D441" label="Reboot" paletteLabel="Reboot" tag="-1" image="NSRefreshTemplate" id="hOg-ec-Okz"/>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="372-hX-Xt1"/>
|
||||
<toolbarItem implicitItemIdentifier="ED8F052E-C9AE-42F6-BA6D-2A675E8390E5" label="Disks" paletteLabel="Disks" tag="-1" image="NSFolderSmart" id="jHk-qj-bmw"/>
|
||||
<toolbarItem implicitItemIdentifier="F7BDADA8-832A-4E26-8BA2-01F9393AB115" label="CPU" paletteLabel="CPU" id="Oc9-Aa-A6p">
|
||||
<nil key="toolTip"/>
|
||||
<size key="minSize" width="28" height="30"/>
|
||||
<size key="maxSize" width="28" height="30"/>
|
||||
<slider key="view" horizontalHuggingPriority="750" verticalHuggingPriority="750" id="fq8-jI-RmM">
|
||||
<rect key="frame" x="2" y="14" width="28" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<sliderCell key="cell" alignment="left" maxValue="100" allowsTickMarkValuesOnly="YES" sliderType="circular" id="wXl-eq-6Wx"/>
|
||||
</slider>
|
||||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="B1B89899-E7C4-4A6A-9B19-B29D3C7FB7CC" label="Pause" paletteLabel="Pause" tag="-1" image="Stop" id="hkP-Yj-QZG"/>
|
||||
<toolbarItem implicitItemIdentifier="3358D7A0-4F67-4503-ADD8-6E900BB291CC" label="Toolbar Item" paletteLabel="Toolbar Item" tag="-1" image="NSUser" id="JbN-Qp-xsc"/>
|
||||
<toolbarItem implicitItemIdentifier="E796EDE5-7BB6-4CBB-AC6B-17DA3FC696C9" label="FullScreen" paletteLabel="FullScreen" tag="-1" image="NSExitFullScreenTemplate" id="Ahr-ZD-7wt"/>
|
||||
</allowedToolbarItems>
|
||||
<defaultToolbarItems>
|
||||
<toolbarItem reference="hOg-ec-Okz"/>
|
||||
<toolbarItem reference="hkP-Yj-QZG"/>
|
||||
<toolbarItem reference="Ahr-ZD-7wt"/>
|
||||
<toolbarItem reference="AoN-cv-QQ2"/>
|
||||
<toolbarItem reference="Oc9-Aa-A6p"/>
|
||||
<toolbarItem reference="AoN-cv-QQ2"/>
|
||||
<toolbarItem reference="jHk-qj-bmw"/>
|
||||
<toolbarItem reference="372-hX-Xt1"/>
|
||||
<toolbarItem reference="sk6-41-C3g"/>
|
||||
<toolbarItem reference="85b-WO-tks"/>
|
||||
</defaultToolbarItems>
|
||||
</toolbar>
|
||||
<point key="canvasLocation" x="-201" y="-1220"/>
|
||||
</window>
|
||||
<customObject id="494" userLabel="EmulatorGLView" customClass="EmulatorGLView"/>
|
||||
<customObject id="M8b-ga-iOS" customClass="EmulatorWindowController" colorLabel="IBBuiltInLabel-Blue">
|
||||
<connections>
|
||||
<outlet property="disksWindow" destination="RAk-at-ZT4" id="64k-qW-zF5"/>
|
||||
<outlet property="pauseMenuItem" destination="r9g-Ro-UwW" id="4YW-pt-lai"/>
|
||||
<outlet property="prefsWindow" destination="Mzv-VG-jce" id="dQt-pf-qdi"/>
|
||||
<outlet property="view" destination="372" id="pRG-Kn-92X"/>
|
||||
<outlet property="window" destination="371" id="z3B-S9-PsV"/>
|
||||
@ -238,7 +530,7 @@ CA
|
||||
<rect key="frame" x="20" y="153" width="212" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
<size key="cellSize" width="89" height="18"/>
|
||||
<size key="cellSize" width="88" height="18"/>
|
||||
<size key="intercellSpacing" width="4" height="2"/>
|
||||
<buttonCell key="prototype" type="radio" title="Radio" imagePosition="left" alignment="left" inset="2" id="800-L1-WxW">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
@ -266,7 +558,7 @@ CA
|
||||
<rect key="frame" x="271" y="153" width="212" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
<size key="cellSize" width="89" height="18"/>
|
||||
<size key="cellSize" width="88" height="18"/>
|
||||
<size key="intercellSpacing" width="4" height="2"/>
|
||||
<buttonCell key="prototype" type="radio" title="Radio" imagePosition="left" alignment="left" inset="2" id="uEc-fa-XXZ">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
@ -365,7 +657,7 @@ DQ
|
||||
<rect key="contentRect" x="109" y="132" width="580" height="360"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1280" height="778"/>
|
||||
<view key="contentView" id="bfK-7M-z1X">
|
||||
<rect key="frame" x="0.0" y="1" width="580" height="360"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="580" height="360"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<tabView id="xvZ-VK-VbM">
|
||||
@ -730,4 +1022,12 @@ DQ
|
||||
</connections>
|
||||
</customObject>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="NSExitFullScreenTemplate" width="15" height="15"/>
|
||||
<image name="NSFolderSmart" width="32" height="32"/>
|
||||
<image name="NSPreferencesGeneral" width="32" height="32"/>
|
||||
<image name="NSRefreshTemplate" width="11" height="15"/>
|
||||
<image name="NSUser" width="32" height="32"/>
|
||||
<image name="Stop" width="32" height="32"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
22
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorDiskController.h
Normal file
22
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorDiskController.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2013-2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
typedef void (^DiskCompletionHandler)(NSOpenPanel *openPanel, NSInteger result);
|
||||
|
||||
@interface EmulatorDiskController : NSWindowController
|
||||
|
||||
+ (NSSet *)emulatorFileTypes;
|
||||
+ (NSString *)extensionForPath:(NSString *)path;
|
||||
+ (void)chooseDiskForWindow:(NSWindow *)window completionHandler:(DiskCompletionHandler)handler;
|
||||
|
||||
@end
|
324
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorDiskController.m
Normal file
324
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorDiskController.m
Normal file
@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2014, 2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#import "EmulatorDiskController.h"
|
||||
#import "EmulatorPrefsController.h"
|
||||
#import "common.h"
|
||||
|
||||
#define READONLY_CHOICE_INDEX 0
|
||||
#define NO_DISK_INSERTED @"(No Disk Inserted)"
|
||||
#define DSK_PROPERTIES @".dsk 143360 bytes"
|
||||
#define NIB_PROPERTIES @".nib 232960 bytes"
|
||||
|
||||
#define kApple2DisksURL @"kApple2DisksURL"
|
||||
|
||||
@interface EmulatorDiskController ()
|
||||
|
||||
@property (assign) IBOutlet NSWindow *disksWindow;
|
||||
@property (assign) IBOutlet NSTextField *diskInA;
|
||||
@property (assign) IBOutlet NSTextField *diskInB;
|
||||
@property (assign) IBOutlet NSTextField *diskAProperties;
|
||||
@property (assign) IBOutlet NSTextField *diskBProperties;
|
||||
@property (assign) IBOutlet NSMatrix *diskAProtection;
|
||||
@property (assign) IBOutlet NSMatrix *diskBProtection;
|
||||
@property (assign) IBOutlet NSButton *chooseDiskA;
|
||||
@property (assign) IBOutlet NSButton *chooseDiskB;
|
||||
@property (assign) IBOutlet NSButton *startupLoadDiskA;
|
||||
@property (assign) IBOutlet NSButton *startupLoadDiskB;
|
||||
|
||||
@end
|
||||
|
||||
@implementation EmulatorDiskController
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
#if CRASH_APP_ON_LOAD_BECAUSE_YAY_GJ_APPLE
|
||||
glGetError();
|
||||
#endif
|
||||
|
||||
[self.diskInA setStringValue:NO_DISK_INSERTED];
|
||||
[self.diskAProperties setStringValue:@""];
|
||||
[self.diskInB setStringValue:NO_DISK_INSERTED];
|
||||
[self.diskBProperties setStringValue:@""];
|
||||
[self.chooseDiskA setKeyEquivalent:@"\r"];
|
||||
[self.chooseDiskA setBezelStyle:NSRoundedBezelStyle];
|
||||
[self.startupLoadDiskA setState:NSOffState];
|
||||
[self.startupLoadDiskB setState:NSOffState];
|
||||
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
NSString *startupDiskA = [defaults stringForKey:kApple2PrefStartupDiskA];
|
||||
BOOL readOnlyA = [defaults boolForKey:kApple2PrefStartupDiskAProtected];
|
||||
if (startupDiskA)
|
||||
{
|
||||
const char *err = disk6_insert(0, [[NSString stringWithFormat:@"%@.gz", startupDiskA] UTF8String], readOnlyA);
|
||||
if (!err)
|
||||
{
|
||||
[self.diskInA setStringValue:[[startupDiskA pathComponents] lastObject]];
|
||||
[self.startupLoadDiskA setState:NSOnState];
|
||||
[self.diskAProtection setState:(readOnlyA ? NSOnState : NSOffState) atRow:0 column:0];
|
||||
[self.diskAProtection setState:(!readOnlyA ? NSOnState : NSOffState) atRow:0 column:1];
|
||||
}
|
||||
}
|
||||
|
||||
NSString *startupDiskB = [defaults stringForKey:kApple2PrefStartupDiskB];
|
||||
BOOL readOnlyB = [defaults boolForKey:kApple2PrefStartupDiskBProtected];
|
||||
if (startupDiskB)
|
||||
{
|
||||
const char *err = disk6_insert(1, [[NSString stringWithFormat:@"%@.gz", startupDiskB] UTF8String], readOnlyB);
|
||||
if (!err)
|
||||
{
|
||||
[self.diskInB setStringValue:[[startupDiskB pathComponents] lastObject]];
|
||||
[self.startupLoadDiskB setState:NSOnState];
|
||||
[self.diskBProtection setState:(readOnlyB ? NSOnState : NSOffState) atRow:0 column:0];
|
||||
[self.diskBProtection setState:(!readOnlyB ? NSOnState : NSOffState) atRow:0 column:1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_savePrefs
|
||||
{
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
[defaults removeObjectForKey:kApple2PrefStartupDiskA];
|
||||
[defaults removeObjectForKey:kApple2PrefStartupDiskB];
|
||||
[defaults removeObjectForKey:kApple2PrefStartupDiskAProtected];
|
||||
[defaults removeObjectForKey:kApple2PrefStartupDiskBProtected];
|
||||
|
||||
if ([self.startupLoadDiskA state] == NSOnState)
|
||||
{
|
||||
if (disk6.disk[0].fd >= 0)
|
||||
{
|
||||
NSString *diskA = [NSString stringWithUTF8String:disk6.disk[0].file_name];
|
||||
[defaults setObject:diskA forKey:kApple2PrefStartupDiskA];
|
||||
NSButtonCell *readOnlyChoice = (NSButtonCell *)[[[self diskAProtection] cells] firstObject];
|
||||
[defaults setBool:([readOnlyChoice state] == NSOnState) forKey:kApple2PrefStartupDiskAProtected];
|
||||
}
|
||||
}
|
||||
|
||||
if ([self.startupLoadDiskB state] == NSOnState)
|
||||
{
|
||||
if (disk6.disk[1].fd >= 0)
|
||||
{
|
||||
NSString *diskB = [NSString stringWithUTF8String:disk6.disk[1].file_name];
|
||||
[defaults setObject:diskB forKey:kApple2PrefStartupDiskB];
|
||||
NSButtonCell *readOnlyChoice = (NSButtonCell *)[[[self diskBProtection] cells] firstObject];
|
||||
[defaults setBool:([readOnlyChoice state] == NSOnState) forKey:kApple2PrefStartupDiskBProtected];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_protectionChangedForDrive:(int)drive
|
||||
{
|
||||
if (disk6.disk[drive].fd < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// HACK NOTE : dispatch so that state of outlet property is set properly
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSButtonCell *readOnlyChoice = (NSButtonCell *)[[(drive == 0 ? [self diskAProtection] : [self diskBProtection]) cells] firstObject];
|
||||
NSString *path = [NSString stringWithUTF8String:disk6.disk[drive].file_name];
|
||||
[self _insertDisketteInDrive:drive path:path type:[EmulatorDiskController extensionForPath:path] readOnly:([readOnlyChoice state] == NSOnState)];
|
||||
[self _savePrefs];
|
||||
});
|
||||
}
|
||||
|
||||
- (IBAction)diskAProtectionChanged:(id)sender
|
||||
{
|
||||
[self _protectionChangedForDrive:0];
|
||||
}
|
||||
|
||||
- (IBAction)diskBProtectionChanged:(id)sender
|
||||
{
|
||||
[self _protectionChangedForDrive:1];
|
||||
}
|
||||
|
||||
- (BOOL)_insertDisketteInDrive:(int)drive path:(NSString *)path type:(NSString *)type readOnly:(BOOL)readOnly
|
||||
{
|
||||
disk6_eject(drive);
|
||||
|
||||
const char *errMsg = disk6_insert(drive, [path UTF8String], readOnly);
|
||||
if (errMsg)
|
||||
{
|
||||
path = [NSString stringWithFormat:@"%@.gz", path];
|
||||
errMsg = disk6_insert(drive, [path UTF8String], readOnly);
|
||||
if (errMsg)
|
||||
{
|
||||
NSAlert *alert = [NSAlert alertWithError:[NSError errorWithDomain:[NSString stringWithUTF8String:errMsg] code:-1 userInfo:nil]];
|
||||
[alert beginSheetModalForWindow:[self disksWindow] completionHandler:nil];
|
||||
if (!drive)
|
||||
{
|
||||
[[self diskInA] setStringValue:NO_DISK_INSERTED];
|
||||
[[self diskAProperties] setStringValue:@""];
|
||||
}
|
||||
else
|
||||
{
|
||||
[[self diskInB] setStringValue:NO_DISK_INSERTED];
|
||||
[[self diskBProperties] setStringValue:@""];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
path = [NSString stringWithUTF8String:disk6.disk[drive].file_name];
|
||||
NSString *imageName = [[path pathComponents] lastObject];
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
if (drive == 0)
|
||||
{
|
||||
[[self diskInA] setStringValue:imageName];
|
||||
if ([[defaults stringForKey:kApple2PrefStartupDiskA] isEqualToString:path])
|
||||
{
|
||||
[self.startupLoadDiskA setState:NSOnState];
|
||||
//[self.diskAProtection setState:(readOnly ? NSOnState : NSOffState) atRow:0 column:0];
|
||||
//[self.diskAProtection setState:(!readOnly ? NSOnState : NSOffState) atRow:0 column:1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[[self diskInB] setStringValue:imageName];
|
||||
if ([[defaults stringForKey:kApple2PrefStartupDiskB] isEqualToString:path])
|
||||
{
|
||||
[self.startupLoadDiskB setState:NSOnState];
|
||||
//[self.diskBProtection setState:(readOnly ? NSOnState : NSOffState) atRow:0 column:0];
|
||||
//[self.diskBProtection setState:(!readOnly ? NSOnState : NSOffState) atRow:0 column:1];
|
||||
}
|
||||
}
|
||||
|
||||
if ([type isEqualToString:@"dsk"] || [type isEqualToString:@"do"] || [type isEqualToString:@"po"])
|
||||
{
|
||||
if (!drive)
|
||||
{
|
||||
[[self diskAProperties] setStringValue:DSK_PROPERTIES];
|
||||
}
|
||||
else
|
||||
{
|
||||
[[self diskBProperties] setStringValue:DSK_PROPERTIES];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!drive)
|
||||
{
|
||||
[[self diskAProperties] setStringValue:NIB_PROPERTIES];
|
||||
}
|
||||
else
|
||||
{
|
||||
[[self diskBProperties] setStringValue:NIB_PROPERTIES];
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSSet *)emulatorFileTypes
|
||||
{
|
||||
static NSSet *set = nil;
|
||||
static dispatch_once_t onceToken = 0L;
|
||||
dispatch_once(&onceToken, ^{
|
||||
set = [[NSSet alloc] initWithObjects:@"dsk", @"nib", @"do", @"po", @"gz", nil];
|
||||
});
|
||||
return [[set retain] autorelease];
|
||||
}
|
||||
|
||||
+ (NSString *)extensionForPath:(NSString *)path
|
||||
{
|
||||
NSString *extension0 = [path pathExtension];
|
||||
NSString *extension1 = [[path stringByDeletingPathExtension] pathExtension];
|
||||
if ([extension0 isEqualToString:@"gz"])
|
||||
{
|
||||
extension0 = extension1;
|
||||
}
|
||||
return extension0;
|
||||
}
|
||||
|
||||
+ (void)chooseDiskForWindow:(NSWindow *)window completionHandler:(DiskCompletionHandler)handler
|
||||
{
|
||||
NSOpenPanel *openPanel = [[NSOpenPanel openPanel] retain];
|
||||
[openPanel setTitle:@"Choose a disk image"];
|
||||
NSURL *url = [[NSUserDefaults standardUserDefaults] URLForKey:kApple2DisksURL];
|
||||
if (!url)
|
||||
{
|
||||
url = [[NSBundle mainBundle] URLForResource:@"images" withExtension:nil];
|
||||
}
|
||||
[openPanel setDirectoryURL:url];
|
||||
[openPanel setShowsResizeIndicator:YES];
|
||||
[openPanel setShowsHiddenFiles:NO];
|
||||
[openPanel setCanChooseFiles:YES];
|
||||
[openPanel setCanChooseDirectories:NO];
|
||||
[openPanel setCanCreateDirectories:NO];
|
||||
[openPanel setAllowsMultipleSelection:NO];
|
||||
|
||||
// NOTE : Doesn't appear to be a way to specify ".dsk.gz" ... so we may inadvertently allow files of ".foo.gz" here
|
||||
NSSet *fileTypes = [EmulatorDiskController emulatorFileTypes];
|
||||
[openPanel setAllowedFileTypes:[fileTypes allObjects]];
|
||||
handler = Block_copy(handler);
|
||||
[openPanel beginSheetModalForWindow:window completionHandler:^(NSInteger result) {
|
||||
handler(openPanel, result);
|
||||
Block_release(handler);
|
||||
[openPanel autorelease];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)_chooseDisk:(int)drive readOnly:(BOOL)readOnly
|
||||
{
|
||||
[EmulatorDiskController chooseDiskForWindow:[self disksWindow] completionHandler:^(NSOpenPanel *openPanel, NSInteger result) {
|
||||
if (result == NSOKButton)
|
||||
{
|
||||
NSURL *selection = [[openPanel URLs] firstObject];
|
||||
NSString *path = [[selection path] stringByResolvingSymlinksInPath];
|
||||
NSString *extension = [EmulatorDiskController extensionForPath:path];
|
||||
NSSet *fileTypes = [EmulatorDiskController emulatorFileTypes];
|
||||
|
||||
NSString *directory = [path stringByDeletingLastPathComponent];
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults setURL:[NSURL URLWithString:directory] forKey:kApple2DisksURL];
|
||||
|
||||
if (![fileTypes containsObject:extension])
|
||||
{
|
||||
NSAlert *alert = [NSAlert alertWithError:[NSError errorWithDomain:@"Disk image must have file extension of .dsk, .do, .po, or .nib only" code:-1 userInfo:nil]];
|
||||
[alert beginSheetModalForWindow:[self disksWindow] completionHandler:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
[(drive == 0) ? self.startupLoadDiskA : self.startupLoadDiskB setState:NSOffState];
|
||||
[self _insertDisketteInDrive:drive path:path type:extension readOnly:readOnly];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (IBAction)chooseDriveA:(id)sender
|
||||
{
|
||||
NSButtonCell *readOnlyChoice = (NSButtonCell *)[[[self diskAProtection] cells] firstObject];
|
||||
[self _chooseDisk:0 readOnly:([readOnlyChoice state] == NSOnState)];
|
||||
}
|
||||
|
||||
- (IBAction)chooseDriveB:(id)sender
|
||||
{
|
||||
NSButtonCell *readOnlyChoice = (NSButtonCell *)[[[self diskBProtection] cells] firstObject];
|
||||
[self _chooseDisk:1 readOnly:([readOnlyChoice state] == NSOnState)];
|
||||
}
|
||||
|
||||
- (IBAction)startupDiskAChoiceChanged:(id)sender
|
||||
{
|
||||
[self _savePrefs];
|
||||
}
|
||||
|
||||
- (IBAction)startupDiskBChoiceChanged:(id)sender
|
||||
{
|
||||
[self _savePrefs];
|
||||
}
|
||||
|
||||
- (IBAction)disksOK:(id)sender
|
||||
{
|
||||
[[self disksWindow] close];
|
||||
}
|
||||
|
||||
@end
|
18
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorFullscreenWindow.h
Normal file
18
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorFullscreenWindow.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2014, 2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
// Based on sample code from https://developer.apple.com/library/mac/samplecode/GLEssentials/Introduction/Intro.html
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface EmulatorFullscreenWindow : NSWindow
|
||||
|
||||
@end
|
54
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorFullscreenWindow.m
Normal file
54
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorFullscreenWindow.m
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2014, 2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
// Based on sample code from https://developer.apple.com/library/mac/samplecode/GLEssentials/Introduction/Intro.html
|
||||
|
||||
#import "EmulatorFullscreenWindow.h"
|
||||
|
||||
@implementation EmulatorFullscreenWindow
|
||||
|
||||
- (id)init
|
||||
{
|
||||
// Create a screen-sized window on the display you want to take over
|
||||
NSRect screenRect = [[NSScreen mainScreen] frame];
|
||||
|
||||
// Initialize the window making it size of the screen and borderless
|
||||
self = [super initWithContentRect:screenRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
|
||||
|
||||
// Set the window level to be above the menu bar to cover everything else
|
||||
[self setLevel:NSMainMenuWindowLevel+1];
|
||||
|
||||
// Set opaque
|
||||
[self setOpaque:YES];
|
||||
|
||||
// Hide this when user switches to another window (or app)
|
||||
[self setHidesOnDeactivate:YES];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeKeyWindow
|
||||
{
|
||||
// Return yes so that this borderless window can receive input
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)keyUp:(NSEvent *)event
|
||||
{
|
||||
[[self windowController] keyUp:event];
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent *)event
|
||||
{
|
||||
[[self windowController] keyDown:event];
|
||||
}
|
||||
|
||||
@end
|
21
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorGLView.h
Normal file
21
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorGLView.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2014, 2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
// Based on sample code from https://developer.apple.com/library/mac/samplecode/GLEssentials/Introduction/Intro.html
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <QuartzCore/CVDisplayLink.h>
|
||||
|
||||
#import "modelUtil.h"
|
||||
#import "imageUtil.h"
|
||||
|
||||
@interface EmulatorGLView : NSOpenGLView
|
||||
@end
|
321
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorGLView.m
Normal file
321
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorGLView.m
Normal file
@ -0,0 +1,321 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2014, 2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
// Based on sample code from https://developer.apple.com/library/mac/samplecode/GLEssentials/Introduction/Intro.html
|
||||
|
||||
#import "EmulatorGLView.h"
|
||||
|
||||
// Apple //e common routines
|
||||
#import "common.h"
|
||||
|
||||
#if TARGET_OS_MAC
|
||||
#define USE_DISPLAYLINK 0
|
||||
#define BROKEN_DISPLAYLINK 1
|
||||
#else
|
||||
// iOS uses CADisplayLink
|
||||
#define USE_DISPLAYLINK 1
|
||||
#endif
|
||||
|
||||
#define SUPPORT_RETINA_RESOLUTION 1
|
||||
|
||||
const NSString *kDrawTimerNotification = @"kDrawTimerNotification";
|
||||
|
||||
@interface EmulatorGLView ()
|
||||
|
||||
#if USE_DISPLAYLINK
|
||||
@property (nonatomic, assign) CVDisplayLinkRef displayLink;
|
||||
#else
|
||||
@property (nonatomic, retain) NSTimer *timer;
|
||||
#endif
|
||||
|
||||
- (void)initGL;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation EmulatorGLView
|
||||
|
||||
#if USE_DISPLAYLINK
|
||||
@synthesize displayLink = _displayLink;
|
||||
#else
|
||||
@synthesize timer = _timer;
|
||||
#endif
|
||||
|
||||
#pragma mark CVDisplayLink / NSTimer stuff
|
||||
|
||||
#if USE_DISPLAYLINK
|
||||
- (CVReturn)getFrameForTime:(const CVTimeStamp *)outputTime
|
||||
{
|
||||
// There is no autorelease pool when this method is called
|
||||
// because it will be called from a background thread.
|
||||
// It's important to create one or app can leak objects.
|
||||
@autoreleasepool {
|
||||
// We draw on a secondary thread through the display link
|
||||
// When resizing the view, -reshape is called automatically on the main
|
||||
// thread. Add a mutex around to avoid the threads accessing the context
|
||||
// simultaneously when resizing
|
||||
|
||||
#if BROKEN_DISPLAYLINK
|
||||
#warning ASC NOTE 2014/09/27 multi-threaded OpenGL on Mac considered harmful to developer sanity
|
||||
// 2014/09/27 Kinda defeats the purpose of using CVDisplayLink ... but keeps it from crashing to dispatch to main queue
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
#endif
|
||||
[[self openGLContext] makeCurrentContext];
|
||||
[self drawView];
|
||||
#if BROKEN_DISPLAYLINK
|
||||
});
|
||||
#endif
|
||||
}
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
|
||||
// This is the renderer output callback function
|
||||
static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext)
|
||||
{
|
||||
CVReturn result = [(EmulatorGLView *)displayLinkContext getFrameForTime:outputTime];
|
||||
return result;
|
||||
}
|
||||
|
||||
#else // use NSTimer
|
||||
- (void)targetMethod:(NSTimer *)theTimer
|
||||
{
|
||||
NSAssert([NSThread isMainThread], @"Timer fired on non-main thread!");
|
||||
[[self openGLContext] makeCurrentContext];
|
||||
[self drawView];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
NSOpenGLPixelFormatAttribute attrs[] =
|
||||
{
|
||||
NSOpenGLPFADoubleBuffer,
|
||||
NSOpenGLPFADepthSize, 24,
|
||||
// Must specify the 3.2 Core Profile to use OpenGL 3.2
|
||||
NSOpenGLPFAOpenGLProfile,
|
||||
NSOpenGLProfileVersion3_2Core,
|
||||
0
|
||||
};
|
||||
|
||||
NSOpenGLPixelFormat *pf = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attrs] autorelease];
|
||||
|
||||
if (!pf)
|
||||
{
|
||||
NSLog(@"No OpenGL pixel format");
|
||||
}
|
||||
|
||||
NSOpenGLContext* context = [[[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil] autorelease];
|
||||
|
||||
#if defined(DEBUG)
|
||||
// When we're using a CoreProfile context, crash if we call a legacy OpenGL function
|
||||
// This will make it much more obvious where and when such a function call is made so
|
||||
// that we can remove such calls.
|
||||
// Without this we'd simply get GL_INVALID_OPERATION error for calling legacy functions
|
||||
// but it would be more difficult to see where that function was called.
|
||||
CGLEnable([context CGLContextObj], kCGLCECrashOnRemovedFunctions);
|
||||
#endif
|
||||
|
||||
[self setPixelFormat:pf];
|
||||
[self setOpenGLContext:context];
|
||||
|
||||
#if SUPPORT_RETINA_RESOLUTION
|
||||
// Opt-In to Retina resolution
|
||||
[self setWantsBestResolutionOpenGLSurface:YES];
|
||||
#endif // SUPPORT_RETINA_RESOLUTION
|
||||
}
|
||||
|
||||
- (void)prepareOpenGL
|
||||
{
|
||||
[super prepareOpenGL];
|
||||
|
||||
// Make all the OpenGL calls to setup rendering
|
||||
// and build the necessary rendering objects
|
||||
[self initGL];
|
||||
|
||||
#if USE_DISPLAYLINK
|
||||
// Create a display link capable of being used with all active displays
|
||||
CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink);
|
||||
|
||||
// Set the renderer output callback function
|
||||
CVDisplayLinkSetOutputCallback(_displayLink, &displayLinkCallback, self);
|
||||
|
||||
// Set the display link for the current renderer
|
||||
CGLContextObj cglContext = [[self openGLContext] CGLContextObj];
|
||||
CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
|
||||
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(_displayLink, cglContext, cglPixelFormat);
|
||||
|
||||
// Activate the display link
|
||||
CVDisplayLinkStart(_displayLink);
|
||||
#else
|
||||
[self.timer invalidate];
|
||||
self.timer = nil;
|
||||
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0/60.0 target:self selector:@selector(targetMethod:) userInfo:nil repeats:YES];
|
||||
#endif
|
||||
|
||||
// Register to be notified when the window closes so we can stop the displaylink
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowWillClose:) name:NSWindowWillCloseNotification object:[self window]];
|
||||
}
|
||||
|
||||
- (void)windowWillClose:(NSNotification*)notification
|
||||
{
|
||||
// Stop the display link when the window is closing because default
|
||||
// OpenGL render buffers will be destroyed. If display link continues to
|
||||
// fire without renderbuffers, OpenGL draw calls will set errors.
|
||||
#if USE_DISPLAYLINK
|
||||
CVDisplayLinkStop(_displayLink);
|
||||
#else
|
||||
[self.timer invalidate];
|
||||
self.timer = nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)initGL
|
||||
{
|
||||
// The reshape function may have changed the thread to which our OpenGL
|
||||
// context is attached before prepareOpenGL and initGL are called. So call
|
||||
// makeCurrentContext to ensure that our OpenGL context current to this
|
||||
// thread (i.e. makeCurrentContext directs all OpenGL calls on this thread
|
||||
// to [self openGLContext])
|
||||
[[self openGLContext] makeCurrentContext];
|
||||
|
||||
emulator_start();
|
||||
|
||||
// Synchronize buffer swaps with vertical refresh rate
|
||||
GLint swapInt = 1;
|
||||
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
|
||||
|
||||
// Init our renderer. Use 0 for the defaultFBO which is appropriate for
|
||||
// OSX (but not iOS since iOS apps must create their own FBO)
|
||||
#if TARGET_OS_MAC
|
||||
video_backend->init(0);
|
||||
#elif TARGET_OS_IPHONE
|
||||
# error "FBO FIXME TODO"
|
||||
video_backend->init(otherFBO);
|
||||
#else
|
||||
# error "unknown/unsupported Apple platform
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)reshape
|
||||
{
|
||||
[super reshape];
|
||||
|
||||
// We draw on a secondary thread through the display link. However, when
|
||||
// resizing the view, -drawRect is called on the main thread.
|
||||
// Add a mutex around to avoid the threads accessing the context
|
||||
// simultaneously when resizing.
|
||||
CGLLockContext([[self openGLContext] CGLContextObj]);
|
||||
|
||||
// Get the view size in Points
|
||||
NSRect viewRectPoints = [self bounds];
|
||||
|
||||
#if SUPPORT_RETINA_RESOLUTION
|
||||
|
||||
// Rendering at retina resolutions will reduce aliasing, but at the potential
|
||||
// cost of framerate and battery life due to the GPU needing to render more
|
||||
// pixels.
|
||||
|
||||
// Any calculations the renderer does which use pixel dimentions, must be
|
||||
// in "retina" space. [NSView convertRectToBacking] converts point sizes
|
||||
// to pixel sizes. Thus the renderer gets the size in pixels, not points,
|
||||
// so that it can set it's viewport and perform and other pixel based
|
||||
// calculations appropriately.
|
||||
// viewRectPixels will be larger (2x) than viewRectPoints for retina displays.
|
||||
// viewRectPixels will be the same as viewRectPoints for non-retina displays
|
||||
NSRect viewRectPixels = [self convertRectToBacking:viewRectPoints];
|
||||
|
||||
#else //if !SUPPORT_RETINA_RESOLUTION
|
||||
|
||||
// App will typically render faster and use less power rendering at
|
||||
// non-retina resolutions since the GPU needs to render less pixels. There
|
||||
// is the cost of more aliasing, but it will be no-worse than on a Mac
|
||||
// without a retina display.
|
||||
|
||||
// Points:Pixels is always 1:1 when not supporting retina resolutions
|
||||
NSRect viewRectPixels = viewRectPoints;
|
||||
|
||||
#endif // !SUPPORT_RETINA_RESOLUTION
|
||||
|
||||
// Set the new dimensions in our renderer
|
||||
video_backend->reshape((int)viewRectPixels.size.width, (int)viewRectPixels.size.height);
|
||||
|
||||
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
||||
}
|
||||
|
||||
- (void)renewGState
|
||||
{
|
||||
// Called whenever graphics state updated (such as window resize)
|
||||
|
||||
// OpenGL rendering is not synchronous with other rendering on the OSX.
|
||||
// Therefore, call disableScreenUpdatesUntilFlush so the window server
|
||||
// doesn't render non-OpenGL content in the window asynchronously from
|
||||
// OpenGL content, which could cause flickering. (non-OpenGL content
|
||||
// includes the title bar and drawing done by the app with other APIs)
|
||||
[[self window] disableScreenUpdatesUntilFlush];
|
||||
[super renewGState];
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)theRect
|
||||
{
|
||||
NSAssert([NSThread isMainThread], @"drawRect called on non-main thread!");
|
||||
// Called during resize operations
|
||||
// Avoid flickering during resize by drawing
|
||||
[[self openGLContext] makeCurrentContext];
|
||||
[self drawView];
|
||||
}
|
||||
|
||||
- (void)drawView
|
||||
{
|
||||
CGLLockContext([[self openGLContext] CGLContextObj]);
|
||||
video_backend->render();
|
||||
CGLFlushDrawable([[self openGLContext] CGLContextObj]);
|
||||
CGLUnlockContext([[self openGLContext] CGLContextObj]);
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:(NSString *)kDrawTimerNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
// Stop the display link BEFORE releasing anything in the view
|
||||
// otherwise the display link thread may call into the view and crash
|
||||
// when it encounters something that has been release
|
||||
#if USE_DISPLAYLINK
|
||||
CVDisplayLinkStop(_displayLink);
|
||||
CVDisplayLinkRelease(_displayLink);
|
||||
#else
|
||||
[self.timer invalidate];
|
||||
self.timer = nil;
|
||||
#endif
|
||||
|
||||
// shut down common OpenGL stuff AFTER display link has been released
|
||||
emulator_shutdown();
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Application Delegate methods
|
||||
|
||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)application
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)application
|
||||
{
|
||||
disk6_eject(0);
|
||||
disk6_eject(1);
|
||||
return NSTerminateNow;
|
||||
}
|
||||
|
||||
@end
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2014, 2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface EmulatorJoystickCalibrationView : NSView
|
||||
|
||||
@end
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2013-2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#import "EmulatorJoystickCalibrationView.h"
|
||||
#import "common.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@implementation EmulatorJoystickCalibrationView
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
{
|
||||
[super drawRect:dirtyRect];
|
||||
[self drawView];
|
||||
}
|
||||
|
||||
- (void)drawView
|
||||
{
|
||||
static int pulseSize = 1;
|
||||
|
||||
CGRect bounds = [self bounds];
|
||||
|
||||
NSAssert(bounds.size.height == JOY_RANGE, @"view should be 256pts high");
|
||||
NSAssert(bounds.size.width == JOY_RANGE, @"view should be 256pts wide");
|
||||
|
||||
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
|
||||
CGContextSaveGState(context);
|
||||
CGContextSetLineWidth(context, 1);
|
||||
|
||||
if (joy_clip_to_radius && (joy_mode == JOY_PCJOY))
|
||||
{
|
||||
CGContextSetRGBStrokeColor(context, 0, 0, 0, 1);
|
||||
CGContextAddEllipseInRect(context, bounds);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
CGFloat x_val = joy_x;
|
||||
CGFloat y_val = JOY_RANGE-joy_y;
|
||||
|
||||
CGContextSetRGBStrokeColor(context, 1, 0, 0, 1);
|
||||
CGRect cursor = CGRectMake(x_val-(pulseSize/2.f), y_val-(pulseSize/2.f), pulseSize, pulseSize);
|
||||
CGContextAddEllipseInRect(context, cursor);
|
||||
|
||||
CGContextStrokePath(context);
|
||||
CGContextRestoreGState(context);
|
||||
|
||||
pulseSize = ((pulseSize+1) & 0x7) +1;
|
||||
}
|
||||
|
||||
- (void)keyUp:(NSEvent *)event
|
||||
{
|
||||
[[self nextResponder] keyUp:event];
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent *)event
|
||||
{
|
||||
[[self nextResponder] keyDown:event];
|
||||
}
|
||||
|
||||
@end
|
16
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorJoystickController.h
Normal file
16
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorJoystickController.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2013-2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface EmulatorJoystickController : NSObject
|
||||
|
||||
@end
|
228
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorJoystickController.m
Normal file
228
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorJoystickController.m
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2014, 2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#import "EmulatorJoystickController.h"
|
||||
#import "EmulatorWindowController.h"
|
||||
#import "common.h"
|
||||
|
||||
#import <DDHidLib/DDHidJoystick.h>
|
||||
|
||||
@interface EmulatorJoystickController()
|
||||
@property (nonatomic, retain) NSDictionary *allJoysticks;
|
||||
+ (EmulatorJoystickController *)sharedInstance;
|
||||
- (void)resetJoysticks;
|
||||
@end
|
||||
|
||||
void gldriver_joystick_reset(void) {
|
||||
[EmulatorJoystickController sharedInstance];
|
||||
}
|
||||
|
||||
@implementation EmulatorJoystickController
|
||||
|
||||
@synthesize allJoysticks = _allJoysticks;
|
||||
|
||||
+ (EmulatorJoystickController *)sharedInstance
|
||||
{
|
||||
static dispatch_once_t onceToken = 0L;
|
||||
static EmulatorJoystickController *joystickController = nil;
|
||||
dispatch_once(&onceToken, ^{
|
||||
joystickController = [[EmulatorJoystickController alloc] init];
|
||||
});
|
||||
return joystickController;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(connectivityPoll:) name:(NSString *)kDrawTimerNotification object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
self.allJoysticks = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)resetJoysticks
|
||||
{
|
||||
for (DDHidJoystick *joystick in [self.allJoysticks allValues])
|
||||
{
|
||||
@try {
|
||||
[joystick setDelegate:nil];
|
||||
[joystick stopListening];
|
||||
} @catch (NSException *e) {
|
||||
// hot-plugging joysticks can cause glitches
|
||||
NSLog(@"Joystick device library raised exception on close : %@", e);
|
||||
}
|
||||
}
|
||||
NSArray *joysticks = [DDHidJoystick allJoysticks];
|
||||
NSMutableDictionary *allJoysticks = [NSMutableDictionary dictionary];
|
||||
for (DDHidJoystick *joystick in joysticks) {
|
||||
NSString *key =[NSString stringWithFormat:@"%@-%@-%@", [joystick manufacturer], [joystick serialNumber], [joystick transport]];
|
||||
[allJoysticks setObject:joystick forKey:key];
|
||||
}
|
||||
self.allJoysticks = allJoysticks;
|
||||
dispatch_async(dispatch_get_main_queue(), ^ {
|
||||
for (DDHidJoystick *joystick in [self.allJoysticks allValues])
|
||||
{
|
||||
NSLog(@"found joystick : '%@' '%@' '%@' %@", [joystick manufacturer], [joystick serialNumber], [joystick transport], joystick);
|
||||
@try {
|
||||
[joystick setDelegate:self];
|
||||
[joystick startListening];
|
||||
} @catch (NSException *e) {
|
||||
// hot-plugging joystick can cause glitches
|
||||
NSLog(@"Joystick device library raised exception on start : %@", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Joystick connectivity polling
|
||||
|
||||
- (void)connectivityPoll:(NSNotification *)notification
|
||||
{
|
||||
static unsigned int counter = 0;
|
||||
counter = (counter+1) % 60;
|
||||
if (counter == 0)
|
||||
{
|
||||
NSArray *joysticks = [DDHidJoystick allJoysticks];
|
||||
BOOL changed = ([joysticks count] != [self.allJoysticks count]);
|
||||
for (DDHidJoystick *joystick in joysticks)
|
||||
{
|
||||
NSString *key =[NSString stringWithFormat:@"%@-%@-%@", [joystick manufacturer], [joystick serialNumber], [joystick transport]];
|
||||
if (![self.allJoysticks objectForKey:key])
|
||||
{
|
||||
changed = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (changed)
|
||||
{
|
||||
[self resetJoysticks];
|
||||
}
|
||||
}
|
||||
#ifdef KEYPAD_JOYSTICK
|
||||
if (joy_mode == JOY_KPAD)
|
||||
{
|
||||
c_keys_handle_input(-1, 0, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark NSObject(DDHidJoystickDelegate)
|
||||
|
||||
#define DDHID_JOYSTICK_NORMALIZER ((float)JOY_RANGE/(DDHID_JOYSTICK_VALUE_MAX*2))
|
||||
#define QUARTER_JOY (HALF_JOY_RANGE>>1)
|
||||
|
||||
static inline void clampBeyondRadius(void) {
|
||||
CGFloat half_x = joy_x - HALF_JOY_RANGE;
|
||||
CGFloat half_y = joy_y - HALF_JOY_RANGE;
|
||||
CGFloat r = sqrtf(half_x*half_x + half_y*half_y);
|
||||
bool shouldClip = (r > HALF_JOY_RANGE);
|
||||
if (joy_clip_to_radius && shouldClip) {
|
||||
if (joy_x < HALF_JOY_RANGE) {
|
||||
joy_x = (joy_x < QUARTER_JOY) ? 0.f : joy_x;
|
||||
} else {
|
||||
joy_x = (joy_x < HALF_JOY_RANGE+QUARTER_JOY) ? joy_x : JOY_RANGE-1;
|
||||
}
|
||||
if (joy_y < HALF_JOY_RANGE) {
|
||||
joy_y = (joy_y < QUARTER_JOY) ? 0.f : joy_y;
|
||||
} else {
|
||||
joy_y = (joy_y < HALF_JOY_RANGE+QUARTER_JOY) ? joy_y : JOY_RANGE-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)ddhidJoystick:(DDHidJoystick *)joystick stick:(unsigned int)stick xChanged:(int)value
|
||||
{
|
||||
#ifdef KEYPAD_JOYSTICK
|
||||
if (joy_mode == JOY_KPAD) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
joy_x = (uint16_t)((value+DDHID_JOYSTICK_VALUE_MAX) * DDHID_JOYSTICK_NORMALIZER);
|
||||
if (joy_x > 0xFF) {
|
||||
joy_x = 0xFF;
|
||||
}
|
||||
|
||||
clampBeyondRadius();
|
||||
}
|
||||
|
||||
- (void)ddhidJoystick:(DDHidJoystick *)joystick stick:(unsigned int)stick yChanged:(int)value
|
||||
{
|
||||
#ifdef KEYPAD_JOYSTICK
|
||||
if (joy_mode == JOY_KPAD) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
joy_y = (uint16_t)((value+DDHID_JOYSTICK_VALUE_MAX) * DDHID_JOYSTICK_NORMALIZER);
|
||||
if (joy_y > 0xFF) {
|
||||
joy_y = 0xFF;
|
||||
}
|
||||
|
||||
clampBeyondRadius();
|
||||
}
|
||||
|
||||
- (void)ddhidJoystick:(DDHidJoystick *)joystick stick:(unsigned int)stick otherAxis:(unsigned)otherAxis valueChanged:(int)value
|
||||
{
|
||||
// NOOP ...
|
||||
}
|
||||
|
||||
- (void)ddhidJoystick:(DDHidJoystick *)joystick stick:(unsigned int)stick povNumber:(unsigned)povNumber valueChanged:(int)value
|
||||
{
|
||||
// NOOP ...
|
||||
}
|
||||
|
||||
- (void)ddhidJoystick:(DDHidJoystick *)joystick buttonDown:(unsigned int)buttonNumber
|
||||
{
|
||||
#ifdef KEYPAD_JOYSTICK
|
||||
if (joy_mode == JOY_KPAD) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// sample buttons only if apple keys aren't pressed. keys get set to 0xff, and js buttons are set to 0x80.
|
||||
if ((buttonNumber == 0x01) && !(joy_button0 & 0x7f)) {
|
||||
joy_button0 = 0x80;
|
||||
}
|
||||
if ((buttonNumber == 0x02) && !(joy_button1 & 0x7f)) {
|
||||
joy_button1 = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)ddhidJoystick:(DDHidJoystick *)joystick buttonUp:(unsigned int)buttonNumber
|
||||
{
|
||||
#ifdef KEYPAD_JOYSTICK
|
||||
if (joy_mode == JOY_KPAD) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// sample buttons only if apple keys aren't pressed. keys get set to 0xff, and js buttons are set to 0x80.
|
||||
if ((buttonNumber == 0x01) && !(joy_button0 & 0x7f)) {
|
||||
joy_button0 = 0x0;
|
||||
}
|
||||
if ((buttonNumber == 0x02) && !(joy_button1 & 0x7f)) {
|
||||
joy_button1 = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
21
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorPrefsController.h
Normal file
21
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorPrefsController.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2013-2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#define kApple2PrefStartupDiskA @"kApple2PrefStartupDiskA"
|
||||
#define kApple2PrefStartupDiskAProtected @"kApple2PrefStartupDiskAProtected"
|
||||
#define kApple2PrefStartupDiskB @"kApple2PrefStartupDiskB"
|
||||
#define kApple2PrefStartupDiskBProtected @"kApple2PrefStartupDiskBProtected"
|
||||
|
||||
@interface EmulatorPrefsController : NSWindowController
|
||||
|
||||
@end
|
353
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorPrefsController.m
Normal file
353
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorPrefsController.m
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2013-2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#import "EmulatorPrefsController.h"
|
||||
#import "EmulatorDiskController.h"
|
||||
#import "EmulatorJoystickCalibrationView.h"
|
||||
#import "EmulatorWindowController.h"
|
||||
#import "common.h"
|
||||
|
||||
#define kApple2SavedPrefs @"kApple2SavedPrefs"
|
||||
#define kApple2CPUSpeed @"kApple2CPUSpeed"
|
||||
#define kApple2CPUSpeedIsMax @"kApple2CPUSpeedIsMax"
|
||||
#define kApple2AltSpeed @"kApple2AltSpeed"
|
||||
#define kApple2AltSpeedIsMax @"kApple2AltSpeedIsMax"
|
||||
#define kApple2SoundcardConfig @"kApple2SoundcardConfig"
|
||||
#define kApple2ColorConfig @"kApple2ColorConfig"
|
||||
#define kApple2JoystickConfig @"kApple2JoystickConfig"
|
||||
#define kApple2JoystickAutoRecenter @"kApple2JoystickAutoRecenter"
|
||||
#define kApple2JoystickClipToRadius @"kApple2JoystickClipToRadius"
|
||||
#define kApple2JoystickStep @"kApple2JoystickStep"
|
||||
|
||||
@interface EmulatorPrefsController ()
|
||||
|
||||
@property (assign) IBOutlet NSSlider *cpuSlider;
|
||||
@property (assign) IBOutlet NSSlider *altSlider;
|
||||
@property (assign) IBOutlet NSTextField *cpuSliderLabel;
|
||||
@property (assign) IBOutlet NSTextField *altSliderLabel;
|
||||
@property (assign) IBOutlet NSButton *cpuMaxChoice;
|
||||
@property (assign) IBOutlet NSButton *altMaxChoice;
|
||||
|
||||
@property (assign) IBOutlet NSMatrix *soundCardChoice;
|
||||
|
||||
@property (assign) IBOutlet NSPopUpButton *colorChoice;
|
||||
|
||||
@property (assign) IBOutlet NSPopUpButton *joystickChoice;
|
||||
@property (assign) IBOutlet NSButton *joystickRecenter;
|
||||
@property (assign) IBOutlet NSButton *joystickClipToRadius;
|
||||
@property (assign) IBOutlet NSTextField *joystickStepLabel;
|
||||
@property (assign) IBOutlet NSStepper *joystickStepper;
|
||||
@property (assign) IBOutlet NSTextField *joystickStepperLabel;
|
||||
@property (assign) IBOutlet NSTextField *joystickKPadNotes;
|
||||
@property (assign) IBOutlet NSTextField *joystickDeviceNotes;
|
||||
|
||||
@property (assign) IBOutlet NSTextField *button0Pressed;
|
||||
@property (assign) IBOutlet NSTextField *button1Pressed;
|
||||
@property (assign) IBOutlet EmulatorJoystickCalibrationView *joystickCalibrationView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation EmulatorPrefsController
|
||||
|
||||
- (void)awakeFromNib
|
||||
{
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
BOOL firstTime = ![defaults boolForKey:kApple2SavedPrefs];
|
||||
if (firstTime)
|
||||
{
|
||||
[defaults setBool:YES forKey:kApple2SavedPrefs];
|
||||
[defaults setDouble:1.0 forKey:kApple2CPUSpeed];
|
||||
[defaults setDouble:CPU_SCALE_SLOWEST forKey:kApple2AltSpeed];
|
||||
[defaults setBool:NO forKey:kApple2CPUSpeedIsMax];
|
||||
[defaults setBool:NO forKey:kApple2AltSpeedIsMax];
|
||||
[defaults setInteger:COLOR_INTERP forKey:kApple2ColorConfig];
|
||||
[defaults setInteger:JOY_KPAD forKey:kApple2JoystickConfig];
|
||||
[defaults setBool:YES forKey:kApple2JoystickAutoRecenter];
|
||||
[defaults removeObjectForKey:kApple2PrefStartupDiskA];
|
||||
[defaults removeObjectForKey:kApple2PrefStartupDiskB];
|
||||
}
|
||||
|
||||
cpu_scale_factor = [defaults doubleForKey:kApple2CPUSpeed];
|
||||
[self.cpuSlider setDoubleValue:cpu_scale_factor];
|
||||
[self.cpuSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", cpu_scale_factor*100]];
|
||||
if ([defaults boolForKey:kApple2CPUSpeedIsMax])
|
||||
{
|
||||
cpu_scale_factor = CPU_SCALE_FASTEST;
|
||||
[self.cpuMaxChoice setState:NSOnState];
|
||||
[self.cpuSlider setEnabled:NO];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self.cpuMaxChoice setState:NSOffState];
|
||||
[self.cpuSlider setEnabled:YES];
|
||||
}
|
||||
|
||||
cpu_altscale_factor = [defaults doubleForKey:kApple2AltSpeed];
|
||||
[self.altSlider setDoubleValue:cpu_altscale_factor];
|
||||
[self.altSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", cpu_altscale_factor*100]];
|
||||
if ([defaults boolForKey:kApple2AltSpeedIsMax])
|
||||
{
|
||||
cpu_altscale_factor = CPU_SCALE_FASTEST;
|
||||
[self.altMaxChoice setState:NSOnState];
|
||||
[self.altSlider setEnabled:NO];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self.altMaxChoice setState:NSOffState];
|
||||
[self.altSlider setEnabled:YES];
|
||||
}
|
||||
|
||||
#warning TODO : actually implement sound card choices
|
||||
[self.soundCardChoice deselectAllCells];
|
||||
[self.soundCardChoice selectCellAtRow:1 column:0];
|
||||
|
||||
NSInteger mode = [defaults integerForKey:kApple2ColorConfig];
|
||||
if (! ((mode >= COLOR_NONE) && (mode < NUM_COLOROPTS)) )
|
||||
{
|
||||
mode = COLOR_NONE;
|
||||
}
|
||||
[self.colorChoice selectItemAtIndex:mode];
|
||||
color_mode = (color_mode_t)mode;
|
||||
|
||||
mode = [defaults integerForKey:kApple2JoystickConfig];
|
||||
if (! ((mode >= JOY_PCJOY) && (mode < NUM_JOYOPTS)) )
|
||||
{
|
||||
mode = JOY_PCJOY;
|
||||
}
|
||||
joy_mode = (joystick_mode_t)mode;
|
||||
[self.joystickChoice selectItemAtIndex:mode];
|
||||
|
||||
#ifdef KEYPAD_JOYSTICK
|
||||
joy_auto_recenter = [defaults integerForKey:kApple2JoystickAutoRecenter];
|
||||
[self.joystickRecenter setState:joy_auto_recenter ? NSOnState : NSOffState];
|
||||
joy_step = [defaults integerForKey:kApple2JoystickStep];
|
||||
if (!joy_step)
|
||||
{
|
||||
joy_step = 1;
|
||||
}
|
||||
[self.joystickStepLabel setIntegerValue:joy_step];
|
||||
[self.joystickStepper setIntegerValue:joy_step];
|
||||
#endif
|
||||
|
||||
joy_clip_to_radius = [defaults boolForKey:kApple2JoystickClipToRadius];
|
||||
[self.joystickClipToRadius setState:joy_clip_to_radius ? NSOnState : NSOffState];
|
||||
|
||||
[self _setupJoystickUI];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(drawJoystickCalibration:) name:(NSString *)kDrawTimerNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)_savePrefs
|
||||
{
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults setBool:YES forKey:kApple2SavedPrefs];
|
||||
[defaults setDouble:cpu_scale_factor forKey:kApple2CPUSpeed];
|
||||
[defaults setDouble:cpu_altscale_factor forKey:kApple2AltSpeed];
|
||||
[defaults setBool:([self.cpuMaxChoice state] == NSOnState) forKey:kApple2CPUSpeedIsMax];
|
||||
[defaults setBool:([self.altMaxChoice state] == NSOnState) forKey:kApple2AltSpeedIsMax];
|
||||
[defaults setInteger:color_mode forKey:kApple2ColorConfig];
|
||||
[defaults setInteger:joy_mode forKey:kApple2JoystickConfig];
|
||||
[defaults setInteger:joy_step forKey:kApple2JoystickStep];
|
||||
[defaults setBool:joy_auto_recenter forKey:kApple2JoystickAutoRecenter];
|
||||
[defaults setBool:joy_clip_to_radius forKey:kApple2JoystickClipToRadius];
|
||||
}
|
||||
|
||||
- (IBAction)sliderDidMove:(id)sender
|
||||
{
|
||||
NSSlider *slider = (NSSlider *)sender;
|
||||
double value = [slider doubleValue];
|
||||
if (slider == self.cpuSlider)
|
||||
{
|
||||
cpu_scale_factor = value;
|
||||
[self.cpuSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", value*100]];
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu_altscale_factor = value;
|
||||
[self.altSliderLabel setStringValue:[NSString stringWithFormat:@"%.0f%%", value*100]];
|
||||
}
|
||||
|
||||
timing_initialize();
|
||||
|
||||
[self _savePrefs];
|
||||
}
|
||||
|
||||
- (IBAction)peggedChoiceChanged:(id)sender
|
||||
{
|
||||
NSButton *maxButton = (NSButton *)sender;
|
||||
if (maxButton == self.cpuMaxChoice)
|
||||
{
|
||||
[self.cpuSlider setEnabled:([maxButton state] != NSOnState)];
|
||||
cpu_scale_factor = ([maxButton state] == NSOnState) ? CPU_SCALE_FASTEST : [self.cpuSlider doubleValue];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self.altSlider setEnabled:([maxButton state] != NSOnState)];
|
||||
cpu_altscale_factor = ([maxButton state] == NSOnState) ? CPU_SCALE_FASTEST : [self.altSlider doubleValue];
|
||||
}
|
||||
|
||||
timing_initialize();
|
||||
|
||||
[self _savePrefs];
|
||||
}
|
||||
|
||||
- (IBAction)colorChoiceChanged:(id)sender
|
||||
{
|
||||
NSInteger mode = [self.colorChoice indexOfSelectedItem];
|
||||
if (! ((mode >= COLOR_NONE) && (mode < NUM_COLOROPTS)) )
|
||||
{
|
||||
mode = COLOR_NONE;
|
||||
}
|
||||
color_mode = (color_mode_t)mode;
|
||||
[self _savePrefs];
|
||||
|
||||
#warning HACK TODO FIXME need to refactor video resetting procedure
|
||||
video_reset();
|
||||
video_setpage(!!(softswitches & SS_SCREEN));
|
||||
video_redraw();
|
||||
}
|
||||
|
||||
- (IBAction)soundCardChoiceChanged:(id)sender
|
||||
{
|
||||
#warning TODO : make soundcard configurable at runtime
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Joystick preferences
|
||||
|
||||
- (void)_setupJoystickUI
|
||||
{
|
||||
[self.joystickRecenter setHidden:(joy_mode == JOY_PCJOY)];
|
||||
[self.joystickClipToRadius setHidden:(joy_mode != JOY_PCJOY)];
|
||||
[self.joystickStepLabel setHidden:(joy_mode == JOY_PCJOY)];
|
||||
[self.joystickStepper setHidden:(joy_mode == JOY_PCJOY)];
|
||||
[self.joystickStepperLabel setHidden:(joy_mode == JOY_PCJOY)];
|
||||
[self.joystickKPadNotes setHidden:(joy_mode == JOY_PCJOY)];
|
||||
[self.joystickDeviceNotes setHidden:(joy_mode != JOY_PCJOY)];
|
||||
}
|
||||
|
||||
- (IBAction)joystickChoiceChanged:(id)sender
|
||||
{
|
||||
NSInteger mode = [self.joystickChoice indexOfSelectedItem];
|
||||
if (! ((mode >= JOY_PCJOY) && (mode < NUM_JOYOPTS)) )
|
||||
{
|
||||
mode = JOY_PCJOY;
|
||||
}
|
||||
joy_mode = (joystick_mode_t)mode;
|
||||
[self _setupJoystickUI];
|
||||
[self _savePrefs];
|
||||
}
|
||||
|
||||
- (IBAction)autoRecenterChoiceChanged:(id)sender
|
||||
{
|
||||
joy_auto_recenter = ([self.joystickRecenter state] == NSOnState);
|
||||
[self _savePrefs];
|
||||
}
|
||||
|
||||
- (IBAction)clipToRadiusChoiceChanged:(id)sender
|
||||
{
|
||||
joy_clip_to_radius = ([self.joystickClipToRadius state] == NSOnState);
|
||||
[self _savePrefs];
|
||||
}
|
||||
|
||||
- (IBAction)stepValueChanged:(id)sender
|
||||
{
|
||||
joy_step = [self.joystickStepper intValue];
|
||||
[self.joystickStepLabel setIntegerValue:joy_step];
|
||||
[self _savePrefs];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma Joystick calibration
|
||||
|
||||
- (void)drawJoystickCalibration:(NSNotification *)notification
|
||||
{
|
||||
if (![self.joystickCalibrationView isHidden])
|
||||
{
|
||||
[self.joystickCalibrationView setNeedsDisplay:YES];
|
||||
[self.button0Pressed setHidden:!(joy_button0)];
|
||||
[self.button1Pressed setHidden:!(joy_button1)];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)flagsChanged:(NSEvent*)event
|
||||
{
|
||||
// NOTE : yay, awesome! checking for ([event modifierFlags] & NSAlternateKeyMask) does not work properly if both were pressed and then one ALT key is unpressed ... kudoes to Apple for an excellent key-handling API /sarc
|
||||
static BOOL leftAltEngaged = NO;
|
||||
static BOOL rightAltEngaged = NO;
|
||||
switch ([event keyCode])
|
||||
{
|
||||
case ALT_LT:
|
||||
leftAltEngaged = !leftAltEngaged;
|
||||
c_keys_handle_input(SCODE_L_ALT, /*pressed:*/leftAltEngaged, /*cooked:*/0);
|
||||
break;
|
||||
case ALT_RT:
|
||||
rightAltEngaged = !rightAltEngaged;
|
||||
c_keys_handle_input(SCODE_R_ALT, /*pressed:*/rightAltEngaged, /*cooked:*/0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!([event modifierFlags] & NSAlternateKeyMask))
|
||||
{
|
||||
// But we can trust the system state if no alt modifier exists ... this resets b0rken edge cases
|
||||
leftAltEngaged = NO;
|
||||
rightAltEngaged = NO;
|
||||
}
|
||||
[self.button0Pressed setHidden:!(joy_button0)];
|
||||
[self.button1Pressed setHidden:!(joy_button1)];
|
||||
}
|
||||
|
||||
- (void)_handleKeyEvent:(NSEvent *)event pressed:(BOOL)pressed
|
||||
{
|
||||
unichar c = [[event charactersIgnoringModifiers] characterAtIndex:0];
|
||||
int scode = (int)c;
|
||||
switch (scode)
|
||||
{
|
||||
case NSUpArrowFunctionKey:
|
||||
c_keys_handle_input(SCODE_U, pressed, /*cooked:*/0);
|
||||
break;
|
||||
case NSDownArrowFunctionKey:
|
||||
c_keys_handle_input(SCODE_D, pressed, /*cooked:*/0);
|
||||
break;
|
||||
case NSLeftArrowFunctionKey:
|
||||
c_keys_handle_input(SCODE_L, pressed, /*cooked:*/0);
|
||||
break;
|
||||
case NSRightArrowFunctionKey:
|
||||
c_keys_handle_input(SCODE_R, pressed, /*cooked:*/0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)keyUp:(NSEvent *)event
|
||||
{
|
||||
[self _handleKeyEvent:event pressed:NO];
|
||||
|
||||
// Allow other character to be handled (or not and beep)
|
||||
//[super keyDown:event];
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent *)event
|
||||
{
|
||||
[self _handleKeyEvent:event pressed:YES];
|
||||
|
||||
// Allow other character to be handled (or not and beep)
|
||||
//[super keyDown:event];
|
||||
}
|
||||
|
||||
@end
|
16
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindow.h
Normal file
16
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindow.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2013-2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface EmulatorWindow : NSWindow
|
||||
|
||||
@end
|
26
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindow.m
Normal file
26
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindow.m
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2013-2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#import "EmulatorWindow.h"
|
||||
|
||||
@implementation EmulatorWindow
|
||||
|
||||
- (void)keyUp:(NSEvent *)event
|
||||
{
|
||||
[[self windowController] keyUp:event];
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent *)event
|
||||
{
|
||||
[[self windowController] keyDown:event];
|
||||
}
|
||||
|
||||
@end
|
29
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindowController.h
Normal file
29
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindowController.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2013-2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
// Based on sample code from https://developer.apple.com/library/mac/samplecode/GLEssentials/Introduction/Intro.html
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "EmulatorGLView.h"
|
||||
|
||||
#define CAPS_LOCK 0x39
|
||||
#define SHIFT_LT 0x38
|
||||
#define SHIFT_RT 0x3c
|
||||
#define CTRL_LT 0x3b
|
||||
#define CTRL_RT 0x3e
|
||||
#define ALT_LT 0x3a
|
||||
#define ALT_RT 0x3d
|
||||
|
||||
extern const NSString *kDrawTimerNotification;
|
||||
|
||||
@interface EmulatorWindowController : NSWindowController
|
||||
|
||||
@end
|
404
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindowController.m
Normal file
404
Apple2Mac/Apple2Mac/Classes/OSX/EmulatorWindowController.m
Normal file
@ -0,0 +1,404 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2013-2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
// Based on sample code from https://developer.apple.com/library/mac/samplecode/GLEssentials/Introduction/Intro.html
|
||||
|
||||
#import "EmulatorWindowController.h"
|
||||
#import "EmulatorFullscreenWindow.h"
|
||||
#import "common.h"
|
||||
|
||||
@interface EmulatorWindowController ()
|
||||
|
||||
@property (nonatomic, assign) BOOL paused;
|
||||
|
||||
@property (assign) IBOutlet EmulatorGLView *view;
|
||||
@property (assign) IBOutlet NSWindow *disksWindow;
|
||||
@property (assign) IBOutlet NSWindow *prefsWindow;
|
||||
@property (assign) IBOutlet NSMenuItem *pauseMenuItem;
|
||||
@property (assign) IBOutlet NSToolbar *toolBar;
|
||||
@property (assign) IBOutlet NSToolbarItem *pauseItem;
|
||||
@property (assign) IBOutlet NSToolbarItem *disk1Item;
|
||||
@property (assign) IBOutlet NSToolbarItem *disk2Item;
|
||||
@property (nonatomic, retain) EmulatorFullscreenWindow *fullscreenWindow;
|
||||
@property (nonatomic, retain) NSWindow *standardWindow;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation EmulatorWindowController
|
||||
|
||||
@synthesize paused = _paused;
|
||||
@synthesize fullscreenWindow = _fullscreenWindow;
|
||||
@synthesize standardWindow = _standardWindow;
|
||||
|
||||
- (id)initWithWindow:(NSWindow *)window
|
||||
{
|
||||
self = [super initWithWindow:window];
|
||||
|
||||
if (self)
|
||||
{
|
||||
// Initialize to nil since it indicates app is not fullscreen
|
||||
self.fullscreenWindow = nil;
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowWillClose:) name:NSWindowWillCloseNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowWillOpen:) name:NSWindowDidBecomeKeyNotification object:nil];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
#warning TODO FIXME ... probably should exit emulator if this gets invoked ...
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (IBAction)reboot:(id)sender
|
||||
{
|
||||
[[self disksWindow] close];
|
||||
cpu65_reboot();
|
||||
}
|
||||
|
||||
- (IBAction)showDisksWindow:(id)sender
|
||||
{
|
||||
if (self.fullscreenWindow)
|
||||
{
|
||||
[self toggleFullScreen:nil];
|
||||
[self.standardWindow setFrame:[[NSScreen mainScreen] frame] display:YES];
|
||||
}
|
||||
[self.disksWindow makeKeyAndOrderFront:sender];
|
||||
}
|
||||
|
||||
- (IBAction)showPreferences:(id)sender
|
||||
{
|
||||
if (self.fullscreenWindow)
|
||||
{
|
||||
[self toggleFullScreen:nil];
|
||||
[self.standardWindow setFrame:[[NSScreen mainScreen] frame] display:YES];
|
||||
}
|
||||
[self.prefsWindow makeKeyAndOrderFront:sender];
|
||||
}
|
||||
|
||||
- (IBAction)toggleFullScreen:(id)sender
|
||||
{
|
||||
if (self.fullscreenWindow)
|
||||
{
|
||||
[NSCursor unhide];
|
||||
[self goWindow];
|
||||
}
|
||||
else
|
||||
{
|
||||
[NSCursor hide];
|
||||
[self goFullscreen];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)toggleCPUSpeed:(id)sender
|
||||
{
|
||||
cpu_pause();
|
||||
timing_toggleCPUSpeed();
|
||||
if (video_backend && video_backend->animation_showCPUSpeed)
|
||||
{
|
||||
video_backend->animation_showCPUSpeed();
|
||||
}
|
||||
cpu_resume();
|
||||
}
|
||||
|
||||
- (IBAction)togglePause:(id)sender
|
||||
{
|
||||
NSAssert(pthread_main_np(), @"Pause emulation called from non-main thread");
|
||||
self.paused = !_paused;
|
||||
}
|
||||
|
||||
- (void)setPaused:(BOOL)paused
|
||||
{
|
||||
if (_paused == paused)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_paused = paused;
|
||||
if (paused)
|
||||
{
|
||||
[[self pauseMenuItem] setTitle:@"Resume Emulation"];
|
||||
[[self pauseItem] setImage:[NSImage imageNamed:@"Run"]];
|
||||
[[self pauseItem] setLabel:@"Paused"];
|
||||
cpu_pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
[[self pauseMenuItem] setTitle:@"Pause Emulation"];
|
||||
[[self pauseItem] setImage:[NSImage imageNamed:@"Stop"]];
|
||||
[[self pauseItem] setLabel:@"Running"];
|
||||
cpu_resume();
|
||||
}
|
||||
if (video_backend && video_backend->animation_showPaused)
|
||||
{
|
||||
video_backend->animation_showPaused();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)windowWillOpen:(NSNotification *)notification
|
||||
{
|
||||
if ((self.prefsWindow == notification.object) || (self.disksWindow == notification.object))
|
||||
{
|
||||
self.paused = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)windowWillClose:(NSNotification *)notification
|
||||
{
|
||||
if (self.prefsWindow == notification.object)
|
||||
{
|
||||
self.paused = [self.disksWindow isVisible];
|
||||
}
|
||||
if (self.disksWindow == notification.object)
|
||||
{
|
||||
self.paused = [self.prefsWindow isVisible];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)goFullscreen
|
||||
{
|
||||
// If app is already fullscreen...
|
||||
if (self.fullscreenWindow)
|
||||
{
|
||||
//...don't do anything
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate a new fullscreen window
|
||||
self.fullscreenWindow = [[[EmulatorFullscreenWindow alloc] init] autorelease];
|
||||
|
||||
// Resize the view to screensize
|
||||
NSRect viewRect = [self.fullscreenWindow frame];
|
||||
|
||||
// Set the view to the size of the fullscreen window
|
||||
[self.view setFrameSize: viewRect.size];
|
||||
|
||||
// Set the view in the fullscreen window
|
||||
[self.fullscreenWindow setContentView:self.view];
|
||||
|
||||
self.standardWindow = [self window];
|
||||
|
||||
// Hide non-fullscreen window so it doesn't show up when switching out
|
||||
// of this app (i.e. with CMD-TAB)
|
||||
[self.standardWindow orderOut:self];
|
||||
|
||||
// Set controller to the fullscreen window so that all input will go to
|
||||
// this controller (self)
|
||||
[self setWindow:self.fullscreenWindow];
|
||||
|
||||
// Show the window and make it the key window for input
|
||||
[self.fullscreenWindow makeKeyAndOrderFront:self];
|
||||
}
|
||||
|
||||
- (void)goWindow
|
||||
{
|
||||
// If controller doesn't have a full screen window...
|
||||
if (self.fullscreenWindow == nil)
|
||||
{
|
||||
//...app is already windowed so don't do anything
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the rectangle of the original window
|
||||
NSRect viewRect = [self.standardWindow frame];
|
||||
|
||||
// Set the view rect to the new size
|
||||
[self.view setFrame:viewRect];
|
||||
|
||||
// Set controller to the standard window so that all input will go to
|
||||
// this controller (self)
|
||||
[self setWindow:self.standardWindow];
|
||||
|
||||
// Set the content of the orginal window to the view
|
||||
[[self window] setContentView:self.view];
|
||||
|
||||
// Show the window and make it the key window for input
|
||||
[[self window] makeKeyAndOrderFront:self];
|
||||
|
||||
// Release/nilify fullscreenWindow
|
||||
self.fullscreenWindow = nil;
|
||||
}
|
||||
|
||||
- (void)flagsChanged:(NSEvent*)event
|
||||
{
|
||||
static BOOL modified_caps_lock = NO;
|
||||
switch ([event keyCode])
|
||||
{
|
||||
case CAPS_LOCK:
|
||||
{
|
||||
if ([event modifierFlags] & NSAlphaShiftKeyMask)
|
||||
{
|
||||
modified_caps_lock = YES;
|
||||
caps_lock = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
caps_lock = false;
|
||||
}
|
||||
}
|
||||
|
||||
case SHIFT_LT:
|
||||
c_keys_handle_input(SCODE_L_SHIFT, ([event modifierFlags] & NSShiftKeyMask), 0);
|
||||
break;
|
||||
|
||||
case SHIFT_RT:
|
||||
c_keys_handle_input(SCODE_R_SHIFT, ([event modifierFlags] & NSShiftKeyMask), 0);
|
||||
break;
|
||||
|
||||
case CTRL_LT:
|
||||
c_keys_handle_input(SCODE_L_CTRL, ([event modifierFlags] & NSControlKeyMask), 0);
|
||||
break;
|
||||
|
||||
case CTRL_RT:
|
||||
c_keys_handle_input(SCODE_R_CTRL, ([event modifierFlags] & NSControlKeyMask), 0);
|
||||
break;
|
||||
|
||||
case ALT_LT:
|
||||
c_keys_handle_input(SCODE_L_ALT, ([event modifierFlags] & NSAlternateKeyMask), 0);
|
||||
break;
|
||||
|
||||
case ALT_RT:
|
||||
c_keys_handle_input(SCODE_R_ALT, ([event modifierFlags] & NSAlternateKeyMask), 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_handleKeyEvent:(NSEvent *)event pressed:(BOOL)pressed
|
||||
{
|
||||
unichar c = [[event charactersIgnoringModifiers] characterAtIndex:0];
|
||||
int scode = (int)c;
|
||||
|
||||
int cooked = 0;
|
||||
switch (scode)
|
||||
{
|
||||
case 0x1b:
|
||||
scode = SCODE_ESC;
|
||||
break;
|
||||
|
||||
case NSUpArrowFunctionKey:
|
||||
scode = SCODE_U;
|
||||
break;
|
||||
case NSDownArrowFunctionKey:
|
||||
scode = SCODE_D;
|
||||
break;
|
||||
case NSLeftArrowFunctionKey:
|
||||
scode = SCODE_L;
|
||||
break;
|
||||
case NSRightArrowFunctionKey:
|
||||
scode = SCODE_R;
|
||||
break;
|
||||
|
||||
case NSF1FunctionKey:
|
||||
scode = SCODE_F1;
|
||||
break;
|
||||
case NSF2FunctionKey:
|
||||
scode = SCODE_F2;
|
||||
break;
|
||||
case NSF3FunctionKey:
|
||||
scode = SCODE_F3;
|
||||
break;
|
||||
case NSF4FunctionKey:
|
||||
scode = SCODE_F4;
|
||||
break;
|
||||
case NSF5FunctionKey:
|
||||
scode = SCODE_F5;
|
||||
break;
|
||||
case NSF6FunctionKey:
|
||||
scode = SCODE_F6;
|
||||
break;
|
||||
case NSF7FunctionKey:
|
||||
scode = SCODE_F7;
|
||||
break;
|
||||
case NSF8FunctionKey:
|
||||
scode = SCODE_F8;
|
||||
break;
|
||||
case NSF9FunctionKey:
|
||||
scode = SCODE_F9;
|
||||
break;
|
||||
case NSF10FunctionKey:
|
||||
scode = SCODE_F10;
|
||||
break;
|
||||
case NSF11FunctionKey:
|
||||
scode = SCODE_F11;
|
||||
break;
|
||||
case NSF12FunctionKey:
|
||||
scode = SCODE_F12;
|
||||
break;
|
||||
|
||||
case NSInsertFunctionKey:
|
||||
scode = SCODE_INS;
|
||||
break;
|
||||
case NSDeleteFunctionKey:
|
||||
scode = SCODE_DEL;
|
||||
break;
|
||||
case NSHomeFunctionKey:
|
||||
scode = SCODE_HOME;
|
||||
break;
|
||||
case NSEndFunctionKey:
|
||||
scode = SCODE_END;
|
||||
break;
|
||||
|
||||
case NSPageUpFunctionKey:
|
||||
scode = SCODE_PGUP;
|
||||
break;
|
||||
case NSPageDownFunctionKey:
|
||||
scode = SCODE_PGDN;
|
||||
break;
|
||||
|
||||
case NSPrintScreenFunctionKey:
|
||||
scode = SCODE_PRNT;
|
||||
break;
|
||||
case NSPauseFunctionKey:
|
||||
scode = SCODE_PAUSE;
|
||||
break;
|
||||
case NSBreakFunctionKey:
|
||||
scode = SCODE_BRK;
|
||||
break;
|
||||
|
||||
default:
|
||||
if ([event modifierFlags] & NSControlKeyMask)
|
||||
{
|
||||
scode = c_keys_ascii_to_scancode(scode);
|
||||
cooked = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cooked = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
c_keys_handle_input(scode, pressed, cooked);
|
||||
}
|
||||
|
||||
- (void)keyUp:(NSEvent *)event
|
||||
{
|
||||
[self _handleKeyEvent:event pressed:NO];
|
||||
|
||||
// Allow other character to be handled (or not and beep)
|
||||
//[super keyDown:event];
|
||||
}
|
||||
|
||||
- (void)keyDown:(NSEvent *)event
|
||||
{
|
||||
[self _handleKeyEvent:event pressed:YES];
|
||||
|
||||
// Allow other character to be handled (or not and beep)
|
||||
//[super keyDown:event];
|
||||
}
|
||||
|
||||
@end
|
6
Apple2Mac/Apple2Mac/Images.xcassets/Contents.json
Normal file
6
Apple2Mac/Apple2Mac/Images.xcassets/Contents.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
21
Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/Contents.json
vendored
Normal file
21
Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "StepForwardNormalBlue.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/StepForwardNormalBlue.png
vendored
Normal file
BIN
Apple2Mac/Apple2Mac/Images.xcassets/Run.imageset/StepForwardNormalBlue.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
21
Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/Contents.json
vendored
Normal file
21
Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Stop1NormalBlue.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/Stop1NormalBlue.png
vendored
Normal file
BIN
Apple2Mac/Apple2Mac/Images.xcassets/Stop.imageset/Stop1NormalBlue.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
29
Apple2Mac/Apple2Mac/fr.lproj/Credits.rtf
Normal file
29
Apple2Mac/Apple2Mac/fr.lproj/Credits.rtf
Normal file
@ -0,0 +1,29 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf210
|
||||
{\fonttbl\f0\fnil\fcharset0 Menlo-Bold;\f1\fnil\fcharset0 Menlo-Regular;\f2\fnil\fcharset0 Menlo-Italic;
|
||||
}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
\vieww9600\viewh8400\viewkind0
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl216\slmult1\qc
|
||||
|
||||
\f0\b\fs24 \cf0 Authors\
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl216\slmult1\pardirnatural\qc
|
||||
|
||||
\f1\b0 \cf0 Aaron Culliney\
|
||||
and other contributors\
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl120\slmult1\pardirnatural\qc
|
||||
\cf0 \
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl216\slmult1\pardirnatural\qc
|
||||
|
||||
\f0\b \cf0 Web Resources
|
||||
\f1\b0 \
|
||||
|
||||
\f2\i ftp.apple.asimov.net
|
||||
\f1\i0 and elsewhere\
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl120\slmult1\pardirnatural\qc
|
||||
\cf0 \
|
||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\sl216\slmult1\pardirnatural\qc
|
||||
|
||||
\f0\b \cf0 Special thanks to
|
||||
\f1\b0 \
|
||||
Tom Charlesworth\
|
||||
and the AppleWin project}
|
2
Apple2Mac/Apple2Mac/fr.lproj/InfoPlist.strings
Normal file
2
Apple2Mac/Apple2Mac/fr.lproj/InfoPlist.strings
Normal file
@ -0,0 +1,2 @@
|
||||
/* Localized versions of Info.plist keys */
|
||||
|
1065
Apple2Mac/Apple2Mac/fr.lproj/MainMenu.xib
Normal file
1065
Apple2Mac/Apple2Mac/fr.lproj/MainMenu.xib
Normal file
File diff suppressed because it is too large
Load Diff
36
Apple2Mac/Apple2Mac/main.m
Normal file
36
Apple2Mac/Apple2Mac/main.m
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Apple // emulator for *ix
|
||||
*
|
||||
* This software package is subject to the GNU General Public License
|
||||
* version 3 or later (your choice) as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Copyright 2014, 2015 Aaron Culliney
|
||||
*
|
||||
*/
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <UIKit/UIKit.h>
|
||||
#else
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
||||
|
||||
extern int argc;
|
||||
extern const char **argv;
|
||||
|
||||
int main(int argc_, const char *argv_[])
|
||||
{
|
||||
int retVal = 1;
|
||||
argc = argc_;
|
||||
argv = argv_;
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
@autoreleasepool {
|
||||
retVal = UIApplicationMain(argc, argv, nil, nil);
|
||||
}
|
||||
#else
|
||||
retVal = NSApplicationMain(argc, argv);
|
||||
#endif
|
||||
|
||||
return retVal;
|
||||
}
|
Loading…
Reference in New Issue
Block a user