2019-07-26 05:51:36 +00:00
//
// V i e w C o n t r o l l e r . s w i f t
2020-07-13 17:23:33 +00:00
// S t e v e ] [
2019-07-26 05:51:36 +00:00
//
// C r e a t e d b y T a m a s R u d n a i o n 7 / 2 5 / 1 9 .
2020-07-13 17:16:37 +00:00
// C o p y r i g h t © 2 0 1 9 , 2 0 2 0 T a m a s R u d n a i . A l l r i g h t s r e s e r v e d .
2020-07-13 17:10:33 +00:00
//
// T h i s f i l e i s p a r t o f S t e v e ] [ - - T h e A p p l e ] [ E m u l a t o r .
//
// S t e v e ] [ i s f r e e s o f t w a r e : y o u c a n r e d i s t r i b u t e i t a n d / o r m o d i f y
// i t u n d e r t h e t e r m s o f t h e G N U G e n e r a l P u b l i c L i c e n s e a s p u b l i s h e d b y
// t h e F r e e S o f t w a r e F o u n d a t i o n , e i t h e r v e r s i o n 3 o f t h e L i c e n s e , o r
// ( a t y o u r o p t i o n ) a n y l a t e r v e r s i o n .
//
// S t e v e ] [ i s d i s t r i b u t e d i n t h e h o p e t h a t i t w i l l b e u s e f u l ,
// b u t W I T H O U T A N Y W A R R A N T Y ; w i t h o u t e v e n t h e i m p l i e d w a r r a n t y o f
// M E R C H A N T A B I L I T Y o r F I T N E S S F O R A P A R T I C U L A R P U R P O S E . S e e t h e
// G N U G e n e r a l P u b l i c L i c e n s e f o r m o r e d e t a i l s .
//
// Y o u s h o u l d h a v e r e c e i v e d a c o p y o f t h e G N U G e n e r a l P u b l i c L i c e n s e
// a l o n g w i t h S t e v e ] [ . I f n o t , s e e < h t t p s : / / w w w . g n u . o r g / l i c e n s e s / > .
2019-07-26 05:51:36 +00:00
//
2020-01-28 06:54:03 +00:00
2019-07-26 05:51:36 +00:00
import Cocoa
2024-01-06 15:11:52 +00:00
// i m p o r t A V F o u n d a t i o n
// i m p o r t M e t a l
//
// v a r d e v i c e : M T L D e v i c e !
// v a r m e t a l L a y e r : C A M e t a l L a y e r !
// v a r v e r t e x B u f f e r : M T L B u f f e r !
// v a r p i p e l i n e S t a t e : M T L R e n d e r P i p e l i n e S t a t e !
// v a r c o m m a n d Q u e u e : M T L C o m m a n d Q u e u e !
// / / v a r t i m e r : C A D i s p l a y L i n k !
2020-02-07 08:40:31 +00:00
2019-07-26 05:51:36 +00:00
2020-01-28 06:54:03 +00:00
let K : Double = 1000.0
let M : Double = ( K * K )
let G : Double = ( M * K )
let T : Double = ( G * K )
let KB : Double = 1024.0
let MB : Double = ( KB * KB )
let GB : Double = ( MB * KB )
let TB : Double = ( GB * KB )
2020-06-21 05:14:39 +00:00
let colorWhite = NSColor . init ( red : 0.9296875 , green : 0.9296875 , blue : 0.9296875 , alpha : 1 )
let colorGreen = NSColor . init ( red : 0.16796875 , green : 0.84375 , blue : 0.2890625 , alpha : 1 )
let colorOrange = NSColor . init ( red : 1 , green : 0.38671875 , blue : 0.0078125 , alpha : 1 )
var monoColor = colorGreen ;
2024-01-06 15:11:52 +00:00
// v a r s p k _ u p : A V A u d i o P l a y e r ?
// v a r s p k _ d n : A V A u d i o P l a y e r ?
//
// @ _ c d e c l ( " V i e w C o n t r o l l e r _ s p k _ u p _ p l a y " )
// f u n c s p k _ u p _ p l a y ( ) {
// s p k _ u p ? . s t o p ( )
// s p k _ d n ? . s t o p ( )
// s p k _ u p ? . p l a y ( )
// }
//
// @ _ c d e c l ( " V i e w C o n t r o l l e r _ s p k _ d n _ p l a y " )
// f u n c s p k _ d n _ p l a y ( ) {
// s p k _ u p ? . s t o p ( )
// s p k _ d n ? . s t o p ( )
// s p k _ d n ? . p l a y ( )
// }
2020-02-07 08:40:31 +00:00
2024-01-06 15:11:52 +00:00
#if METAL_YES
import Metal
#endif
2019-11-28 04:27:32 +00:00
2020-04-27 14:26:04 +00:00
class ViewController : NSViewController {
2019-07-26 05:51:36 +00:00
2024-01-06 15:11:52 +00:00
static var shared : ViewController ? = nil
var displayLink : CVDisplayLink ?
@IBOutlet var monitorView : MonitorView !
2020-08-02 22:00:42 +00:00
@IBOutlet weak var textDisplayScroller : NSScrollView !
@IBOutlet var textDisplay : NSTextView !
2019-09-17 09:12:05 +00:00
@IBOutlet weak var speedometer : NSTextFieldCell !
2020-05-29 15:50:47 +00:00
@IBOutlet weak var lores : LoRes !
2019-11-28 04:27:32 +00:00
@IBOutlet weak var hires : HiRes !
2020-06-11 02:11:27 +00:00
@IBOutlet weak var splashScreen : NSView !
2020-06-17 16:46:17 +00:00
@IBOutlet weak var scanLines : NSImageView !
2019-11-28 04:27:32 +00:00
2020-06-17 16:46:17 +00:00
var CRTMonitor = false
2020-06-21 01:46:26 +00:00
var ColorMonitor = true
2020-06-02 17:10:18 +00:00
var Keyboard2Joystick = true
var Mouse2Joystick = false
var MouseInterface = true
2019-09-17 09:12:05 +00:00
2019-09-10 07:00:00 +00:00
// s t a t i c l e t c h a r C o n v S t r : S t r i n g =
// " @ 🄰 🄱 🄲 🄳 🄴 🄵 🄶 🄷 🄸 🄹 🄺 🄻 🄼 🄽 🄾 🄿 🅀 🅁 🅂 🅃 🅄 🅅 🅆 🅇 🅈 🅉 [ \ \ ] ^ _ ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " +
// " @ 🅰 🅱 🅲 🅳 🅴 🅵 🅶 🅷 🅸 🅹 🅺 🅻 🅼 🅽 🅾 🅿 🆀 🆁 🆂 🆃 🆄 🆅 🆆 🆇 🆈 🆉 [ \ \ ] ^ _ ⬛ ︎ ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " + / / F L
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " +
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ ? "
2019-09-19 09:27:56 +00:00
// s t a t i c l e t c h a r C o n v S t r : S t r i n g =
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " +
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ ░ ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " + / / F L
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ \ u { E 0 A 0 } ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " +
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ ? "
// s t a t i c l e t c h a r C o n v S t r : S t r i n g =
// " \ u { E 1 4 0 } \ u { E 1 4 1 } \ u { E 1 4 2 } \ u { E 1 4 3 } \ u { E 1 4 4 } \ u { E 1 4 5 } \ u { E 1 4 6 } \ u { E 1 4 7 } \ u { E 1 4 8 } \ u { E 1 4 9 } \ u { E 1 4 A } \ u { E 1 4 B } \ u { E 1 4 C } \ u { E 1 4 D } \ u { E 1 4 E } \ u { E 1 4 F } \ u { E 1 5 0 } \ u { E 1 5 1 } \ u { E 1 5 2 } \ u { E 1 5 3 } \ u { E 1 5 4 } \ u { E 1 5 5 } \ u { E 1 5 6 } \ u { E 1 5 7 } \ u { E 1 5 8 } \ u { E 1 5 9 } \ u { E 1 5 A } \ u { E 1 5 B } \ u { E 1 5 C } \ u { E 1 5 D } \ u { E 1 5 E } \ u { E 1 5 F } \ u { E 1 2 0 } \ u { E 1 2 1 } \ u { E 1 2 2 } \ u { E 1 2 3 } \ u { E 1 2 4 } \ u { E 1 2 5 } \ u { E 1 2 6 } \ u { E 1 2 7 } \ u { E 1 2 8 } \ u { E 1 2 9 } \ u { E 1 2 A } \ u { E 1 2 B } \ u { E 1 2 C } \ u { E 1 2 D } \ u { E 1 2 E } \ u { E 1 2 F } \ u { E 1 3 0 } \ u { E 1 3 1 } \ u { E 1 3 2 } \ u { E 1 3 3 } \ u { E 1 3 4 } \ u { E 1 3 5 } \ u { E 1 3 6 } \ u { E 1 3 7 } \ u { E 1 3 8 } \ u { E 1 3 9 } \ u { E 1 3 A } \ u { E 1 3 B } \ u { E 1 3 C } \ u { E 1 3 D } \ u { E 1 3 E } \ u { E 1 3 F } " +
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ ░ ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " + / / F L
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ \ u { E 0 A 0 } ! \ " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? " +
// " @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ ? "
2019-09-09 02:55:19 +00:00
2024-01-06 15:11:52 +00:00
// TODO: O n 8 0 n c o l m o d e n o f l a s h + s m a l l c a p s a r e i n v e r s e d o n t h e F l a s h m a p
static let charConvStrFlashOff40 : String =
// I N V E R S E
2019-09-19 09:27:56 +00:00
" \ u{E140} \ u{E141} \ u{E142} \ u{E143} \ u{E144} \ u{E145} \ u{E146} \ u{E147} \ u{E148} \ u{E149} \ u{E14A} \ u{E14B} \ u{E14C} \ u{E14D} \ u{E14E} \ u{E14F} \ u{E150} \ u{E151} \ u{E152} \ u{E153} \ u{E154} \ u{E155} \ u{E156} \ u{E157} \ u{E158} \ u{E159} \ u{E15A} \ u{E15B} \ u{E15C} \ u{E15D} \ u{E15E} \ u{E15F} \ u{E120} \ u{E121} \ u{E122} \ u{E123} \ u{E124} \ u{E125} \ u{E126} \ u{E127} \ u{E128} \ u{E129} \ u{E12A} \ u{E12B} \ u{E12C} \ u{E12D} \ u{E12E} \ u{E12F} \ u{E130} \ u{E131} \ u{E132} \ u{E133} \ u{E134} \ u{E135} \ u{E136} \ u{E137} \ u{E138} \ u{E139} \ u{E13A} \ u{E13B} \ u{E13C} \ u{E13D} \ u{E13E} \ u{E13F} " +
2020-04-26 04:28:18 +00:00
2024-01-06 15:11:52 +00:00
// F L A S H
" @ABCDEFGHIJKLMNOPQRSTUVWXYZ[ \\ ]^_ ! \" #$%&'()*+,-./0123456789:;<=>? " + // F L
" @ABCDEFGHIJKLMNOPQRSTUVWXYZ[ \\ ]^_ ! \" #$%&'()*+,-./0123456789:;<=>? " +
2020-04-26 04:28:18 +00:00
2024-01-06 15:11:52 +00:00
" @ABCDEFGHIJKLMNOPQRSTUVWXYZ[ \\ ]^_`abcdefghijklmnopqrstuvwxyz{|}~ \ u{E27F} "
2019-09-19 09:27:56 +00:00
2024-01-06 15:11:52 +00:00
static let charConvStrFlashOn40 : String =
// I N V E R S E
2019-09-19 09:27:56 +00:00
" \ u{E140} \ u{E141} \ u{E142} \ u{E143} \ u{E144} \ u{E145} \ u{E146} \ u{E147} \ u{E148} \ u{E149} \ u{E14A} \ u{E14B} \ u{E14C} \ u{E14D} \ u{E14E} \ u{E14F} \ u{E150} \ u{E151} \ u{E152} \ u{E153} \ u{E154} \ u{E155} \ u{E156} \ u{E157} \ u{E158} \ u{E159} \ u{E15A} \ u{E15B} \ u{E15C} \ u{E15D} \ u{E15E} \ u{E15F} \ u{E120} \ u{E121} \ u{E122} \ u{E123} \ u{E124} \ u{E125} \ u{E126} \ u{E127} \ u{E128} \ u{E129} \ u{E12A} \ u{E12B} \ u{E12C} \ u{E12D} \ u{E12E} \ u{E12F} \ u{E130} \ u{E131} \ u{E132} \ u{E133} \ u{E134} \ u{E135} \ u{E136} \ u{E137} \ u{E138} \ u{E139} \ u{E13A} \ u{E13B} \ u{E13C} \ u{E13D} \ u{E13E} \ u{E13F} " +
2024-01-06 15:11:52 +00:00
// F L A S H
2019-09-19 09:27:56 +00:00
" \ u{E140} \ u{E141} \ u{E142} \ u{E143} \ u{E144} \ u{E145} \ u{E146} \ u{E147} \ u{E148} \ u{E149} \ u{E14A} \ u{E14B} \ u{E14C} \ u{E14D} \ u{E14E} \ u{E14F} \ u{E150} \ u{E151} \ u{E152} \ u{E153} \ u{E154} \ u{E155} \ u{E156} \ u{E157} \ u{E158} \ u{E159} \ u{E15A} \ u{E15B} \ u{E15C} \ u{E15D} \ u{E15E} \ u{E15F} \ u{E120} \ u{E121} \ u{E122} \ u{E123} \ u{E124} \ u{E125} \ u{E126} \ u{E127} \ u{E128} \ u{E129} \ u{E12A} \ u{E12B} \ u{E12C} \ u{E12D} \ u{E12E} \ u{E12F} \ u{E130} \ u{E131} \ u{E132} \ u{E133} \ u{E134} \ u{E135} \ u{E136} \ u{E137} \ u{E138} \ u{E139} \ u{E13A} \ u{E13B} \ u{E13C} \ u{E13D} \ u{E13E} \ u{E13F} " +
2020-04-26 04:28:18 +00:00
2024-01-06 15:11:52 +00:00
" @ABCDEFGHIJKLMNOPQRSTUVWXYZ[ \\ ]^_ ! \" #$%&'()*+,-./0123456789:;<=>? " +
2020-04-26 04:28:18 +00:00
2024-01-06 15:11:52 +00:00
" @ABCDEFGHIJKLMNOPQRSTUVWXYZ[ \\ ]^_`abcdefghijklmnopqrstuvwxyz{|}~ \ u{E27F} "
static let charConvStrCol80 : String =
// I N V E R S E
" \ u{E140} \ u{E141} \ u{E142} \ u{E143} \ u{E144} \ u{E145} \ u{E146} \ u{E147} \ u{E148} \ u{E149} \ u{E14A} \ u{E14B} \ u{E14C} \ u{E14D} \ u{E14E} \ u{E14F} \ u{E150} \ u{E151} \ u{E152} \ u{E153} \ u{E154} \ u{E155} \ u{E156} \ u{E157} \ u{E158} \ u{E159} \ u{E15A} \ u{E15B} \ u{E15C} \ u{E15D} \ u{E15E} \ u{E15F} \ u{E120} \ u{E121} \ u{E122} \ u{E123} \ u{E124} \ u{E125} \ u{E126} \ u{E127} \ u{E128} \ u{E129} \ u{E12A} \ u{E12B} \ u{E12C} \ u{E12D} \ u{E12E} \ u{E12F} \ u{E130} \ u{E131} \ u{E132} \ u{E133} \ u{E134} \ u{E135} \ u{E136} \ u{E137} \ u{E138} \ u{E139} \ u{E13A} \ u{E13B} \ u{E13C} \ u{E13D} \ u{E13E} \ u{E13F} " +
// I N V E R S E 2 w i t h s m a l l c a p s
" \ u{E140} \ u{E141} \ u{E142} \ u{E143} \ u{E144} \ u{E145} \ u{E146} \ u{E147} \ u{E148} \ u{E149} \ u{E14A} \ u{E14B} \ u{E14C} \ u{E14D} \ u{E14E} \ u{E14F} \ u{E150} \ u{E151} \ u{E152} \ u{E153} \ u{E154} \ u{E155} \ u{E156} \ u{E157} \ u{E158} \ u{E159} \ u{E15A} \ u{E15B} \ u{E15C} \ u{E15D} \ u{E15E} \ u{E15F} \ u{E160} \ u{E161} \ u{E162} \ u{E163} \ u{E164} \ u{E165} \ u{E166} \ u{E167} \ u{E168} \ u{E169} \ u{E16A} \ u{E16B} \ u{E16C} \ u{E16D} \ u{E16E} \ u{E16F} \ u{E170} \ u{E171} \ u{E172} \ u{E173} \ u{E174} \ u{E175} \ u{E176} \ u{E177} \ u{E178} \ u{E179} \ u{E17A} \ u{E13B} \ u{E13C} \ u{E13D} \ u{E13E} \ u{E13F} " +
2019-09-19 09:27:56 +00:00
2024-01-06 15:11:52 +00:00
" @ABCDEFGHIJKLMNOPQRSTUVWXYZ[ \\ ]^_ ! \" #$%&'()*+,-./0123456789:;<=>? " +
" @ABCDEFGHIJKLMNOPQRSTUVWXYZ[ \\ ]^_`abcdefghijklmnopqrstuvwxyz{|}~ \ u{E27F} "
static let charConvTblFlashOn40 = Array ( charConvStrFlashOn40 )
static let charConvTblFlashOff40 = Array ( charConvStrFlashOff40 )
static let charConvTblCol80 = Array ( charConvStrCol80 )
static var charConvTblFlashOn = charConvTblFlashOn40
static var charConvTblFlashOff = charConvTblFlashOff40
2019-09-22 08:31:09 +00:00
static var charConvTbl = charConvTblFlashOn
2020-04-26 07:23:05 +00:00
2024-01-06 15:11:52 +00:00
// s t a t i c v a r r o m F i l e N a m e = " A p p l e 2 e _ E n h a n c e d . r o m "
static var romFileName = " Apple2e_32k.rom "
// s t a t i c v a r r o m F i l e N a m e = " 0 7 7 - 0 0 1 9 A p p l e I I e D i a g n o s t i c C a r d - E n g l i s h . r o m "
2019-09-09 02:55:19 +00:00
2020-05-29 15:50:47 +00:00
static let textLineOfs : [ Int ] = [
2019-09-09 02:55:19 +00:00
0x000 , 0x080 , 0x100 , 0x180 , 0x200 , 0x280 , 0x300 , 0x380 , 0x028 , 0x0A8 , 0x128 , 0x1A8 ,
0x228 , 0x2A8 , 0x328 , 0x3A8 , 0x050 , 0x0D0 , 0x150 , 0x1D0 , 0x250 , 0x2D0 , 0x350 , 0x3D0
]
2020-06-04 18:37:35 +00:00
func dialogOK ( title : String , text : String ) {
let alert = NSAlert ( )
alert . messageText = title
alert . informativeText = text
alert . alertStyle = . warning
alert . addButton ( withTitle : " OK " )
alert . runModal ( )
// r e t u r n a l e r t . r u n M o d a l ( ) = = . a l e r t F i r s t B u t t o n R e t u r n
}
@objc func chk_woz_load ( err : Int32 ) {
switch ( err ) {
case WOZ_ERR_OK :
break
case WOZ_ERR_FILE_NOT_FOUND :
dialogOK ( title : " Error Loading Disk Image " , text : " File Not Found! " )
break
case WOZ_ERR_NOT_WOZ_FILE :
dialogOK ( title : " Error Loading Disk Image " , text : " File is not a WOZ image! " )
break
case WOZ_ERR_BAD_CHUNK_HDR , WOZ_ERR_BAD_DATA :
dialogOK ( title : " Error Loading Disk Image " , text : " Malformed WOZ image! " )
break
default :
dialogOK ( title : " Error Loading Disk Image " , text : " Unknown Error! ( \( err ) ) " )
break
}
}
2019-09-12 01:36:30 +00:00
var workItem : DispatchWorkItem ? = nil ;
2020-06-26 03:23:08 +00:00
@IBAction func PowerOn ( _ sender : Any ) {
2020-05-09 21:40:42 +00:00
2024-01-06 15:11:52 +00:00
#if SCHEDULER_CVDISPLAYLINK
CVDisplayLinkStop ( displayLink ! )
#else
2020-05-09 21:40:42 +00:00
upd . suspend ( )
2024-01-06 15:11:52 +00:00
#endif
2020-06-17 16:46:17 +00:00
cpuState = cpuState_inited ;
2020-06-26 03:23:08 +00:00
spkr_stopAll ( )
2020-05-09 10:39:55 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// A n i m a t e d S p l a s h S c r e e n f a d e o u t a n d ( T e x t ) M o n i t o r f a d e i n
2020-05-09 21:40:42 +00:00
hires . isHidden = true
2020-08-04 07:20:55 +00:00
lores . isHidden = true
2020-08-02 22:00:42 +00:00
// d i s p l a y F i e l d . a l p h a V a l u e = 0
// d i s p l a y F i e l d . i s H i d d e n = f a l s e
textDisplayScroller . alphaValue = 0
textDisplayScroller . isHidden = false
2020-05-09 10:39:55 +00:00
splashScreen . alphaValue = 1
splashScreen . isHidden = false
2020-05-09 21:40:42 +00:00
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 0.5 ) {
2020-05-09 10:39:55 +00:00
NSAnimationContext . runAnimationGroup ( { ( context ) in
2024-01-06 15:11:52 +00:00
context . duration = 1.0
2020-05-09 10:39:55 +00:00
// U s e t h e v a l u e y o u w a n t t o a n i m a t e t o ( N O T t h e s t a r t i n g v a l u e )
2020-08-02 22:00:42 +00:00
self . textDisplayScroller . animator ( ) . alphaValue = 1
2024-01-06 15:11:52 +00:00
self . hires . animator ( ) . alphaValue = 1
self . lores . animator ( ) . alphaValue = 1
2020-05-09 10:39:55 +00:00
self . splashScreen . animator ( ) . alphaValue = 0
} ,
completionHandler : { ( ) -> Void in
2020-08-02 22:00:42 +00:00
self . textDisplayScroller . alphaValue = 1
2024-01-06 15:11:52 +00:00
self . hires . alphaValue = 1
self . lores . alphaValue = 1
2020-05-09 10:39:55 +00:00
self . splashScreen . isHidden = true
} )
2020-05-09 21:40:42 +00:00
2020-06-24 22:44:15 +00:00
m6502_ColdReset ( Bundle . main . resourcePath ! + " /rom/ " , ViewController . romFileName )
2020-05-09 21:40:42 +00:00
2020-06-17 16:46:17 +00:00
cpuState = cpuState_running ;
2024-01-06 15:11:52 +00:00
#if SCHEDULER_CVDISPLAYLINK
CVDisplayLinkStart ( self . displayLink ! )
#else
2020-05-09 21:40:42 +00:00
self . upd . resume ( )
2024-01-06 15:11:52 +00:00
#endif
if let debugger = DebuggerWindowController . shared {
debugger . PauseButtonUpdate ( needUpdateMainToolbar : false )
}
2020-05-09 10:39:55 +00:00
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2020-02-07 08:40:31 +00:00
2019-09-19 09:27:56 +00:00
#if SPEEDTEST
if ( workItem != nil ) {
workItem ! . cancel ( ) ;
workItem = nil ;
}
else {
workItem = DispatchWorkItem {
DispatchQueue . global ( qos : . userInteractive ) . async {
// D i s p a t c h Q u e u e . g l o b a l ( q o s : . u s e r I n i t i a t e d ) . a s y n c {
// D i s p a t c h Q u e u e . g l o b a l ( q o s : . b a c k g r o u n d ) . a s y n c {
tst6502 ( )
}
}
DispatchQueue . global ( ) . async ( execute : workItem ! ) ;
}
#else
2020-04-30 14:26:46 +00:00
2020-05-09 21:40:42 +00:00
2019-09-19 09:27:56 +00:00
#endif
2019-09-09 07:27:31 +00:00
}
2020-06-26 03:23:08 +00:00
@IBAction func PowerOff ( _ sender : Any ) {
2024-01-06 15:11:52 +00:00
#if SCHEDULER_CVDISPLAYLINK
CVDisplayLinkStop ( displayLink ! )
#else
2020-06-26 03:23:08 +00:00
upd . suspend ( )
2024-01-06 15:11:52 +00:00
#endif
2020-06-26 03:23:08 +00:00
cpuState = cpuState_inited ;
spkr_stopAll ( )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// A n i m a t e d S p l a s h S c r e e n f a d e o u t a n d ( T e x t ) M o n i t o r f a d e i n
2024-01-06 15:11:52 +00:00
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 0.0 ) {
self . splashScreen . alphaValue = 0
self . splashScreen . isHidden = false
NSAnimationContext . runAnimationGroup ( { ( context ) in
context . duration = 0.5
// U s e t h e v a l u e y o u w a n t t o a n i m a t e t o ( N O T t h e s t a r t i n g v a l u e )
self . textDisplayScroller . animator ( ) . alphaValue = 0
self . hires . animator ( ) . alphaValue = 0
self . lores . animator ( ) . alphaValue = 0
self . splashScreen . animator ( ) . alphaValue = 1
} ,
completionHandler : { ( ) -> Void in
self . textDisplayScroller . alphaValue = 0
self . textDisplayScroller . isHidden = true
self . splashScreen . isHidden = false
self . hires . alphaValue = 0
self . lores . alphaValue = 0
self . hires . isHidden = true
self . lores . isHidden = true
self . splashScreen . isHidden = false
} )
}
if let debugger = DebuggerWindowController . shared {
debugger . PauseButtonUpdate ( needUpdateMainToolbar : false )
}
// h i r e s . i s H i d d e n = t r u e
// l o r e s . i s H i d d e n = t r u e
// t e x t D i s p l a y S c r o l l e r . a l p h a V a l u e = 0
// / / t e x t D i s p l a y S c r o l l e r . i s H i d d e n = f a l s e
// s p l a s h S c r e e n . a l p h a V a l u e = 1
// s p l a s h S c r e e n . i s H i d d e n = f a l s e
2020-06-26 03:23:08 +00:00
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
}
2024-01-06 15:11:52 +00:00
func debuggerShowWindow ( ) {
if let debuggerWindowController = DebuggerWindowController . shared {
DispatchQueue . main . async {
debuggerWindowController . showWindow ( self )
}
}
}
func debuggerRemoveHighlight ( ) {
if let debuggerViewController = DebuggerViewController . shared {
debuggerViewController . remove_highlight ( view : debuggerViewController . Disass_Display , line : debuggerViewController . highlighted_line_number )
}
}
func debuggerPauseUpdate ( ) {
if let debuggerViewController = DebuggerViewController . shared {
debuggerViewController . TrunDisassAddressPC ( . on )
debuggerViewController . remove_highlight ( view : debuggerViewController . Disass_Display , line : debuggerViewController . highlighted_line_number )
debuggerViewController . Update ( )
}
}
func Resume ( ) {
debuggerRemoveHighlight ( )
#if SCHEDULER_CVDISPLAYLINK
CVDisplayLinkStart ( displayLink ! )
#else
upd . resume ( )
#endif
cpuState = cpuState_running
DispatchQueue . main . async {
self . view . window ? . windowController ? . showWindow ( self )
}
if let debugger = DebuggerWindowController . shared {
debugger . PauseButtonUpdate ( )
}
}
func Pause ( ) {
#if SCHEDULER_CVDISPLAYLINK
CVDisplayLinkStop ( displayLink ! )
#else
upd . suspend ( )
#endif
cpuState = cpuState_halted
if let debugger = DebuggerWindowController . shared {
debugger . PauseButtonUpdate ( )
}
debuggerPauseUpdate ( )
}
2020-06-26 03:23:08 +00:00
@IBAction func Pause ( _ sender : Any ) {
switch ( cpuState ) {
case cpuState_halted :
2024-01-06 15:11:52 +00:00
Resume ( )
2020-06-26 03:23:08 +00:00
break
case cpuState_running :
2024-01-06 15:11:52 +00:00
Pause ( )
2020-06-26 03:23:08 +00:00
break
default :
// u p d . s u s p e n d ( )
// c p u S t a t e = c p u S t a t e _ h a l t e d
break
}
}
2019-09-09 07:27:31 +00:00
@IBAction func Reset ( _ sender : Any ) {
2020-05-03 05:39:54 +00:00
// m 6 5 0 2 . i n t e r r u p t = S O F T R E S E T ;
2020-05-03 05:35:59 +00:00
2020-05-03 05:39:54 +00:00
// l e t s a v e d _ f r m _ s e t = c l k _ 6 5 0 2 _ p e r _ f r m _ s e t ;
// c l k _ 6 5 0 2 _ p e r _ f r m _ s e t = 0
// c l k _ 6 5 0 2 _ p e r _ f r m _ m a x = 0
// / / w a i t f o r 1 m s t o a l l o w t h e s i m u l a t i o n t o h a l t
// u s l e e p ( 1 0 0 0 0 ) ;
2020-05-03 05:35:59 +00:00
softReset ( )
2020-05-03 05:39:54 +00:00
// c l k _ 6 5 0 2 _ p e r _ f r m _ s e t = s a v e d _ f r m _ s e t
2019-09-09 07:27:31 +00:00
}
2020-05-25 04:04:34 +00:00
static let textPage1Addr = 0x400
static let textPage2Addr = 0x800
2020-02-23 00:37:54 +00:00
static let textBufferSize = 0x400
2020-04-27 14:26:04 +00:00
// s t a t i c o n l y n e e d e d t o b e a b l e t o i n i t i a l i z e t h i n g s
static let textLines = 24
static let textCols = 40
static let lineEndChars = 1
// t h e s e a r e n e e d e d t o b e a b l e t o e a s y a c c e s s t o t h e s e c o n s t a n t s f r o m i n s t a n c e s
let textLines = ViewController . textLines
let textCols = ViewController . textCols
let lineEndChars = ViewController . lineEndChars
2020-02-23 00:37:54 +00:00
var frameCnt = 0
2024-01-06 15:11:52 +00:00
var flashInverted = false
2020-02-23 00:37:54 +00:00
// l e t s p a c e C h a r : C h a r a c t e r = " \ u { E 1 7 F } "
// l e t b l o c k C h a r : C h a r a c t e r = " \ u { E 0 7 F } "
2020-04-27 14:26:04 +00:00
// s t a t i c l e t s p a c e C h a r : C h a r a c t e r = " "
// s t a t i c l e t b l o c k C h a r : C h a r a c t e r = " ░ "
// s t a t i c v a r f l a s h i n g S p a c e : C h a r a c t e r = " "
2020-02-23 00:37:54 +00:00
2020-05-01 21:43:41 +00:00
let ramBufferPointer = UnsafeRawBufferPointer ( start : MEM , count : 64 * 1024 )
2020-05-27 04:13:31 +00:00
static let textPage1Pointer = UnsafeRawBufferPointer ( start : MEM + textPage1Addr , count : textBufferSize )
static let textPage2Pointer = UnsafeRawBufferPointer ( start : MEM + textPage2Addr , count : textBufferSize )
static let textIntBufferPointer = UnsafeRawBufferPointer ( start : RAM + textPage1Addr , count : textBufferSize )
static let textAuxBufferPointer = UnsafeRawBufferPointer ( start : AUX + textPage1Addr , count : textBufferSize )
2024-01-06 15:11:52 +00:00
static let textPageShadowBuffer = UnsafeMutableRawBufferPointer . allocate ( byteCount : textBufferSize , alignment : 1 )
2020-05-29 15:50:47 +00:00
// TODO: R e n d e r t e x t s c r e e n i n n a t i v e C
// s t a t i c l e t t e x t S c r e e n = U n s a f e M u t a b l e R a w P o i n t e r ( m u t a t i n g : t e s t T e x t )
2020-05-25 04:04:34 +00:00
var textBufferPointer = textPage1Pointer
2020-04-27 14:26:04 +00:00
static let textArraySize = textLines * ( textCols + lineEndChars ) + textCols * 2
2024-01-06 15:11:52 +00:00
let txtClear = [ Character ] ( repeating : " " , count : textArraySize * 2 )
2020-08-02 22:00:42 +00:00
var unicodeTextArray = [ Character ] ( repeating : " " , count : textArraySize * 2 )
2020-02-23 00:37:54 +00:00
var s = String ( )
func HexDump ( ) {
var txt : String = " "
for y in 0. . . textLines - 1 {
txt += String ( format : " %04X: " , y * 16 )
for x in 0. . . 15 {
let byte = ramBufferPointer [ y * 16 + x ]
let chr = String ( format : " %02X " , byte )
txt += chr
}
txt += " \n "
}
DispatchQueue . main . async {
2024-01-06 15:11:52 +00:00
self . textDisplay . string = txt
2020-02-23 00:37:54 +00:00
self . speedometer . stringValue = String ( format : " %0.3lf MHz " , mhz ) ;
}
}
2019-09-22 08:31:09 +00:00
// A p p l e S c r i p t K e y c o d e s
2024-01-06 15:11:52 +00:00
let leftArrowKey = 123
let rightArrowKey = 124
let upArrowKey = 126
let downArrowKey = 125
let F4FunctionKey = 118
let F5FunctionKey = 96
let F6FunctionKey = 97
let F7FunctionKey = 98
let F8FunctionKey = 100
2019-09-22 08:31:09 +00:00
2020-04-27 14:26:04 +00:00
override var acceptsFirstResponder : Bool {
2020-07-11 20:16:10 +00:00
get {
return true
}
2020-04-27 14:26:04 +00:00
}
2020-07-11 23:33:29 +00:00
func SelectAll ( ) {
2020-08-02 22:00:42 +00:00
// t e x t D i s p l a y S c r o l l e r . c u r r e n t E d i t o r ( ) ? . s e l e c t A l l ( n i l )
2024-01-06 15:11:52 +00:00
// d i s p l a y F i e l d . s e l e c t T e x t ( n i l )
textDisplay . setSelectedRange ( NSRange ( ) )
2020-07-11 23:33:29 +00:00
}
func Copy ( ) {
let pasteBoard = NSPasteboard . general
pasteBoard . clearContents ( )
// TODO: F i n d a b e t t e r w a y t o a v o i d i n d e x o u t o f r a n g e e r r o r w h e n t h e e n t i r e t e x t a r e a i s s e l e c t e d
2024-01-06 15:11:52 +00:00
let string = textDisplay . string + " "
let selectedRange = textDisplay . selectedRange ( )
if selectedRange != NSRange ( ) {
2020-07-11 23:33:29 +00:00
let startIndex = string . index ( string . startIndex , offsetBy : selectedRange . lowerBound )
let endIndex = string . index ( string . startIndex , offsetBy : selectedRange . upperBound )
let selectedString = string [ startIndex . . < endIndex ]
pasteBoard . setString ( String ( selectedString ) , forType : . string )
}
}
func Paste ( ) {
let pasteBoard = NSPasteboard . general
if let str = pasteBoard . string ( forType : . string ) {
print ( " PASTED: " , str )
DispatchQueue . global ( qos : . background ) . async {
for char in str . uppercased ( ) {
if let ascii = char . asciiValue {
// TODO: W r i t e s e p a r a t e P a s t e A c c e l e r a t o r
2024-01-06 15:11:52 +00:00
// d i s k _ a c c e l e r a t o r _ s p e e d u p ( )
kbdPaste ( ascii )
2020-07-11 23:33:29 +00:00
}
}
}
}
}
2020-04-27 14:26:04 +00:00
2024-01-06 15:11:52 +00:00
let mouseCursorHidden = true ;
let mouseCursorJoystickEmulation = NSCursor . crosshair
let mouseCursorHiddenJoystickEmulation = NSCursor . init ( image : NSImage . init ( size : NSSize ( width : 1 , height : 1 ) ) , hotSpot : NSPoint ( x : 0 , y : 0 ) )
func mouseCursor ( hide : Bool ) {
if hide {
if mouseCursorHidden {
// N S C u r s o r . h i d e ( ) i s w o r k i n g w e i r d , b e t t e r t o s e t a 1 p x t r a n s p a r e n t c u r s o r
// m o u s e C u r s o r H i d d e n J o y s t i c k E m u l a t i o n . s e t ( )
mouseCursorJoystickEmulation . set ( )
}
else {
mouseCursorJoystickEmulation . set ( )
}
}
else {
// i f m o u s e C u r s o r H i d d e n {
// N S C u r s o r . u n h i d e ( )
// }
NSCursor . arrow . set ( )
}
}
func getScreenWithMouse ( ) -> NSScreen ? {
let mouseLocation = NSEvent . mouseLocation
let screens = NSScreen . screens
let screenWithMouse = ( screens . first { NSMouseInRect ( mouseLocation , $0 . frame , false ) } )
return screenWithMouse
}
func convertPoint ( toCG point : NSPoint ) -> CGPoint {
// / C o c o a a n d C o r e G r a p h i c s ( a . k . a . Q u a r t z ) u s e d i f f e r e n t c o o r d i n a t e s y s t e m s . I n C o c o a , t h e o r i g i n i s a t t h e l o w e r l e f t o f t h e p r i m a r y s c r e e n a n d y i n c r e a s e s a s y o u g o u p . I n C o r e G r a p h i c s , t h e o r i g i n i s a t t h e t o p l e f t o f t h e p r i m a r y s c r e e n a n d y i n c r e a s e s a s y o u g o d o w n .
// / N e e d t o c o n v e r t c o o r d i n a t e s f r o m C o c o a t o C o r e G r a p h i c s
var cgpoint = view . window ! . convertPoint ( toScreen : point )
if let screen = getScreenWithMouse ( ) {
cgpoint . y = NSHeight ( screen . frame ) - cgpoint . y ;
}
return cgpoint
}
2020-07-13 04:40:08 +00:00
override func mouseMoved ( with event : NSEvent ) {
2024-01-06 15:11:52 +00:00
// p r i n t ( # f u n c t i o n )
var location = event . locationInWindow
// d i s p l a y O r i g i n = t e x t D i s p l a y S c r o l l e r . f r a m e . o r i g i n .
// p r i n t ( " m x : " , l o c a t i o n . x , " m y : " , l o c a t i o n . y )
var mouseCursorNeedsReplace = false
if location . x < 8 {
mouseCursorNeedsReplace = true
location . x = 8
}
if location . x > textDisplay . frame . width - 8 {
mouseCursorNeedsReplace = true
location . x = textDisplay . frame . width - 8
}
if location . y < 8 {
mouseCursorNeedsReplace = true
location . y = 8
}
if location . y > textDisplay . frame . height - 8 {
mouseCursorNeedsReplace = true
location . y = textDisplay . frame . height - 8
}
mouseCursor ( hide : Mouse2Joystick )
2020-07-13 04:40:08 +00:00
if ( Mouse2Joystick ) {
2024-01-06 15:11:52 +00:00
if mouseCursorNeedsReplace {
CGWarpMouseCursorPosition ( convertPoint ( toCG : location ) )
}
2020-07-13 04:40:08 +00:00
pdl_prevarr [ 0 ] = pdl_valarr [ 0 ]
2024-01-06 15:11:52 +00:00
pdl_valarr [ 0 ] = Double ( location . x / ( textDisplay . frame . width ) )
2020-07-13 04:40:08 +00:00
pdl_diffarr [ 0 ] = pdl_valarr [ 0 ] - pdl_prevarr [ 0 ]
pdl_prevarr [ 1 ] = pdl_valarr [ 1 ]
2024-01-06 15:11:52 +00:00
pdl_valarr [ 1 ] = 1 - Double ( location . y / ( textDisplay . frame . height ) )
2020-07-13 04:40:08 +00:00
pdl_diffarr [ 1 ] = pdl_valarr [ 1 ] - pdl_prevarr [ 1 ]
}
if ( MouseInterface ) {
pdl_prevarr [ 2 ] = pdl_valarr [ 2 ]
2024-01-06 15:11:52 +00:00
pdl_valarr [ 2 ] = Double ( location . x / ( textDisplay . frame . width ) )
2020-07-13 04:40:08 +00:00
pdl_diffarr [ 2 ] = pdl_valarr [ 2 ] - pdl_prevarr [ 2 ]
pdl_prevarr [ 3 ] = pdl_valarr [ 3 ]
2024-01-06 15:11:52 +00:00
pdl_valarr [ 3 ] = 1 - Double ( location . y / ( textDisplay . frame . height ) )
2020-07-13 04:40:08 +00:00
pdl_diffarr [ 3 ] = pdl_valarr [ 3 ] - pdl_prevarr [ 3 ]
}
}
2024-01-06 15:11:52 +00:00
var savedVideoMode = videoMode_t . init ( )
2019-09-09 07:27:31 +00:00
override func keyDown ( with event : NSEvent ) {
2020-06-17 16:46:17 +00:00
2024-01-06 15:11:52 +00:00
m6502 . ecoSpindown = ecoSpindown ;
2020-06-17 16:46:17 +00:00
if ( cpuMode = = cpuMode_eco ) {
cpuState = cpuState_running ;
2024-01-06 15:11:52 +00:00
#if SCHEDULER_CVDISPLAYLINK
CVDisplayLinkStart ( displayLink ! )
#else
2020-06-18 22:14:54 +00:00
upd . resume ( )
2024-01-06 15:11:52 +00:00
#endif
2020-06-17 16:46:17 +00:00
}
2020-06-06 06:16:17 +00:00
// p r i n t ( " k e y D o w n " )
2020-02-23 00:37:54 +00:00
2019-09-15 11:02:22 +00:00
// s w i t c h e v e n t . m o d i f i e r F l a g s . i n t e r s e c t i o n ( . d e v i c e I n d e p e n d e n t F l a g s M a s k ) {
// c a s e [ . c o m m a n d ] w h e r e e v e n t . c h a r a c t e r s = = " l " ,
// [ . c o m m a n d , . s h i f t ] w h e r e e v e n t . c h a r a c t e r s = = " l " :
// p r i n t ( " c o m m a n d - l o r c o m m a n d - s h i f t - l " )
// d e f a u l t :
// b r e a k
// }
// p r i n t ( " k e y = " + ( e v e n t . c h a r a c t e r s I g n o r i n g M o d i f i e r s ? ? " " ) )
// p r i n t ( " \ n c h a r a c t e r = " + ( e v e n t . c h a r a c t e r s ? ? " " ) )
2019-09-09 07:27:31 +00:00
2020-04-23 02:18:28 +00:00
if event . modifierFlags . contains ( . command ) { // . s h i f t , . o p t i o n , . c o n t r o l . . .
if let chars = event . charactersIgnoringModifiers {
switch chars {
2020-07-11 23:33:29 +00:00
case " a " :
// p r i n t ( " C M D + A " )
SelectAll ( )
return // t o a v o i d d e s e l e c t t e x t
2020-04-23 02:18:28 +00:00
2020-07-11 23:33:29 +00:00
case " c " :
// p r i n t ( " C M D + C " )
Copy ( )
case " v " :
// p r i n t ( " C M D + V " )
Paste ( )
2020-07-02 00:47:43 +00:00
2020-04-23 02:18:28 +00:00
default :
2020-06-03 17:23:55 +00:00
super . keyDown ( with : event )
2019-09-09 07:27:31 +00:00
}
}
}
2020-04-23 02:18:28 +00:00
else {
#if FUNCTIONTEST
#else
let keyCode = Int ( event . keyCode )
switch keyCode {
case leftArrowKey :
2024-01-06 15:11:52 +00:00
// p r i n t ( " L E F T " ) ;
2020-06-02 17:10:18 +00:00
if ( Keyboard2Joystick ) {
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
pdl_valarr [ 0 ] = 0
}
2024-01-06 15:11:52 +00:00
kbdInput ( 0x88 )
2020-05-24 19:14:09 +00:00
2020-04-23 02:18:28 +00:00
case rightArrowKey :
2020-06-06 06:16:17 +00:00
// p r i n t ( " R I G H T " )
2020-05-24 19:14:09 +00:00
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
2020-06-02 17:10:18 +00:00
if ( Keyboard2Joystick ) {
pdl_valarr [ 0 ] = 1
}
2024-01-06 15:11:52 +00:00
kbdInput ( 0x95 )
2020-04-23 02:18:28 +00:00
case downArrowKey :
2020-06-06 06:16:17 +00:00
// p r i n t ( " D O W N " )
2020-05-24 19:14:09 +00:00
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
2020-06-02 17:10:18 +00:00
if ( Keyboard2Joystick ) {
pdl_valarr [ 1 ] = 1
}
else {
2024-01-06 15:11:52 +00:00
kbdInput ( 0x8A )
2020-06-02 17:10:18 +00:00
}
2024-01-06 15:11:52 +00:00
2020-04-23 02:18:28 +00:00
case upArrowKey :
2020-06-06 06:16:17 +00:00
// p r i n t ( " U P " )
2020-05-24 19:14:09 +00:00
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
2020-06-02 17:10:18 +00:00
if ( Keyboard2Joystick ) {
pdl_valarr [ 1 ] = 0
}
else {
2024-01-06 15:11:52 +00:00
kbdInput ( 0x8B )
}
case F4FunctionKey :
// i f l e t d e b u g g e r = D e b u g g e r W i n d o w C o n t r o l l e r . c u r r e n t {
// d e b u g g e r . C o n t i n u e ( )
// }
Resume ( )
case F5FunctionKey :
// i f l e t d e b u g g e r = D e b u g g e r W i n d o w C o n t r o l l e r . c u r r e n t {
// d e b u g g e r . P a u s e ( )
// }
Pause ( )
case F6FunctionKey :
if let debugger = DebuggerWindowController . shared {
debugger . Step_Over ( event )
}
case F7FunctionKey :
if let debugger = DebuggerWindowController . shared {
debugger . Step_In ( event )
}
case F8FunctionKey :
if let debugger = DebuggerWindowController . shared {
debugger . Step_Out ( event )
2020-06-02 17:10:18 +00:00
}
2020-04-23 02:18:28 +00:00
default :
// p r i n t ( " k e y c o d e : % d " , k e y C o d e )
if let chars = event . characters {
let char = chars . uppercased ( ) [ chars . startIndex ]
if let ascii = char . asciiValue {
kbdInput ( ascii )
}
}
}
#endif
}
2020-04-27 14:26:04 +00:00
2024-01-06 15:11:52 +00:00
// d i s p l a y F i e l d . c u r r e n t E d i t o r ( ) ? . s e l e c t e d R a n g e = N S M a k e R a n g e ( 0 , 0 )
textDisplay . setSelectedRange ( NSRange ( ) )
2019-09-09 07:27:31 +00:00
}
2020-05-06 06:03:36 +00:00
2020-02-23 00:37:54 +00:00
override func keyUp ( with event : NSEvent ) {
2020-06-06 06:16:17 +00:00
// p r i n t ( " k e y U p " )
2020-02-23 00:37:54 +00:00
// s w i t c h e v e n t . m o d i f i e r F l a g s . i n t e r s e c t i o n ( . d e v i c e I n d e p e n d e n t F l a g s M a s k ) {
// c a s e [ . c o m m a n d ] w h e r e e v e n t . c h a r a c t e r s = = " l " ,
// [ . c o m m a n d , . s h i f t ] w h e r e e v e n t . c h a r a c t e r s = = " l " :
// p r i n t ( " c o m m a n d - l o r c o m m a n d - s h i f t - l " )
// d e f a u l t :
// b r e a k
// }
// p r i n t ( " k e y = " + ( e v e n t . c h a r a c t e r s I g n o r i n g M o d i f i e r s ? ? " " ) )
// p r i n t ( " \ n c h a r a c t e r = " + ( e v e n t . c h a r a c t e r s ? ? " " ) )
#if FUNCTIONTEST
#else
let keyCode = Int ( event . keyCode )
switch keyCode {
case leftArrowKey :
// k b d I n p u t ( 0 x 0 8 )
2020-05-24 19:14:09 +00:00
// s e t I O ( 0 x C 0 6 4 , 1 2 7 ) ;
2020-06-06 06:16:17 +00:00
// p r i n t ( " l e f t " )
2020-05-24 19:14:09 +00:00
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
pdl_valarr [ 0 ] = 0.5
2020-02-23 00:37:54 +00:00
case rightArrowKey :
// k b d I n p u t ( 0 x 1 5 )
2020-05-24 19:14:09 +00:00
// s e t I O ( 0 x C 0 6 4 , 1 2 8 ) ;
2020-06-06 06:16:17 +00:00
// p r i n t ( " r i g h t " )
2020-05-24 19:14:09 +00:00
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
pdl_valarr [ 0 ] = 0.5
2020-02-23 00:37:54 +00:00
case downArrowKey :
// k b d I n p u t ( 0 x 0 B )
2020-05-24 19:14:09 +00:00
// s e t I O ( 0 x C 0 6 5 , 1 2 7 ) ;
2020-06-06 06:16:17 +00:00
// p r i n t ( " d o w n " )
2020-05-24 19:14:09 +00:00
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
pdl_valarr [ 1 ] = 0.5
2020-02-23 00:37:54 +00:00
case upArrowKey :
// k b d I n p u t ( 0 x 0 A )
2020-05-24 19:14:09 +00:00
// s e t I O ( 0 x C 0 6 5 , 1 2 8 ) ;
2020-06-06 06:16:17 +00:00
// p r i n t ( " u p " )
2020-05-24 19:14:09 +00:00
// K e y b o a r d 2 J o y S t i c k ( G a m e C o n t r o l l e r / P a d d l e )
pdl_valarr [ 1 ] = 0.5
2020-02-23 00:37:54 +00:00
default :
// p r i n t ( " k e y c o d e : % d " , k e y C o d e )
// i f l e t c h a r s = e v e n t . c h a r a c t e r s {
// l e t c h a r = c h a r s . u p p e r c a s e d ( ) [ c h a r s . s t a r t I n d e x ]
// i f l e t a s c i i = c h a r . a s c i i V a l u e {
// k b d I n p u t ( a s c i i )
// }
// }
break
}
#endif
2020-05-05 15:35:57 +00:00
kbdUp ( )
2020-02-23 00:37:54 +00:00
}
2020-05-21 05:22:44 +00:00
override func flagsChanged ( with event : NSEvent ) {
2024-01-06 15:11:52 +00:00
let flags = event . modifierFlags . intersection ( . deviceIndependentFlagsMask )
switch flags {
2020-05-21 05:22:44 +00:00
case [ . shift ] :
2020-06-25 04:05:55 +00:00
setIO ( 0xC061 , 0 )
setIO ( 0xC062 , 0 )
setIO ( 0xC063 , 0 ) // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// p r i n t ( " s h i f t k e y i s p r e s s e d " )
// c a s e [ . c o n t r o l ] :
// p r i n t ( " c o n t r o l k e y i s p r e s s e d " )
2020-05-21 05:22:44 +00:00
case [ . option ] :
2020-06-29 04:00:25 +00:00
setIO ( 0xC061 , 0 )
setIO ( 0xC062 , 1 << 7 )
2020-06-25 04:05:55 +00:00
setIO ( 0xC063 , 1 << 7 ) // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// p r i n t ( " o p t i o n k e y i s p r e s s e d " )
2020-05-21 05:22:44 +00:00
case [ . command ] :
2020-06-06 06:16:17 +00:00
// p r i n t ( " C o m m a n d k e y i s p r e s s e d " )
2020-06-29 04:00:25 +00:00
setIO ( 0xC061 , 1 << 7 )
setIO ( 0xC062 , 0 )
2020-06-25 04:05:55 +00:00
setIO ( 0xC063 , 1 << 7 ) // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// c a s e [ . c o n t r o l , . s h i f t ] :
// p r i n t ( " c o n t r o l - s h i f t k e y s a r e p r e s s e d " )
2020-05-21 05:22:44 +00:00
case [ . option , . shift ] :
2020-06-25 04:05:55 +00:00
setIO ( 0xC061 , 1 << 7 )
setIO ( 0xC062 , 0 )
setIO ( 0xC063 , 0 ) // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// p r i n t ( " o p t i o n - s h i f t k e y s a r e p r e s s e d " )
2020-05-21 05:22:44 +00:00
case [ . command , . shift ] :
2020-06-29 04:00:25 +00:00
setIO ( 0xC061 , 1 << 7 )
setIO ( 0xC062 , 0 )
2020-06-25 04:05:55 +00:00
setIO ( 0xC063 , 0 ) // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// p r i n t ( " c o m m a n d - s h i f t k e y s a r e p r e s s e d " )
// c a s e [ . c o n t r o l , . o p t i o n ] :
// p r i n t ( " c o n t r o l - o p t i o n k e y s a r e p r e s s e d " )
// c a s e [ . c o n t r o l , . c o m m a n d ] :
// p r i n t ( " c o n t r o l - c o m m a n d k e y s a r e p r e s s e d " )
2020-05-21 05:22:44 +00:00
case [ . option , . command ] :
2020-06-25 04:05:55 +00:00
setIO ( 0xC061 , 1 << 7 )
setIO ( 0xC062 , 1 << 7 )
setIO ( 0xC063 , 1 << 7 ) // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// p r i n t ( " o p t i o n - c o m m a n d k e y s a r e p r e s s e d " )
// c a s e [ . s h i f t , . c o n t r o l , . o p t i o n ] :
// p r i n t ( " s h i f t - c o n t r o l - o p t i o n k e y s a r e p r e s s e d " )
// c a s e [ . s h i f t , . c o n t r o l , . c o m m a n d ] :
// p r i n t ( " s h i f t - c o n t r o l - c o m m a n d k e y s a r e p r e s s e d " )
// c a s e [ . c o n t r o l , . o p t i o n , . c o m m a n d ] :
// p r i n t ( " c o n t r o l - o p t i o n - c o m m a n d k e y s a r e p r e s s e d " )
2020-05-21 05:22:44 +00:00
case [ . shift , . command , . option ] :
2020-06-25 04:05:55 +00:00
setIO ( 0xC061 , 1 << 7 )
setIO ( 0xC062 , 1 << 7 )
2020-05-28 16:35:17 +00:00
setIO ( 0xC063 , 0 ) ; // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// p r i n t ( " s h i f t - c o m m a n d - o p t i o n k e y s a r e p r e s s e d " )
// c a s e [ . s h i f t , . c o n t r o l , . o p t i o n , . c o m m a n d ] :
// p r i n t ( " s h i f t - c o n t r o l - o p t i o n - c o m m a n d k e y s a r e p r e s s e d " )
// c a s e [ . f u n c t i o n ] :
// p r i n t ( " f u n c t i o n k e y i s p r e s s e d " )
// c a s e [ . c a p s L o c k ] :
// p r i n t ( " c a p s L o c k k e y i s p r e s s e d " )
2024-01-06 15:11:52 +00:00
case [ . control , . command , . option ] :
Mouse2Joystick = ! Mouse2Joystick
mouseCursor ( hide : Mouse2Joystick )
ToolBarController . current ? . MouseToJoystickMenuItem . state = Mouse2Joystick ? . on : . off
2020-05-21 05:22:44 +00:00
default :
2020-06-25 04:05:55 +00:00
setIO ( 0xC061 , 0 )
setIO ( 0xC062 , 0 )
setIO ( 0xC063 , 1 << 7 ) // i n v e r t e d ( b i t 7 : n o t p r e s s e d )
2020-06-06 06:16:17 +00:00
// p r i n t ( " n o m o d i f i e r k e y s a r e p r e s s e d " )
2020-05-21 05:22:44 +00:00
}
}
2019-09-09 07:27:31 +00:00
2019-11-28 04:27:32 +00:00
var was = 0 ;
2020-04-27 14:26:04 +00:00
var currentVideoMode = videoMode
2020-04-29 22:35:54 +00:00
var lastFrameTime = CACurrentMediaTime ( ) as Double
2020-05-06 16:56:21 +00:00
var frameCounter : UInt32 = 0
2020-04-29 22:35:54 +00:00
var clkCounter : Double = 0
2020-04-27 14:26:04 +00:00
2020-05-24 19:14:09 +00:00
var shadowTxt : String = " "
2024-01-06 15:11:52 +00:00
var unicodeTextString : String = " "
2020-05-24 19:14:09 +00:00
2024-01-06 15:11:52 +00:00
func Flash ( ) {
self . frameCnt += 1
if ( self . frameCnt = = fps / video_fps_divider / 2 ) {
if ! flashInverted {
ViewController . charConvTbl = ViewController . charConvTblFlashOn
flashInverted = true
}
}
else if ( self . frameCnt >= fps / video_fps_divider ) {
self . frameCnt = 0
if flashInverted {
ViewController . charConvTbl = ViewController . charConvTblFlashOff
flashInverted = false
}
}
}
var textNeedRender = false
func RenderText ( ) {
Flash ( )
textNeedRender = false
2019-09-17 09:12:05 +00:00
2024-01-06 15:11:52 +00:00
var fromLines = 0
var toLines = textLines
2020-05-02 02:10:44 +00:00
2024-01-06 15:11:52 +00:00
if videoMode . text = = 0 {
if videoMode . mixed = = 1 {
fromLines = toLines - 4
}
else {
toLines = 0
}
2019-09-17 09:12:05 +00:00
}
2024-01-06 15:11:52 +00:00
unicodeTextArray = NSArray ( array : txtClear , copyItems : true ) as ! [ Character ]
// r e n d e r a n e m p t y s p a c e t o e i m i n a t e d i s p l a y i n g t e x t p o r t i o n o f t h e s c r e e n c o v e r e d b y g r a p h i c s
let charDisposition = videoMode . col80 = = 0 ? 1 : 2
for y in 0 . . < fromLines {
unicodeTextArray [ y * ( textCols * charDisposition + lineEndChars ) + textCols * charDisposition ] = " \n "
2019-09-17 09:12:05 +00:00
}
2024-01-06 15:11:52 +00:00
// 4 0 c o l
if videoMode . col80 = = 0 {
if MEMcfg . txt_page_2 = = 0 {
2024-01-14 01:47:42 +00:00
if ( MEMcfg . RD_AUX_MEM = = 0 ) {
textBufferPointer = ViewController . textPage1Pointer
}
else {
textBufferPointer = ViewController . textIntBufferPointer
}
2020-02-23 00:37:54 +00:00
}
2024-01-06 15:11:52 +00:00
else {
textBufferPointer = ViewController . textPage2Pointer
2020-05-02 02:10:44 +00:00
}
2020-06-11 00:48:37 +00:00
2024-01-06 15:11:52 +00:00
if textBufferPointer . elementsEqual ( ViewController . textPageShadowBuffer ) {
2020-05-06 16:56:21 +00:00
}
else {
2024-01-06 15:11:52 +00:00
ViewController . textPage1Pointer . copyBytes ( to : ViewController . textPageShadowBuffer )
textNeedRender = true
2020-05-27 04:13:31 +00:00
2020-05-06 16:56:21 +00:00
// r e n d e r t h e r e s t o f t h e t e x t s c r e e n
for y in fromLines . . < toLines {
2024-01-06 15:11:52 +00:00
for x in 0 . . < textCols {
let byte = textBufferPointer [ ViewController . textLineOfs [ y ] + x ]
2020-05-06 16:56:21 +00:00
let idx = Int ( byte ) ;
let chr = ViewController . charConvTbl [ idx ]
2024-01-06 15:11:52 +00:00
unicodeTextArray [ y * ( textCols + lineEndChars ) + x ] = chr
2020-05-06 16:56:21 +00:00
}
2024-01-06 15:11:52 +00:00
unicodeTextArray [ y * ( textCols + lineEndChars ) + textCols ] = " \n "
2020-04-27 14:26:04 +00:00
}
2020-08-02 22:00:42 +00:00
2024-01-06 15:11:52 +00:00
unicodeTextString = String ( unicodeTextArray )
2019-09-22 08:31:09 +00:00
}
2024-01-06 15:11:52 +00:00
}
// 8 0 c o l
else {
let auxPage = ( MEMcfg . is_80STORE = = 1 ) && ( MEMcfg . txt_page_2 = = 1 )
2019-09-22 08:31:09 +00:00
2024-01-06 15:11:52 +00:00
let textIntBuffer = auxPage ? ViewController . textIntBufferPointer : ViewController . textPage1Pointer
let textAuxBuffer = auxPage ? ViewController . textPage1Pointer : ViewController . textAuxBufferPointer
2020-06-11 00:48:37 +00:00
2024-01-06 15:11:52 +00:00
// r e n d e r t h e r e s t o f t h e t e x t s c r e e n
for y in fromLines . . < toLines {
for x in 0 . . < textCols {
let byte = textIntBuffer [ ViewController . textLineOfs [ y ] + x ]
let idx = Int ( byte ) ;
let chr = ViewController . charConvTbl [ idx ]
2020-06-11 00:48:37 +00:00
2024-01-06 15:11:52 +00:00
unicodeTextArray [ y * ( textCols * 2 + lineEndChars ) + x * 2 + 1 ] = chr
2020-05-29 15:50:47 +00:00
2024-01-06 15:11:52 +00:00
let byte2 = textAuxBuffer [ ViewController . textLineOfs [ y ] + x ]
let idx2 = Int ( byte2 ) ;
let chr2 = ViewController . charConvTbl [ idx2 ]
unicodeTextArray [ y * ( textCols * 2 + lineEndChars ) + x * 2 ] = chr2
2020-05-29 15:50:47 +00:00
}
2024-01-06 15:11:52 +00:00
unicodeTextArray [ y * ( textCols * 2 + lineEndChars ) + textCols * 2 ] = " \n "
2020-05-04 20:53:36 +00:00
}
2020-06-11 00:48:37 +00:00
2024-01-06 15:11:52 +00:00
unicodeTextString = String ( unicodeTextArray )
}
}
func SetSplashScreenFont ( ) {
for view in splashScreen . subviews {
if view is NSTextField {
let textField = view as ! NSTextField
if let fontSize = textField . font ? . pointSize {
textField . font = NSFont ( name : " PrintChar21 " , size : fontSize )
}
}
}
// S e t A p p l e ] [ f o n t
if let fontSize = textDisplay . font ? . pointSize {
textDisplay . font = NSFont ( name : " PrintChar21 " , size : fontSize )
ViewController . charConvTblFlashOn = ViewController . charConvTblFlashOn40
ViewController . charConvTblFlashOff = ViewController . charConvTblFlashOff40
}
}
func SetCol40 ( ) {
// S e t A p p l e ] [ f o n t
if let fontSize = textDisplay . font ? . pointSize {
textDisplay . font = NSFont ( name : " PrintChar21 " , size : fontSize )
ViewController . charConvTblFlashOn = ViewController . charConvTblFlashOn40
ViewController . charConvTblFlashOff = ViewController . charConvTblFlashOff40
}
}
func SetCol80 ( ) {
// S e t A p p l e ] [ f o n t
if let fontSize = textDisplay . font ? . pointSize {
textDisplay . font = NSFont ( name : " PRNumber3 " , size : fontSize )
ViewController . charConvTblFlashOn = ViewController . charConvTblCol80
ViewController . charConvTblFlashOff = ViewController . charConvTblCol80
}
}
func UpdateText ( ) {
// TODO: R e n d e r t e x t S c r e e n i n n a t i v e C
// t x t = S t r i n g ( b y t e s N o C o p y : V i e w C o n t r o l l e r . t e x t S c r e e n ! , l e n g t h : 1 0 , e n c o d i n g : . a s c i i , f r e e W h e n D o n e : f a l s e ) ? ? " H M M "
if videoMode . col80 != currentVideoMode . col80 {
currentVideoMode . col80 = videoMode . col80
2020-06-11 00:48:37 +00:00
2024-01-06 15:11:52 +00:00
if videoMode . col80 = = 1 {
SetCol80 ( )
}
else {
SetCol40 ( )
}
}
if textNeedRender || shadowTxt != unicodeTextString {
shadowTxt = unicodeTextString
let selectedRange = textDisplay . selectedRange ( )
// D i s p a t c h Q u e u e . m a i n . a s y n c { [ s e l f ] i n
textDisplay . string = unicodeTextString
textDisplay . setSelectedRange ( selectedRange )
// }
2020-06-11 00:48:37 +00:00
2024-01-06 15:11:52 +00:00
// l e t b o l d 1 4 = N S F o n t . b o l d S y s t e m F o n t ( o f S i z e : 1 4 . 0 )
// l e t t e x t C o l o r = N S C o l o r . r e d
// l e t a t t r i b s = [ N S A t t r i b u t e d S t r i n g . K e y . f o n t : b o l d 1 4 , N S A t t r i b u t e d S t r i n g . K e y . f o r e g r o u n d C o l o r : t e x t C o l o r , N S A t t r i b u t e d S t r i n g . K e y . p a r a g r a p h S t y l e : t e x t P a r a g r a p h ]
// l e t t e x t P a r a g r a p h = N S M u t a b l e P a r a g r a p h S t y l e ( )
// t e x t P a r a g r a p h . l i n e S p a c i n g = 0
// t e x t P a r a g r a p h . m i n i m u m L i n e H e i g h t = 3 2 . 0
// t e x t P a r a g r a p h . m a x i m u m L i n e H e i g h t = 3 2 . 0
//
// l e t a t t r i b s = [ N S A t t r i b u t e d S t r i n g . K e y . p a r a g r a p h S t y l e : t e x t P a r a g r a p h ]
// l e t a t t r S t r i n g : N S A t t r i b u t e d S t r i n g = N S A t t r i b u t e d S t r i n g . i n i t ( s t r i n g : u n i c o d e T e x t S t r i n g , a t t r i b u t e s : a t t r i b s )
// d i s p l a y . a t t r i b u t e d S t r i n g V a l u e = a t t r S t r i n g
}
// d i s p l a y . s t r i n g V a l u e = " t e s t i n g \ n i t \ n o u t "
}
func UpdateCPUspeed ( ) {
// D i s p a t c h Q u e u e . m a i n . a s y n c { [ s e l f ] i n
// u n d e r ~ 1 . 5 M H z - - 3 d e c i m a l s t o b e a b l e t o d i s p l a y 1 . 0 2 3 M H z
if ( ( mhz < 1.4 ) && ( mhz != floor ( mhz ) ) ) {
speedometer . stringValue = String ( format : " %0.3lf MHz " , mhz ) ;
}
// u n d e r ~ 1 0 0 M H z - - 1 d e c i m a l
else if ( mhz < 95 ) {
speedometer . stringValue = String ( format : " %0.1lf MHz " , mhz ) ;
}
// o v e r ~ 1 0 0 0 M H z - - 1 d e c i m a l G H z
else if ( mhz > 950 ) {
speedometer . stringValue = String ( format : " %0.1lf GHz " , mhz / 1000 ) ;
}
// h u n d r e d s - - n o d e c i m a l s
else {
speedometer . stringValue = String ( format : " %0.0lf MHz " , mhz ) ;
}
// }
}
func RenderGraphics ( ) {
// o n l y r e f r e s h g r a p h i c s v i e w w h e n n e e d e d ( a k a n o t i n t e x t m o d e )
if ( videoMode . text = = 0 ) {
if ( videoMode . hires = = 0 ) {
// w h e n w e c h a n g e v i d e o m o d e , b u f f e r n e e d s t o b e c l e a r e d t o a v o i d a r t i f a c t s
if ( savedVideoMode . text = = 1 )
|| ( savedVideoMode . mixed != videoMode . mixed )
|| ( savedVideoMode . hires != videoMode . hires )
{
lores . clearScreen ( )
lores . isHidden = false
hires . isHidden = true
unicodeTextString = String ( unicodeTextArray )
}
lores . Render ( )
}
else {
// w h e n w e c h a n g e v i d e o m o d e , b u f f e r n e e d s t o b e c l e a r e d t o a v o i d a r t i f a c t s
if ( savedVideoMode . text = = 1 )
|| ( savedVideoMode . mixed != videoMode . mixed )
|| ( savedVideoMode . hires != videoMode . hires )
{
hires . clearScreen ( )
hires . isHidden = false
lores . isHidden = true
unicodeTextString = String ( unicodeTextArray )
}
hires . Render ( )
}
}
else if ( savedVideoMode . text = = 0 ) {
// w e j u s t s w i t c h e d f r o m g r a h i c s t o t e x t
lores . isHidden = true
hires . isHidden = true
unicodeTextString = String ( unicodeTextArray )
}
savedVideoMode = videoMode
}
func Render ( ) {
self . RenderText ( )
// R e n d e r i n g i s h a p p e n i n g i n t h e m a i n t h r e a d , w h i c h h a s t w o i m p l i c a t i o n s :
// 1 . W e c a n u p d a t e U I e l e m e n t s
// 2 . i t i s i n d e p e n d e n t o f t h e s i m u l a t i o n , d e t h a t i s r u n n i n g i n t h e b a c k g r o u n d t h r e a d w h i l e w e a r e b u s y w i t h r e n d e r i n g . . .
// D i s p a t c h Q u e u e . g l o b a l ( q o s : . u s e r I n i t i a t e d ) . a s y n c {
DispatchQueue . main . async {
self . UpdateText ( )
self . UpdateCPUspeed ( )
#if HIRES
self . RenderGraphics ( )
#endif // H I R E S
2020-05-29 15:50:47 +00:00
}
2020-06-11 00:48:37 +00:00
}
2020-06-25 04:05:55 +00:00
override func mouseDown ( with event : NSEvent ) {
2024-01-06 15:11:52 +00:00
// p r i n t ( # f u n c t i o n )
switch event . modifierFlags . intersection ( . deviceIndependentFlagsMask ) {
case [ . control , . command , . option ] :
Mouse2Joystick = ! Mouse2Joystick
mouseCursor ( hide : Mouse2Joystick )
ToolBarController . current ? . MouseToJoystickMenuItem . state = Mouse2Joystick ? . on : . off
default :
break
}
2020-06-25 04:05:55 +00:00
if ( Mouse2Joystick ) {
setIO ( 0xC061 , 1 << 7 )
}
2024-01-06 15:11:52 +00:00
2020-06-25 04:05:55 +00:00
}
2020-06-11 00:48:37 +00:00
2020-06-25 04:05:55 +00:00
override func mouseUp ( with event : NSEvent ) {
2024-01-06 15:11:52 +00:00
// p r i n t ( # f u n c t i o n )
2020-06-25 04:05:55 +00:00
if ( Mouse2Joystick ) {
setIO ( 0xC061 , 0 )
}
}
override func rightMouseDown ( with event : NSEvent ) {
2024-01-06 15:11:52 +00:00
// p r i n t ( # f u n c t i o n )
2020-06-25 04:05:55 +00:00
if ( Mouse2Joystick ) {
setIO ( 0xC062 , 1 << 7 )
}
}
override func rightMouseUp ( with event : NSEvent ) {
2024-01-06 15:11:52 +00:00
// p r i n t ( # f u n c t i o n )
2020-06-25 04:05:55 +00:00
if ( Mouse2Joystick ) {
setIO ( 0xC062 , 0 )
}
}
override func otherMouseDown ( with event : NSEvent ) {
2024-01-06 15:11:52 +00:00
// p r i n t ( # f u n c t i o n )
2020-06-25 04:05:55 +00:00
if ( Mouse2Joystick ) {
setIO ( 0xC063 , 0 ) // i n v e r t e d ( b i t 7 : 0 = p r e s s e d )
}
}
override func otherMouseUp ( with event : NSEvent ) {
2024-01-06 15:11:52 +00:00
// p r i n t ( # f u n c t i o n )
2020-06-25 04:05:55 +00:00
if ( Mouse2Joystick ) {
setIO ( 0xC063 , 1 << 7 ) // i n v e r t e d ( b i t 7 : 1 = n o t p r e s s e d )
}
}
2020-06-17 16:46:17 +00:00
2024-01-06 15:11:52 +00:00
func diskButtonUpdate ( ) {
DispatchQueue . main . async {
if ( self . frameCounter % DEF_DRV_LED_DIV = = 0 ) {
// D i s k M o t o r L E D
if spkr_is_disk_motor_playing ( ) {
if self . disk1_led . isHidden {
self . disk1_led . isHidden = false
}
}
else {
if ! self . disk1_led . isHidden {
self . disk1_led . isHidden = true
}
}
// D i s k L o a d e d
if woz_is_loaded ( ) > 0 {
if self . disk1_closed . isHidden {
self . disk1_closed . isHidden = false
}
}
else {
if ! self . disk1_closed . isHidden {
self . disk1_closed . isHidden = true
}
}
}
}
}
func debugBreak ( ) {
Pause ( )
spkr_play_disk_motor_time = 0
spkr_stopAll ( )
// TODO: T h i s s h o u l d b e i n D e b u g g e r !
debuggerPauseUpdate ( )
debuggerShowWindow ( )
}
let UpdateSemaphore = DispatchSemaphore ( value : 1 )
2020-06-17 16:46:17 +00:00
func Update ( ) {
2024-01-06 15:11:52 +00:00
// c l k _ 6 5 0 2 _ p e r _ f r m _ m a x = 0
if UpdateSemaphore . wait ( timeout : . now ( ) + 0.001 ) = = . timedOut {
// g e t b a c k h e r e n e x t t i m e . . .
return
}
diskButtonUpdate ( )
2020-06-17 16:46:17 +00:00
switch cpuState {
case cpuState_running :
2024-01-06 15:11:52 +00:00
clkCounter += Double ( m6502 . clkfrm )
2020-06-17 16:46:17 +00:00
// w e s t a r t a n e w f r a m e f r o m h e r e , s o C P U i s r u n n i n g e v e n w h i l e r e n d e r i n g
2024-01-06 15:11:52 +00:00
// m 6 5 0 2 . c l k f r m = 0
2020-06-17 16:46:17 +00:00
frameCounter += 1
2024-01-06 15:11:52 +00:00
2020-06-17 16:46:17 +00:00
if ( frameCounter % fps = = 0 ) {
let currentTime = CACurrentMediaTime ( ) as Double
let elpasedTime = currentTime - lastFrameTime
lastFrameTime = currentTime
mhz = Double ( clkCounter ) / ( elpasedTime * M ) ;
clkCounter = 0
}
#if SPEEDTEST
#else
// p o l l i n p u t d e v i c e s l i k e m o u s e a n d j o y s t i c k
2020-07-13 04:40:08 +00:00
// I n p u t ( )
2020-06-17 16:46:17 +00:00
// r u n s o m e c o d e
2024-01-06 15:11:52 +00:00
// c p u S t a t e = c p u S t a t e _ e x e c u t i n g
// D i s p a t c h Q u e u e . g l o b a l ( q o s : . u s e r I n i t i a t e d ) . a s y n c {
if m6502 . debugger . on {
m6502_Debug ( )
switch m6502 . interrupt {
case HALT :
debugBreak ( )
case BREAK : // B R K i n s t r u c t i o n
debugBreak ( )
case BREAKPOINT : // C P U h a l t e d b e c a u s e o f a b r e a k p o i n t
debugBreak ( )
case BREAKRDMEM : // C P U h a l t e d b e c a u s e o f a b r e a k p o i n t
debugBreak ( )
case BREAKWRMEM : // C P U h a l t e d b e c a u s e o f a b r e a k p o i n t
debugBreak ( )
case RET :
if m6502 . debugger . mask . ret = = 1 {
// S t e p _ O u t / S t e p _ O v e r
if m6502 . PC >= m6502 . debugger . SP {
debugBreak ( )
}
}
case INV : // i n v a l i d i n s t r u c t i o n
debugBreak ( )
default :
break
}
// c l e a r i t e r r u p t
m6502 . interrupt = NO_INT
}
else {
// D i s p a t c h Q u e u e . g l o b a l ( q o s : . u s e r I n i t i a t e d ) . a s y n c {
m6502_Run ( )
// }
// c p u S t a t e = c p u S t a t e _ r u n n i n g
}
2020-06-17 16:46:17 +00:00
// v i d e o r e n d e r i n g
2020-06-23 02:23:41 +00:00
if ( frameCounter % video_fps_divider = = 0 ) {
2020-06-17 16:46:17 +00:00
Render ( )
2020-06-23 02:23:41 +00:00
}
2024-01-06 15:11:52 +00:00
// TODO: T h i s s h o u l d b e i n D e b u g g e r !
if let debugger = DebuggerViewController . shared {
debugger . Update ( )
}
2020-06-17 16:46:17 +00:00
#endif
break
2024-01-06 15:11:52 +00:00
case cpuState_executing :
// p r e v e n t r u n n i n g m o r e i n s t a n c e s p e r s e s s i o n
// s e t C P U C l o c k S p e e d ( f r e q : M H z _ 6 5 0 2 - 1 )
break
2020-07-13 04:40:08 +00:00
2020-06-17 16:46:17 +00:00
case cpuState_halting :
cpuState = cpuState_halted
2024-01-06 15:11:52 +00:00
// l a s t v i d e o r e n d e r i n g b e f o r e h a l t
2020-06-17 16:46:17 +00:00
Render ( )
2024-01-06 15:11:52 +00:00
2020-06-17 16:46:17 +00:00
break
2020-06-18 22:14:54 +00:00
case cpuState_halted :
2024-01-06 15:11:52 +00:00
#if SCHEDULER_CVDISPLAYLINK
CVDisplayLinkStop ( displayLink ! )
#else
2020-06-18 22:14:54 +00:00
upd . suspend ( )
2024-01-06 15:11:52 +00:00
#endif
2020-06-18 22:14:54 +00:00
break
2020-06-17 16:46:17 +00:00
default :
break
}
2024-01-06 15:11:52 +00:00
// o k , f r o m n o w y o u c a n u p d a t e a g a i n
UpdateSemaphore . signal ( )
2019-09-07 23:18:05 +00:00
}
2019-09-15 11:02:22 +00:00
2019-09-07 23:18:05 +00:00
// f u n c F r o m B u f ( p t r : U n s a f e M u t a b l e P o i n t e r < U I n t 8 > , l e n g t h l e n : I n t ) - > S t r i n g ? {
// / / c o n v e r t t h e b y t e s u s i n g t h e U T F 8 e n c o d i n g
// i f l e t t h e S t r i n g = N S S t r i n g ( b y t e s : p t r , l e n g t h : l e n , e n c o d i n g : N S U T F 8 S t r i n g E n c o d i n g ) {
// r e t u r n t h e S t r i n g a s S t r i n g
// } e l s e {
// r e t u r n n i l / / t h e b y t e s a r e n ' t v a l i d U T F 8
// }
// }
2019-11-28 04:27:32 +00:00
2019-09-15 11:02:22 +00:00
2024-01-06 15:11:52 +00:00
#if SCHEDULER_CVDISPLAYLINK
#else
2020-06-23 02:23:41 +00:00
var upd = RepeatingTimer ( timeInterval : 1 )
2020-02-07 08:40:31 +00:00
2020-06-23 02:23:41 +00:00
func newUpdateTimer ( timeInterval : Double ) {
upd . kill ( )
upd = RepeatingTimer ( timeInterval : timeInterval )
upd . eventHandler = {
self . Update ( )
}
upd . resume ( )
}
2020-07-27 00:31:56 +00:00
2024-01-06 15:11:52 +00:00
#endif
2020-07-27 00:31:56 +00:00
// K e l v i n S h e r l o c k ' s f i x t o a v o i d u n i n s t a l l e d f o n t p r o b l e m s
override func awakeFromNib ( ) {
2024-01-06 15:11:52 +00:00
// s e l f . d i s p l a y . f o n t = N S F o n t ( n a m e : " P r i n t C h a r 2 1 " , s i z e : 3 2 )
2020-07-27 00:31:56 +00:00
}
2024-01-06 15:11:52 +00:00
required init ? ( coder : NSCoder ) {
// p r i n t ( # f u n c t i o n )
super . init ( coder : coder )
2020-08-02 22:00:42 +00:00
2024-01-06 15:11:52 +00:00
ViewController . shared = self
}
// f u n c r e n d e r ( ) {
//
// v a r x = v e r t e x D a t a [ 2 * 3 + 0 ]
// x - = 0 . 0 1
// i f x < - 1 {
// x = 1
// }
// v e r t e x D a t a [ 2 * 3 + 0 ] = x
//
// g u a r d l e t d r a w a b l e = m e t a l L a y e r ? . n e x t D r a w a b l e ( ) e l s e { r e t u r n }
// l e t r e n d e r P a s s D e s c r i p t o r = M T L R e n d e r P a s s D e s c r i p t o r ( )
// r e n d e r P a s s D e s c r i p t o r . c o l o r A t t a c h m e n t s [ 0 ] . t e x t u r e = d r a w a b l e . t e x t u r e
// r e n d e r P a s s D e s c r i p t o r . c o l o r A t t a c h m e n t s [ 0 ] . l o a d A c t i o n = . c l e a r
// r e n d e r P a s s D e s c r i p t o r . c o l o r A t t a c h m e n t s [ 0 ] . c l e a r C o l o r = M T L C l e a r C o l o r (
// r e d : 0 . 0 ,
// g r e e n : 1 0 4 . 0 / 2 5 5 . 0 ,
// b l u e : 5 5 . 0 / 2 5 5 . 0 ,
// a l p h a : 0 . 3 )
//
// i f l e t c o m m a n d B u f f e r = c o m m a n d Q u e u e . m a k e C o m m a n d B u f f e r ( ) {
// i f l e t r e n d e r E n c o d e r = c o m m a n d B u f f e r . m a k e R e n d e r C o m m a n d E n c o d e r ( d e s c r i p t o r : r e n d e r P a s s D e s c r i p t o r ) {
// r e n d e r E n c o d e r . s e t R e n d e r P i p e l i n e S t a t e ( p i p e l i n e S t a t e )
// l e t d a t a S i z e = v e r t e x D a t a . c o u n t * M e m o r y L a y o u t . s i z e ( o f V a l u e : v e r t e x D a t a [ 0 ] ) / / 1
// v e r t e x B u f f e r = d e v i c e . m a k e B u f f e r ( b y t e s : v e r t e x D a t a , l e n g t h : d a t a S i z e , o p t i o n s : [ ] ) / / 2
// r e n d e r E n c o d e r . s e t V e r t e x B u f f e r ( v e r t e x B u f f e r , o f f s e t : 0 , i n d e x : 0 )
// r e n d e r E n c o d e r . d r a w P r i m i t i v e s ( t y p e : . t r i a n g l e , v e r t e x S t a r t : 0 , v e r t e x C o u n t : 3 , i n s t a n c e C o u n t : 1 )
// r e n d e r E n c o d e r . e n d E n c o d i n g ( )
// c o m m a n d B u f f e r . p r e s e n t ( d r a w a b l e )
// c o m m a n d B u f f e r . c o m m i t ( )
// }
// }
// }
//
//
// v a r v e r t e x D a t a : [ F l o a t ] = [
// 0 . 0 , 1 . 0 , 0 . 0 ,
// - 1 . 0 , - 1 . 0 , 0 . 0 ,
// 1 . 0 , - 1 . 0 , 0 . 0
// ]
#if SCHEDULER_CVDISPLAYLINK
2020-08-02 22:00:42 +00:00
2024-01-06 15:11:52 +00:00
// T h e c a l l b a c k f u n c t i o n i s c a l l e d e v e r y t i m e C V D i s p l a y L i n k s a y s i t s t i m e t o g e t a n e w f r a m e .
let displayLinkOutputCallback : CVDisplayLinkOutputCallback = { ( displayLink : CVDisplayLink , _ inNow : UnsafePointer < CVTimeStamp > , _ inOutputTime : UnsafePointer < CVTimeStamp > , _ flagsIn : CVOptionFlags , _ flagsOut : UnsafeMutablePointer < CVOptionFlags > , _ vController : UnsafeMutableRawPointer ? ) -> CVReturn in
2020-06-12 01:29:26 +00:00
2024-01-06 15:11:52 +00:00
/* T h e d i s p l a y L i n k C o n t e x t i s C V D i s p l a y L i n k ' s p a r a m e t e r d e f i n i t i o n o f t h e v i e w i n w h i c h w e a r e w o r k i n g .
In order to access the methods of a given view we need to specify what kind of view it is as right
now the UnsafeMutablePointer < Void > just means we have a pointer to " something " . To cast the pointer
such that the compiler at runtime can access the methods associated with our SwiftOpenGLView , we use
an unsafeBitCast . The definition of which states , " Returns the the bits of x, interpreted as having
type U . " We may then call any of that view's methods. Here we call drawView() which we draw a
frame for rendering . */
// u n s a f e B i t C a s t ( d i s p l a y L i n k C o n t e x t , S w i f t O p e n G L V i e w . s e l f ) . r e n d e r F r a m e ( )
// / T h i s c a n b e a p r e c i s e F P S u p d a t e r s o M H z w o u l d b e d e a d p e r f e c t p i t c h - - h o w e v e r , i t m a k e s t h i n g s w o r s e
// l e t n o w : C V T i m e S t a m p = i n N o w . p o i n t e e
// / / p r i n t ( " R a t e S c a l e r : " , n o w . r a t e S c a l a r )
// i f ( m y S e l f . l a s t _ f r a m e _ t i m e ! = 0 ) {
// l e t v i d e o T i m e D i f f = n o w . v i d e o T i m e - m y S e l f . l a s t _ f r a m e _ t i m e
// l e t c u r r e n t F P S = D o u b l e ( n o w . v i d e o T i m e S c a l e ) / D o u b l e ( v i d e o T i m e D i f f )
//
// f p s = c u r r e n t F P S
// / / m y S e l f . s e t C P U C l o c k S p e e d ( f r e q : M H z _ 6 5 0 2 )
// c l k _ 6 5 0 2 _ p e r _ f r m = U I n t 6 4 ( M H z _ 6 5 0 2 * M / c u r r e n t F P S )
// c l k _ 6 5 0 2 _ p e r _ f r m _ s e t = c l k _ 6 5 0 2 _ p e r _ f r m
//
// }
// m y S e l f . l a s t _ f r a m e _ t i m e = n o w . v i d e o T i m e ;
2020-06-04 18:37:35 +00:00
2024-01-06 15:11:52 +00:00
let mySelf = Unmanaged < ViewController > . fromOpaque ( vController ! ) . takeUnretainedValue ( )
mySelf . Update ( ) ;
// W e a r e g o i n g t o a s s u m e t h a t e v e r y t h i n g w e n t w e l l f o r t h i s m o c k u p , a n d p a s s s u c c e s s a s t h e C V R e t u r n
return kCVReturnSuccess
}
// s e t s a c a l l b a c k a t e v e r y s c r e e n r e f r e s h ( n o r m a l l y 6 0 H z )
func setupDisplayLink ( ) {
// G r a b t h e a l i n k t o t h e a c t i v e d i s p l a y s , s e t t h e c a l l b a c k d e f i n e d a b o v e , a n d s t a r t t h e l i n k .
/* A n a l t e r n a t i v e t o a n e s t e d f u n c t i o n i s a g l o b a l f u n c t i o n o r a c l o s u r e p a s s e d a s t h e a r g u m e n t - - a l o c a l f u n c t i o n
( i . e . a function defined within the class ) is NOT allowed . */
// T h e U n s a f e M u t a b l e P o i n t e r < V o i d > ( u n s a f e A d d r e s s O f ( s e l f ) ) p a s s e s a p o i n t e r t o t h e i n s t a n c e o f o u r c l a s s .
CVDisplayLinkCreateWithActiveCGDisplays ( & displayLink )
2019-09-22 08:31:09 +00:00
2024-01-06 15:11:52 +00:00
let unsafeSelf : UnsafeMutableRawPointer = Unmanaged . passUnretained ( self ) . toOpaque ( )
CVDisplayLinkSetOutputCallback ( displayLink ! , displayLinkOutputCallback , unsafeSelf )
// C V D i s p l a y L i n k S t a r t ( d i s p l a y L i n k ! )
}
#endif
@IBOutlet weak var disk1_led : NSImageView !
@IBOutlet weak var disk2_led : NSImageView !
@IBOutlet weak var disk1_closed : NSImageView !
@IBOutlet weak var disk2_closed : NSImageView !
var keyDownMonitor : Any ?
var keyUpMonitor : Any ?
func keyEventsOn ( ) {
2019-09-22 08:31:09 +00:00
// N S E v e n t . r e m o v e M o n i t o r ( N S E v e n t . E v e n t T y p e . f l a g s C h a n g e d )
// N S E v e n t . a d d L o c a l M o n i t o r F o r E v e n t s ( m a t c h i n g : . f l a g s C h a n g e d ) {
// s e l f . f l a g s C h a n g e d ( w i t h : $ 0 )
// r e t u r n $ 0
// }
2019-11-28 04:27:32 +00:00
2024-01-06 15:11:52 +00:00
if let event = keyDownMonitor {
NSEvent . removeMonitor ( event )
keyDownMonitor = nil
}
keyDownMonitor = NSEvent . addLocalMonitorForEvents ( matching : . keyDown ) {
2020-04-27 14:26:04 +00:00
// p r i n t ( " k e y D o w n e v e n t " )
self . keyDown ( with : $0 )
return nil
}
2024-01-06 15:11:52 +00:00
if let event = keyUpMonitor {
NSEvent . removeMonitor ( event )
keyUpMonitor = nil
}
keyUpMonitor = NSEvent . addLocalMonitorForEvents ( matching : . keyUp ) {
2020-04-27 14:26:04 +00:00
// p r i n t ( " k e y U p e v e n t " )
self . keyUp ( with : $0 )
return nil
}
2024-01-06 15:11:52 +00:00
}
func keyEventsOff ( ) {
// N S E v e n t . r e m o v e M o n i t o r ( N S E v e n t . E v e n t T y p e . f l a g s C h a n g e d )
if let event = keyDownMonitor {
NSEvent . removeMonitor ( event )
keyDownMonitor = nil
}
if let event = keyUpMonitor {
NSEvent . removeMonitor ( event )
keyUpMonitor = nil
}
}
override func viewDidLoad ( ) {
super . viewDidLoad ( )
// i f l e t i m a g e = D i s k 1 _ o p e n _ o n _ i m g {
// D i s k 1 _ B u t t o n C e l l . a l t e r n a t e I m a g e = i m a g e
// N S L o g ( " D i s k 1 _ B u t t o n C e l l : % @ " , D i s k 1 _ B u t t o n C e l l )
// }
// l e t l a y e r = C A L a y e r ( )
// h i r e s . l a y e r = l a y e r
// h i r e s . w a n t s L a y e r = t r u e
// d e v i c e = M T L C r e a t e S y s t e m D e f a u l t D e v i c e ( )
// m e t a l L a y e r = C A M e t a l L a y e r ( ) / / 1
// m e t a l L a y e r . d e v i c e = d e v i c e / / 2
// m e t a l L a y e r . p i x e l F o r m a t = . b g r a 8 U n o r m / / 3
// m e t a l L a y e r . f r a m e b u f f e r O n l y = t r u e / / 4
// m e t a l L a y e r . f r a m e = h i r e s . l a y e r ! . f r a m e / / 5
// h i r e s . l a y e r ! . a d d S u b l a y e r ( m e t a l L a y e r ) / / 6
//
// l e t d a t a S i z e = v e r t e x D a t a . c o u n t * M e m o r y L a y o u t . s i z e ( o f V a l u e : v e r t e x D a t a [ 0 ] ) / / 1
// v e r t e x B u f f e r = d e v i c e . m a k e B u f f e r ( b y t e s : v e r t e x D a t a , l e n g t h : d a t a S i z e , o p t i o n s : [ ] ) / / 2
//
// / / 1
// l e t d e f a u l t L i b r a r y = d e v i c e . m a k e D e f a u l t L i b r a r y ( ) !
// l e t f r a g m e n t P r o g r a m = d e f a u l t L i b r a r y . m a k e F u n c t i o n ( n a m e : " b a s i c _ f r a g m e n t " )
// l e t v e r t e x P r o g r a m = d e f a u l t L i b r a r y . m a k e F u n c t i o n ( n a m e : " b a s i c _ v e r t e x " )
//
// / / 2
// l e t p i p e l i n e S t a t e D e s c r i p t o r = M T L R e n d e r P i p e l i n e D e s c r i p t o r ( )
// p i p e l i n e S t a t e D e s c r i p t o r . v e r t e x F u n c t i o n = v e r t e x P r o g r a m
// p i p e l i n e S t a t e D e s c r i p t o r . f r a g m e n t F u n c t i o n = f r a g m e n t P r o g r a m
// p i p e l i n e S t a t e D e s c r i p t o r . c o l o r A t t a c h m e n t s [ 0 ] . p i x e l F o r m a t = . b g r a 8 U n o r m
//
// / / 3
// p i p e l i n e S t a t e = t r y ! d e v i c e . m a k e R e n d e r P i p e l i n e S t a t e ( d e s c r i p t o r : p i p e l i n e S t a t e D e s c r i p t o r )
//
// c o m m a n d Q u e u e = d e v i c e . m a k e C o m m a n d Q u e u e ( )
// t i m e r = C A D i s p l a y L i n k ( t a r g e t : s e l f , s e l e c t o r : # s e l e c t o r ( g a m e l o o p ) )
// t i m e r . a d d ( t o : R u n L o o p . m a i n , f o r M o d e : . d e f a u l t )
2020-04-27 14:26:04 +00:00
2024-01-06 15:11:52 +00:00
// S e t A p p l e ] [ f o n t
SetCol40 ( )
SetSplashScreenFont ( )
openLog ( )
hires . clearScreen ( ) ;
spkr_load_sfx ( Bundle . main . resourcePath ! + " /sfx " )
let woz_err = woz_loadFile ( Bundle . main . resourcePath ! + " /dsk/Apple DOS 3.3 January 1983.woz " )
chk_woz_load ( err : woz_err )
woz_flags . image_file_readonly = 1
// v i e w . f r a m e = C G R e c t ( o r i g i n : C G P o i n t ( ) , s i z e : N S S c r e e n . m a i n ! . v i s i b l e F r a m e . s i z e )
// c r e a t e H i R e s ( )
self . textDisplayScroller . scaleUnitSquare ( to : NSSize ( width : 1 , height : 1 ) )
keyEventsOn ( )
// d i s p l a y F i e l d . m a x i m u m N u m b e r O f L i n e s = t e x t L i n e s
// d i s p l a y F i e l d . p r e f e r r e d M a x L a y o u t W i d t h = d i s p l a y F i e l d . f r a m e . w i d t h
2019-09-07 23:18:05 +00:00
2019-09-22 08:31:09 +00:00
// D i s p a t c h Q u e u e . m a i n . a s y n c A f t e r ( d e a d l i n e : . n o w ( ) + 1 / f p s , e x e c u t e : {
2019-09-09 02:55:19 +00:00
// s e l f . u p d a t e ( )
2019-09-08 21:52:52 +00:00
// } )
2019-09-15 11:02:22 +00:00
2019-09-17 09:12:05 +00:00
// # i f F U N C T I O N T E S T
// # e l s e
2019-09-15 11:02:22 +00:00
// D i s p a t c h Q u e u e . g l o b a l ( q o s : . b a c k g r o u n d ) . a s y n c {
// s e l f . u p d a t e ( )
// }
2019-09-07 23:18:05 +00:00
2020-06-23 02:23:41 +00:00
// u p d . e v e n t H a n d l e r = {
// s e l f . U p d a t e ( )
// }
// u p d . r e s u m e ( )
2024-01-06 15:11:52 +00:00
#if SCHEDULER_CVDISPLAYLINK
// G r a b t h e a l i n k t o t h e a c t i v e d i s p l a y s , s e t t h e c a l l b a c k d e f i n e d a b o v e , a n d s t a r t t h e l i n k .
/* A n a l t e r n a t i v e t o a n e s t e d f u n c t i o n i s a g l o b a l f u n c t i o n o r a c l o s u r e p a s s e d a s t h e a r g u m e n t - - a l o c a l f u n c t i o n
( i . e . a function defined within the class ) is NOT allowed . */
// T h e U n s a f e M u t a b l e P o i n t e r < V o i d > ( u n s a f e A d d r e s s O f ( s e l f ) ) p a s s e s a p o i n t e r t o t h e i n s t a n c e o f o u r c l a s s .
CVDisplayLinkCreateWithActiveCGDisplays ( & displayLink )
let unsafeSelf : UnsafeMutableRawPointer = Unmanaged . passUnretained ( self ) . toOpaque ( )
CVDisplayLinkSetOutputCallback ( displayLink ! , displayLinkOutputCallback , unsafeSelf )
CVDisplayLinkStart ( displayLink ! )
#else
2020-06-23 02:23:41 +00:00
newUpdateTimer ( timeInterval : 1 / Double ( fps ) )
2024-01-06 15:11:52 +00:00
#endif
// s o u n d G a p S l i d e r . i n t e g e r V a l u e = I n t ( s p k r _ e x t r a _ b u f )
// l e d i n g I n i t E d g e L a b e l . t i t l e = " I L E : " + S t r i n g ( S P K R _ I N I T I A L _ L E A D I N G _ E D G E )
// i n i t i a l L e a d E d g e S l i d e r . f l o a t V a l u e = S P K R _ I N I T I A L _ L E A D I N G _ E D G E
// l e a d i n g E d g e L a b e l . t i t l e = " L E : " + S t r i n g ( S P K R _ F A D E _ L E A D I N G _ E D G E )
// l e a d E d g e S l i d e r . f l o a t V a l u e = S P K R _ F A D E _ L E A D I N G _ E D G E
// t r a i l i n g I n i t E d g e L a b e l . t i t l e = " I T E : " + S t r i n g ( S P K R _ I N I T I A L _ T R A I L I N G _ E D G E )
// i n i t i a l T a i l E d g e S l i d e r . f l o a t V a l u e = S P K R _ I N I T I A L _ T R A I L I N G _ E D G E
// t r a i l i n g E d g e L a b e l . t i t l e = " T E : " + S t r i n g ( S P K R _ F A D E _ T R A I L I N G _ E D G E )
// t a i l E d g e S l i d e r . f l o a t V a l u e = S P K R _ F A D E _ T R A I L I N G _ E D G E
// / / B U G F I X : I a m n o t s u r e w h y b u t i f I d o n o t a d j u s t t h e f r a m e a n d b o u n d s s i z e
// / / c o u p l e o f t i m e s , C o c o a m i s c a l c u l a t e s t h e m
// v a r s i z e = M o n i t o r V i e w . t e x t V i e w B o u n d s
// s i z e . w i d t h / = 2
// s i z e . h e i g h t / = 2
// t e x t D i s p l a y . s e t F r a m e S i z e ( s i z e )
// t e x t D i s p l a y . s e t B o u n d s S i z e ( s i z e )
//
// s i z e . w i d t h + = 1 3 6 + 1 1 * 2
// s i z e . h e i g h t + = 6 4 + 1 1 * 2
// v i e w . s e t F r a m e S i z e ( s i z e )
// v i e w . s e t B o u n d s S i z e ( s i z e )
2020-06-23 02:23:41 +00:00
2019-07-26 05:51:36 +00:00
}
2024-01-06 15:11:52 +00:00
2020-07-11 20:16:10 +00:00
override func viewDidAppear ( ) {
2024-01-06 15:11:52 +00:00
// d i s p l a y F i e l d . c u r r e n t E d i t o r ( ) ? . s e l e c t e d R a n g e = N S M a k e R a n g e ( 0 , 0 )
// s e l f . d i s p l a y F i e l d . w i n d o w ? . m a k e F i r s t R e s p o n d e r ( s e l f )
textDisplay . setSelectedRange ( NSRange ( ) )
textDisplay . window ? . makeFirstResponder ( self )
DispatchQueue . main . asyncAfter ( deadline : . now ( ) + 0.1 ) {
self . monitorView . adjustTextDisplaySize ( )
}
2020-07-11 20:16:10 +00:00
}
2020-01-28 06:54:03 +00:00
2024-01-06 15:11:52 +00:00
func setSpkrExtrabuf ( freq : Double ) {
// TODO: P r o b a b l y t h i s i s n o t t h e b e s t w a y t o d e a l w i t h t h e p r o b l e m : T o m a k e s o u n d c o n t i n o u s i n d e p e n d e n t o f F P S a n d F r e q
2019-07-26 05:51:36 +00:00
2024-01-06 15:11:52 +00:00
// s p k r _ e x t r a _ b u f = I n t 3 2 ( 7 8 0 / f p s )
switch freq {
case 0.25 :
spkr_extra_buf = - 65
break
case 0.5 :
spkr_extra_buf = - 140
break
case 1.5 :
spkr_extra_buf = 175
break
case 2.0 :
// s p k r _ e x t r a _ b u f = I n t 3 2 ( D o u b l e ( s p k r _ e x t r a _ b u f ) * 2 . 9 6 1 5 3 8 4 6 1 5 3 8 4 6 2 ) / / n o r m a l l y i t s h o u l d c o m e u p a s 7 7 , b u t t h i s w a y i t i s c a l c u l a t e d w i t h F P S
// s p k r _ e x t r a _ b u f = 2 0
spkr_extra_buf = 195 // 8 8
break
case 2.8 :
spkr_extra_buf = 65 // 1 8 5
break
case 4.0 :
// s p k r _ e x t r a _ b u f = I n t 3 2 ( D o u b l e ( s p k r _ e x t r a _ b u f ) * 1 . 3 4 6 1 5 3 8 4 6 1 5 3 8 4 6 ) / / n o r m a l l y i t s h o u l d c o m e u p a s 3 5 , b u t t h i s w a y i t i s c a l c u l a t e d w i t h F P S
// s p k r _ e x t r a _ b u f = 4 5
spkr_extra_buf = 25 // 9 0 / / 8 0 / / 2 0
break
default :
// s p k r _ e x t r a _ b u f = I n t 3 2 ( 7 8 0 / f p s ) / / n o r m a l l y i t s h o u l d c o m e u p a s 2 6 , b u t t h i s w a y i t i s c a l c u l a t e d w i t h F P S
spkr_extra_buf = 0 // 2 6
break
2020-01-28 06:54:03 +00:00
}
2024-01-06 15:11:52 +00:00
soundGapLabel . title = String ( spkr_extra_buf )
soundGapSlider . integerValue = Int ( spkr_extra_buf )
}
func setCPUClockSpeed ( freq : Double ) {
spkr_stopAll ( ) ;
2020-05-28 02:12:28 +00:00
2024-01-06 15:11:52 +00:00
MHz_6502 = freq
clk_6502_per_frm = UInt32 ( MHz_6502 * M / Double ( fps ) )
clk_6502_per_frm_set = clk_6502_per_frm
2020-05-28 02:12:28 +00:00
2024-01-06 15:11:52 +00:00
spkr_extra_buf = 0
// s e t S p k r E x t r a b u f ( f r e q : f r e q )
2020-01-28 06:54:03 +00:00
}
2024-01-06 15:11:52 +00:00
2020-01-28 06:54:03 +00:00
2024-01-06 15:11:52 +00:00
@IBOutlet weak var soundGapLabel : NSTextFieldCell !
2020-07-09 21:15:00 +00:00
@IBAction func extraBuf ( _ sender : NSSlider ) {
spkr_extra_buf = sender . intValue
2024-01-06 15:11:52 +00:00
soundGapLabel . title = String ( spkr_extra_buf )
}
@IBOutlet weak var ledingInitEdgeLabel : NSTextFieldCell !
@IBAction func leadingInitEdgeSelected ( _ sender : NSSlider ) {
SPKR_INITIAL_LEADING_EDGE = sender . floatValue
ledingInitEdgeLabel . title = " ILE: " + String ( SPKR_INITIAL_LEADING_EDGE )
}
@IBOutlet weak var leadingEdgeLabel : NSTextFieldCell !
@IBAction func leadingEdgeSelected ( _ sender : NSSlider ) {
SPKR_FADE_LEADING_EDGE = sender . floatValue
leadingEdgeLabel . title = " LE: " + String ( SPKR_FADE_LEADING_EDGE )
}
@IBOutlet weak var trailingInitEdgeLabel : NSTextFieldCell !
@IBAction func trailingInitEdgeSelected ( _ sender : NSSlider ) {
SPKR_INITIAL_TRAILING_EDGE = sender . floatValue
trailingInitEdgeLabel . title = " ITE: " + String ( SPKR_INITIAL_TRAILING_EDGE )
}
@IBOutlet weak var trailingEdgeLabel : NSTextFieldCell !
@IBAction func trailingEdgeSelected ( _ sender : NSSlider ) {
SPKR_FADE_TRAILING_EDGE = sender . floatValue
trailingEdgeLabel . title = " TE: " + String ( SPKR_FADE_TRAILING_EDGE )
2020-07-09 21:15:00 +00:00
}
2020-06-23 02:23:41 +00:00
2024-01-06 15:11:52 +00:00
@IBOutlet weak var wozExtraLabel : NSTextFieldCell !
@IBAction func wozExtraSelected ( _ sender : NSSlider ) {
extraForward = Int32 ( sender . floatValue )
wozExtraLabel . title = " WE: " + String ( extraForward )
}
@IBOutlet weak var EMALabel : NSTextFieldCell !
@IBAction func EMASelected ( _ sender : NSSlider ) {
spkr_ema_len = Int32 ( sender . floatValue )
EMALabel . title = " EMA: " + String ( spkr_ema_len )
}
2020-06-23 02:23:41 +00:00
func setSimulationMode ( mode : String ) {
switch ( mode ) {
case " Eco " :
cpuMode = cpuMode_eco
2020-06-17 16:46:17 +00:00
2020-06-23 02:23:41 +00:00
fps = DEFAULT_FPS
2024-01-06 15:11:52 +00:00
video_fps_divider = ECO_VIDEO_DIV
spkr_fps_divider = DEF_SPKR_DIV
2020-06-23 02:23:41 +00:00
break
case " Game " :
cpuMode = cpuMode_game
cpuState = cpuState_running
fps = GAME_FPS
video_fps_divider = GAME_VIDEO_DIV
2024-01-06 15:11:52 +00:00
spkr_fps_divider = GAME_SPKR_DIV
2020-06-23 02:23:41 +00:00
break
default :
cpuMode = cpuMode_normal
cpuState = cpuState_running
fps = DEFAULT_FPS
video_fps_divider = DEF_VIDEO_DIV
2024-01-06 15:11:52 +00:00
spkr_fps_divider = DEF_SPKR_DIV
2020-06-23 02:23:41 +00:00
break
2020-06-17 16:46:17 +00:00
}
2020-06-24 05:59:20 +00:00
2024-01-06 15:11:52 +00:00
// s p k r _ f p s _ d i v i d e r = f p s / s p k r _ f p s
// s p k r _ f p s = f p s ;
spkr_play_timeout = SPKR_PLAY_TIMEOUT // * s p k r _ f p s _ d i v i d e r
// p i x e l T r a i l = p o w ( 2 5 6 , 1 / D o u b l e ( f p s / v i d e o _ f p s _ d i v i d e r / 3 ) )
2020-06-24 05:59:20 +00:00
// s p k r _ b u f _ s i z e = s p k r _ s a m p l e _ r a t e * 2 / s p k r _ f p s
2024-01-06 15:11:52 +00:00
#if SCHEDULER_CVDISPLAYLINK
#else
2020-06-23 02:23:41 +00:00
newUpdateTimer ( timeInterval : 1 / Double ( fps ) )
2024-01-06 15:11:52 +00:00
#endif
2020-06-23 02:23:41 +00:00
setCPUClockSpeed ( freq : MHz_6502 )
// TODO: B e t t e r w a y t o d e a l w i t h s p e a k e r ! ! !
2024-01-06 15:11:52 +00:00
spkr_play_timeout = SPKR_PLAY_TIMEOUT * Int32 ( video_fps_divider )
2020-06-23 02:23:41 +00:00
}
2020-07-04 17:13:12 +00:00
@IBAction func setCPUMode ( _ sender : NSPopUpButton ) {
setSimulationMode ( mode : sender . selectedItem ? . title ? ? " Normal " )
2020-06-17 16:46:17 +00:00
}
2020-01-28 06:54:03 +00:00
2024-01-06 15:11:52 +00:00
@IBOutlet weak var initialLeadEdgeSlider : NSSlider !
@IBOutlet weak var leadEdgeSlider : NSSlider !
@IBOutlet weak var initialTailEdgeSlider : NSSlider !
@IBOutlet weak var tailEdgeSlider : NSSlider !
@IBOutlet weak var soundGapSlider : NSSlider !
// @ I B O u t l e t w e a k v a r s o u n d G a p : N S T e x t F i e l d C e l l !
//
// @ I B A c t i o n f u n c S o u n d G a p C h a n g e d ( _ s e n d e r : N S S t e p p e r ) {
// S o u n d G a p . i n t e g e r V a l u e = s e n d e r . i n t e g e r V a l u e
// s p k r _ e x t r a _ b u f = I n t 3 2 ( s e n d e r . i n t e g e r V a l u e )
// }
2020-05-17 14:49:05 +00:00
2020-06-17 16:46:17 +00:00
@IBAction func CRTMonitorOnOff ( _ sender : NSButton ) {
CRTMonitor = sender . state = = . on
scanLines . isHidden = ! CRTMonitor
2020-08-02 22:00:42 +00:00
if ( CRTMonitor ) {
2024-01-06 15:11:52 +00:00
textDisplay . textColor = . white
2020-08-02 22:00:42 +00:00
// TODO: A d j u s t g a m m a s o p i x e l s a r e b r i g h t e r
}
else {
2024-01-06 15:11:52 +00:00
textDisplay . textColor = colorWhite
2020-08-02 22:00:42 +00:00
// TODO: A d j u s t g a m m a s o p i x e l s a r e d i m m e r
}
2020-06-21 05:14:39 +00:00
hires . RenderFullScreen ( )
2020-06-21 01:46:26 +00:00
}
2020-07-02 00:47:43 +00:00
func ColorMonitorSelector ( color : Bool ) {
ColorMonitor = color
2020-06-21 05:14:39 +00:00
if ( ColorMonitor ) {
2024-01-06 15:11:52 +00:00
textDisplay . textColor = colorWhite // . w h i t e
2020-06-21 05:14:39 +00:00
}
else {
2024-01-06 15:11:52 +00:00
textDisplay . textColor = colorGreen // . g r e e n
2020-06-21 05:14:39 +00:00
}
2020-07-02 00:47:43 +00:00
hires . RenderFullScreen ( )
}
@IBAction func ColorMonitorOnOff ( _ sender : NSButton ) {
ColorMonitorSelector ( color : sender . state = = . on )
2020-06-21 05:14:39 +00:00
}
2020-07-08 07:56:45 +00:00
func MonoMonitorChange ( color : String ) {
switch color {
case " Green " :
2020-06-21 05:14:39 +00:00
ColorMonitor = false
monoColor = colorGreen
hires . monoColor = hires . color_green
2020-07-08 07:56:45 +00:00
case " Amber " :
2020-06-21 05:14:39 +00:00
ColorMonitor = false
monoColor = colorOrange
hires . monoColor = hires . color_orange
2020-07-08 07:56:45 +00:00
2020-06-21 05:14:39 +00:00
default :
2020-07-08 07:56:45 +00:00
ColorMonitor = false
2020-06-21 05:14:39 +00:00
monoColor = colorWhite
2020-07-08 07:56:45 +00:00
hires . monoColor = hires . color_white
2020-06-21 05:14:39 +00:00
}
2024-01-06 15:11:52 +00:00
textDisplay . textColor = monoColor
2020-06-21 05:14:39 +00:00
hires . RenderFullScreen ( )
2020-06-17 16:46:17 +00:00
}
2020-07-08 07:56:45 +00:00
@IBAction func MonitorChange ( _ sender : NSButton ) {
switch sender . title {
case " Green Mono " :
MonoMonitorChange ( color : " Green " )
case " Amber Mono " :
MonoMonitorChange ( color : " Amber " )
default :
MonoMonitorChange ( color : " White " )
}
}
2020-06-02 17:10:18 +00:00
@IBAction func Keyboard2JoystickOnOff ( _ sender : NSButton ) {
Keyboard2Joystick = sender . state = = . on
}
@IBAction func Mouse2JoystickOnOff ( _ sender : NSButton ) {
Mouse2Joystick = sender . state = = . on
}
@IBAction func MouseOnOff ( _ sender : NSButton ) {
MouseInterface = sender . state = = . on
}
2020-05-28 02:12:28 +00:00
@IBAction func QuickDisk ( _ sender : NSButton ) {
if sender . state = = . on {
2020-06-12 05:44:53 +00:00
diskAccelerator_enabled = 1 ;
2020-05-28 02:12:28 +00:00
}
else {
2020-06-12 05:44:53 +00:00
diskAccelerator_enabled = 0 ;
2020-05-28 02:12:28 +00:00
}
}
2020-06-12 06:16:26 +00:00
@IBAction func DiskSound ( _ sender : NSButton ) {
if sender . state = = . on {
disk_sfx_enabled = 1 ;
}
else {
disk_sfx_enabled = 0 ;
}
}
2020-06-03 17:23:55 +00:00
2020-07-04 17:13:12 +00:00
func openDiskImage ( url : URL ) {
2024-01-14 01:47:42 +00:00
woz_eject ( )
2020-07-04 17:13:12 +00:00
switch url . pathExtension . uppercased ( ) {
case " WOZ " :
let err = woz_loadFile ( url . path )
if err = = WOZ_ERR_OK {
NSDocumentController . shared . noteNewRecentDocumentURL ( URL ( fileURLWithPath : url . path ) )
}
else {
self . chk_woz_load ( err : err )
}
case " DSK " , " DO " , " PO " :
let err = dsk2woz ( url . path )
if err = = WOZ_ERR_OK {
let err = woz_parseBuffer ( )
if err = = WOZ_ERR_OK {
NSDocumentController . shared . noteNewRecentDocumentURL ( URL ( fileURLWithPath : url . path ) )
}
}
else {
self . chk_woz_load ( err : err )
}
default :
break
}
}
@objc func openDiskImageDialog ( ) {
2020-06-03 17:23:55 +00:00
let openPanel = NSOpenPanel ( )
2020-06-26 02:52:23 +00:00
openPanel . title = " Open Disk Image "
2020-06-03 17:23:55 +00:00
openPanel . allowsMultipleSelection = false
openPanel . canChooseDirectories = false
openPanel . canCreateDirectories = false
openPanel . canChooseFiles = true
openPanel . allowedFileTypes = [ " dsk " , " do " , " po " , " nib " , " woz " ]
openPanel . begin { ( result ) -> Void in
if result = = NSApplication . ModalResponse . OK {
2020-07-04 17:13:12 +00:00
// p r i n t ( " f i l e : " , o p e n P a n e l . u r l ! . p a t h )
2020-06-03 17:23:55 +00:00
// D o w h a t y o u w i l l
// I f t h e r e ' s o n l y o n e U R L , s u r e l y ' o p e n P a n e l . U R L '
// b u t o t h e r w i s e a f o r l o o p w o r k s
2020-07-04 17:13:12 +00:00
if let url = openPanel . url {
self . openDiskImage ( url : url )
}
else {
let a = NSAlert ( )
a . messageText = " File Not Found "
a . informativeText = " Could not locate selected file "
a . alertStyle = . critical
2020-06-29 04:00:25 +00:00
2020-07-04 17:13:12 +00:00
a . beginSheetModal ( for : self . view . window ! )
2020-06-03 17:23:55 +00:00
}
}
}
}
2020-06-26 02:52:23 +00:00
@objc func saveDiskImage ( ) {
let openPanel = NSOpenPanel ( )
openPanel . title = " Save Disk Image "
openPanel . allowsMultipleSelection = false
openPanel . canChooseDirectories = false
openPanel . canCreateDirectories = false
openPanel . canChooseFiles = true
openPanel . allowedFileTypes = [ " dsk " , " do " , " po " , " nib " , " woz " ]
openPanel . begin { ( result ) -> Void in
if result = = NSApplication . ModalResponse . OK {
2020-07-04 17:13:12 +00:00
// p r i n t ( " f i l e : " , o p e n P a n e l . u r l ! . p a t h )
2020-06-26 02:52:23 +00:00
// D o w h a t y o u w i l l
// I f t h e r e ' s o n l y o n e U R L , s u r e l y ' o p e n P a n e l . U R L '
// b u t o t h e r w i s e a f o r l o o p w o r k s
if let filePath = openPanel . url ? . path {
2020-07-04 17:13:12 +00:00
let woz_err = woz_saveFile ( filePath )
2020-06-26 02:52:23 +00:00
if woz_err = = WOZ_ERR_OK {
NSDocumentController . shared . noteNewRecentDocumentURL ( URL ( fileURLWithPath : filePath ) )
}
else {
self . chk_woz_load ( err : woz_err )
}
}
}
}
}
2020-07-09 21:15:00 +00:00
@IBOutlet weak var QuickDisk_Disk1 : NSMenuItem !
@IBOutlet weak var QuickDisk_Disk2 : NSMenuItem !
@IBOutlet weak var DiskSound_Disk1 : NSMenuItem !
@IBOutlet weak var DiskSound_Disk2 : NSMenuItem !
2020-07-08 20:12:46 +00:00
@IBAction func Disk1 ( _ sender : NSPopUpButton ) {
switch sender . selectedItem ? . tag {
case 1 : // O p e n
openDiskImageDialog ( )
case 2 : // S a v e
saveFile ( )
case 3 : // S a v e A s . . .
saveFileAs ( )
case 4 : // E j e c t
woz_eject ( )
case 21 : // Q u i c k D i s k
if diskAccelerator_enabled = = 0 {
diskAccelerator_enabled = 1 ;
}
else {
diskAccelerator_enabled = 0 ;
}
2020-07-09 21:15:00 +00:00
let state : NSControl . StateValue = diskAccelerator_enabled = = 1 ? . on : . off
QuickDisk_Disk1 ? . state = state
QuickDisk_Disk2 ? . state = state
2020-07-08 20:12:46 +00:00
break
case 22 : // D i s k S o u n d
if disk_sfx_enabled = = 0 {
disk_sfx_enabled = 1 ;
}
else {
disk_sfx_enabled = 0 ;
}
2020-07-09 21:15:00 +00:00
let state : NSControl . StateValue = disk_sfx_enabled = = 1 ? . on : . off
DiskSound_Disk1 ? . state = state
DiskSound_Disk2 ? . state = state
2020-07-08 20:12:46 +00:00
break
case 1000 : // O p e n D e f a u l t D i s k I m a g e
if let menuIdentifier = sender . selectedItem ? . title {
let woz_err = woz_loadFile ( Bundle . main . resourcePath ! + " /dsk/ " + menuIdentifier + " .woz " )
2024-01-06 15:11:52 +00:00
ViewController . shared ? . chk_woz_load ( err : woz_err )
2020-07-08 20:12:46 +00:00
woz_flags . image_file_readonly = 1
}
default :
break
}
2020-06-03 17:23:55 +00:00
}
2020-06-19 22:16:27 +00:00
@IBAction func traceEnable ( _ sender : NSButton ) {
switch sender . state {
case . on :
2024-01-06 15:11:52 +00:00
m6502 . debugger . mask . trace = 1
2020-06-19 22:16:27 +00:00
openLog ( )
default :
2024-01-06 15:11:52 +00:00
m6502 . debugger . mask . trace = 0
2020-06-19 22:16:27 +00:00
closeLog ( )
}
}
2020-05-28 02:12:28 +00:00
2020-06-26 02:52:23 +00:00
func saveFile ( ) {
if ( woz_flags . image_file_readonly != 0 ) {
// i t i s r e a d o n l y , s a v e i t t o a d i f f e r e n t f i l e . . .
saveFileAs ( )
}
else {
// s a v e W O Z i m a g e f i l e o v e r w r i t i n g t h e o r i g i n a l i m a g e
woz_saveFile ( nil )
}
}
func saveFileAs ( ) {
let savePanel = NSSavePanel ( )
savePanel . title = " Save WOZ Disk Image As... "
savePanel . begin { ( result ) in
if result . rawValue = = NSApplication . ModalResponse . OK . rawValue {
woz_saveFile ( savePanel . url ? . path ) ;
}
else {
let a = NSAlert ( )
a . messageText = " Are you sure? "
a . informativeText = " Are you sure you would like to cancel and lose all modification you have made to the Disk Image? \n ALERT: You will lose all new files and modified files from this Disk Image since you loaded. Your decision if permanent and irreversible! "
a . addButton ( withTitle : " Save " )
a . addButton ( withTitle : " Cancel " )
a . alertStyle = . warning
a . beginSheetModal ( for : self . view . window ! , completionHandler : { ( modalResponse ) -> Void in
if modalResponse = = . alertFirstButtonReturn {
self . saveFileAs ( )
}
} )
}
}
}
2024-01-06 15:11:52 +00:00
func Cheat_Wavy_Navy_Victory ( ) {
#if ! DEBUGGER
JUMP ( 0x1528 ) // c a l l e d w h e n p l a y e r c l e a r s t h e l e v e l
#endif
}
func Cheat_Wavy_Navy_Add_3_Ships ( ) {
#if ! DEBUGGER
let ships = min ( getMEM ( 0x4746 ) + 3 , 9 )
setMEM ( 0x4746 , ships )
m6502 . A = ships
// m 6 5 0 2 . X = 0 x 1 0
setMEM16 ( 0x4728 , 0x16F0 ) // c u r s o r p o s : 0 x 4 7 2 8 : x , 0 x 4 7 2 9 : y
CALL ( 0x1FDA ) // p o s i t i o n a n d n u m b e r n e e d e d ? A : N u m b e r o f s h i p s X : 0 x 1 0
#endif
}
func Cheat_Wavy_Navy_OtherCheats ( ) {
#if ! DEBUGGER
// R e p l a c e S T C / S B C $ 0 x 1 t o N O P s . . .
setMEM ( 0x1E63 , 0xEA )
setMEM ( 0x1E64 , 0xEA )
setMEM ( 0x1E65 , 0xEA )
// / / c a l l t o d e c e a s e
// s e t M E M ( 0 x 1 5 5 6 , 0 x E A ) ;
// s e t M E M ( 0 x 1 5 5 7 , 0 x E A ) ;
// s e t M E M ( 0 x 1 5 5 8 , 0 x E A ) ;
// s e t M E M ( 0 x 1 5 F 3 , 0 x E A ) ;
// s e t M E M ( 0 x 1 5 F 4 , 0 x E A ) ;
// s e t M E M ( 0 x 1 5 F 5 , 0 x E A ) ;
// s e t M E M ( 0 x 1 5 E A , 0 x E A ) ;
// s e t M E M ( 0 x 1 5 E B , 0 x E A ) ;
// / / n o e n d
// s e t M E M ( 0 x 1 5 1 5 , 0 x E A ) ;
// s e t M E M ( 0 x 1 5 1 6 , 0 x E A ) ;
// / / n o e n d
// s e t M E M ( 0 x 1 5 3 7 , 0 x E A ) ;
// s e t M E M ( 0 x 1 5 3 8 , 0 x E A ) ;
// l o s e t o w i n
setMEM ( 0x1545 , 0xEA )
setMEM ( 0x1546 , 0xEA )
// v a r i : U I n t 1 6 = 0 x 1 5 E A ;
// w h i l e i < 0 x 1 6 0 8 {
// s e t M E M ( i , 0 x E A )
// i + = 1
// }
#endif
}
func Cheat_Wavy_Navy_Never_Lose ( ) -> NSControl . StateValue {
#if ! DEBUGGER
// R e p l a c e S T C / S B C # $ 0 1 t o N O P s . . .
// s e t M E M ( 0 x 1 E 6 3 , 0 x E A )
// s e t M E M ( 0 x 1 E 6 4 , 0 x E A )
// s e t M E M ( 0 x 1 E 6 5 , 0 x E A )
if ( getMEM16 ( 0x1E64 ) = = 0x01E9 ) { // S B C # $ 0 1
// R e p l a c e S B C # $ 0 1 t o S B C # $ 0 0 . . .
setMEM ( 0x1E65 , 0 )
return . on
}
else if ( getMEM16 ( 0x1E64 ) = = 0x00E9 ) { // S B C # $ 0 0
// R e p l a c e S B C # $ 0 0 t o S B C # $ 0 1 . . .
setMEM ( 0x1E65 , 1 )
return . off
}
else {
print ( " Not Wavy Navy! " )
return . off
}
#else
return . off
#endif
}
func Cheat_Wavy_Navy_Lose_To_Win ( ) -> NSControl . StateValue {
#if ! DEBUGGER
if ( getMEM16 ( 0x1545 ) = = 0x09F0 ) { // B E Q $ 1 5 5 0
// l o s e t o w i n
setMEM16 ( 0x1545 , 0xEAEA ) // N O P N O P
return . on
}
else if ( getMEM16 ( 0x1545 ) = = 0xEAEA ) { // N O P N O P
// l o s e t o w i n
setMEM16 ( 0x1545 , 0x09F0 ) // B E Q $ 1 5 5 0
return . off
}
else {
print ( " Not Wavy Navy! " )
return . off
}
#else
return . off
#endif
}
func Get_Hard_Hat_Mack ( ) -> UInt8 {
#if ! DEBUGGER
return getMEM ( 0x4EDF )
#else
return 0
#endif
}
func Cheat_Hard_Hat_Mack ( add : UInt8 ) -> UInt8 {
#if ! DEBUGGER
let ships = min ( getMEM ( 0x4EDF ) + add , 9 )
setMEM ( 0x4EDF , ships )
// C A L L ( 0 x 1 2 1 9 ) / / s t a r t s f r o m t h e b e g i n n i n g
CALL ( 0x1A2B ) // r e f r e s h M a c k c o u n t e r o n s c r e e n
return ships
#else
return 0
#endif
}
func Cheat_Hard_Hat_Mack_Never_Lose ( ) -> NSControl . StateValue {
#if ! DEBUGGER
setMEM ( 0x0503 , 0x18 )
setMEM ( 0x0504 , 0x60 )
setMEM ( 0x50A5 , 0xEA )
setMEM ( 0x50A6 , 0xEA )
setMEM ( 0x50A7 , 0xEA )
#endif
return . on
}
2020-06-26 02:52:23 +00:00
}
@ _cdecl ( " woz_ask_to_save " )
func woz_ask_to_save ( ) {
2024-01-06 15:11:52 +00:00
ViewController . shared ? . saveFile ( )
2019-07-26 05:51:36 +00:00
}