Initials changes

Added NSToolbar and French Localization
This commit is contained in:
jvernet 2015-12-22 19:57:36 +01:00 committed by Aaron Culliney
parent 40129d9a14
commit f4258ade45
30 changed files with 3620 additions and 569 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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>

View 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

View File

@ -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>

View File

@ -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>

View 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

View 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

View 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

View 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

View 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

View 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

View 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 2014, 2015 Aaron Culliney
*
*/
#import <Cocoa/Cocoa.h>
@interface EmulatorJoystickCalibrationView : NSView
@end

View File

@ -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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View 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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View 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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View 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}

View File

@ -0,0 +1,2 @@
/* Localized versions of Info.plist keys */

File diff suppressed because it is too large Load Diff

View 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;
}