diff --git a/fusepb/FuseX.xcodeproj/project.pbxproj b/fusepb/FuseX.xcodeproj/project.pbxproj index 9f73b313..2bb03fb8 100644 --- a/fusepb/FuseX.xcodeproj/project.pbxproj +++ b/fusepb/FuseX.xcodeproj/project.pbxproj @@ -7,8 +7,20 @@ objects = { /* Begin PBXBuildFile section */ + 03A9A1325AFA09F88C578556 /* mlt.icns in Resources */ = {isa = PBXBuildFile; fileRef = 06FA366DDA50516B0E710919 /* mlt.icns */; }; + 133B0AD3B7A88DDE320CC90A /* spc.icns in Resources */ = {isa = PBXBuildFile; fileRef = 6B9DA7F77DF8F6DD5023E33A /* spc.icns */; }; + 1B79AE9FC29230B4DE1FF5DC /* sta.icns in Resources */ = {isa = PBXBuildFile; fileRef = 1C8D4F4DD60D5C25EDFCCA5A /* sta.icns */; }; + 24B929685CC83115F56DC8C4 /* mgtsnp.icns in Resources */ = {isa = PBXBuildFile; fileRef = D38E7769E2D2868BBA22FAF0 /* mgtsnp.icns */; }; + 3838E5C60CA2380E55AD418B /* pok.icns in Resources */ = {isa = PBXBuildFile; fileRef = D90C923FA0D816592D66D6AB /* pok.icns */; }; + 45D5B2DAFBC8D29B19A693F0 /* img.icns in Resources */ = {isa = PBXBuildFile; fileRef = AC1A633A88D7CB61D74DA1D1 /* img.icns */; }; 576F061291E1888735FB9D38 /* FuseQLPreview.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 2395678A67FCB7B7DAFF9A83 /* FuseQLPreview.appex */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 58ED2BB163960C572FE0F3E3 /* pzx.icns in Resources */ = {isa = PBXBuildFile; fileRef = 23103D2BCD71D4B9DEC65FCF /* pzx.icns */; }; 70561DA4F03E4F3DA5B85553 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAA54F20E902456BACB24998 /* MetalKit.framework */; }; + 70C4AAF3348BCAAF406ABD72 /* fdi.icns in Resources */ = {isa = PBXBuildFile; fileRef = 0434807795A36A2ADBE801FD /* fdi.icns */; }; + 77D4DC318FB2F3901F6F1F0C /* ltp.icns in Resources */ = {isa = PBXBuildFile; fileRef = 73634C6A823C65469329182E /* ltp.icns */; }; + 7F7BB782D4AEBC99DC6AF1C8 /* d80.icns in Resources */ = {isa = PBXBuildFile; fileRef = 3B061F2A9CBA3011FBE7A640 /* d80.icns */; }; + 83B45F940FB7799F67BC0C7E /* wav.icns in Resources */ = {isa = PBXBuildFile; fileRef = A0EDEF7D7639C051DFFA7415 /* wav.icns */; }; + A077D12A865257945F8ED735 /* d40.icns in Resources */ = {isa = PBXBuildFile; fileRef = 0DE6490BEE632A2E645C4086 /* d40.icns */; }; B2D0915DE32D43E89E59E3EF /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8287F6EDEBAC4FFA8708CC4E /* Metal.framework */; }; B6013812164692F5005FD3AE /* Fuse.iconset in Resources */ = {isa = PBXBuildFile; fileRef = B6013811164692F5005FD3AE /* Fuse.iconset */; }; B61159BF0EEE99D50029FEA3 /* Graphics_Filter.png in Resources */ = {isa = PBXBuildFile; fileRef = B61159BE0EEE99D50029FEA3 /* Graphics_Filter.png */; }; @@ -289,6 +301,9 @@ B6F66E351E473D68005B270A /* memory_pages.c in Sources */ = {isa = PBXBuildFile; fileRef = B6F66E331E473D68005B270A /* memory_pages.c */; }; B6FA759D0C1D7507007F5A10 /* audiofile.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6FA759C0C1D7507007F5A10 /* audiofile.framework */; }; B6FA75C60C1D76A5007F5A10 /* audiofile.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = B6FA759C0C1D7507007F5A10 /* audiofile.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + C0C0617E40B5762CC966FBB0 /* opu.icns in Resources */ = {isa = PBXBuildFile; fileRef = E1F94955E564E275BA43C35D /* opu.icns */; }; + C56D1BEAC229ADB9FFF68BA0 /* mgt.icns in Resources */ = {isa = PBXBuildFile; fileRef = E58E141DFD2813AA4F512B32 /* mgt.icns */; }; + CA66F1720693EF645640178F /* opd.icns in Resources */ = {isa = PBXBuildFile; fileRef = 6EE199DF1B56E0F5DC20ACDD /* opd.icns */; }; CC2086963F8A491084EEBE3B /* DisplayShaders.metal in Sources */ = {isa = PBXBuildFile; fileRef = 2BDC12F02C4E48F98494D156 /* DisplayShaders.metal */; }; D12E7FF3292596B200185E4D /* AppSandboxFileAccess.m in Sources */ = {isa = PBXBuildFile; fileRef = D12E7FED292596B100185E4D /* AppSandboxFileAccess.m */; }; D12E7FF4292596B200185E4D /* AppSandboxFileAccessOpenSavePanelDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D12E7FEE292596B100185E4D /* AppSandboxFileAccessOpenSavePanelDelegate.m */; }; @@ -312,7 +327,7 @@ FE8E3FD92FD70FFB009FDB81 /* libssh2.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = FE8E3FD72FD70FFB009FDB81 /* libssh2.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; FE8E3FDF2FDAE9CA009FDB81 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = FE8E3FDE2FDAE9CA009FDB81 /* Sparkle */; }; FE8E3FE22FDB108A009FDB81 /* FuseQLThumbnail.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = FE8E3FE12FDB108A009FDB81 /* FuseQLThumbnail.appex */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - FE8E40202FD71100009FDB81 /* (null) in Copy Files */ = {isa = PBXBuildFile; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + FE8E40202FD71100009FDB81 /* BuildFile in Copy Files */ = {isa = PBXBuildFile; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; FE9443BC2F881C540059A578 /* engine_argv.c in Sources */ = {isa = PBXBuildFile; fileRef = FE9443B72F881C540059A578 /* engine_argv.c */; }; FE9443BD2F881C540059A578 /* lexer.c in Sources */ = {isa = PBXBuildFile; fileRef = FE9443B02F881C540059A578 /* lexer.c */; }; FE9443BE2F881C540059A578 /* engine_fs.c in Sources */ = {isa = PBXBuildFile; fileRef = FE9443B92F881C540059A578 /* engine_fs.c */; }; @@ -429,7 +444,7 @@ files = ( B6FA75C60C1D76A5007F5A10 /* audiofile.framework in Copy Files */, FED24C472EE104C60013DD32 /* mbedtls.framework in Copy Files */, - FE8E40202FD71100009FDB81 /* (null) in Copy Files */, + FE8E40202FD71100009FDB81 /* BuildFile in Copy Files */, B6D65C3818A645A100170B64 /* gcrypt.framework in Copy Files */, FE8E3FD92FD70FFB009FDB81 /* libssh2.framework in Copy Files */, ); @@ -449,14 +464,25 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0434807795A36A2ADBE801FD /* fdi.icns */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.icns; name = fdi.icns; path = resources/fdi.icns; sourceTree = SOURCE_ROOT; }; + 06FA366DDA50516B0E710919 /* mlt.icns */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.icns; name = mlt.icns; path = resources/mlt.icns; sourceTree = SOURCE_ROOT; }; 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 0DE6490BEE632A2E645C4086 /* d40.icns */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.icns; name = d40.icns; path = resources/d40.icns; sourceTree = SOURCE_ROOT; }; 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 1C8D4F4DD60D5C25EDFCCA5A /* sta.icns */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.icns; name = sta.icns; path = resources/sta.icns; sourceTree = SOURCE_ROOT; }; + 23103D2BCD71D4B9DEC65FCF /* pzx.icns */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.icns; name = pzx.icns; path = resources/pzx.icns; sourceTree = SOURCE_ROOT; }; 2395678A67FCB7B7DAFF9A83 /* FuseQLPreview.appex */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "wrapper.app-extension"; name = FuseQLPreview.appex; path = ../3rdparty/FuseGenerator/build/Deployment/FuseQLPreview.appex; sourceTree = ""; }; 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 2BDC12F02C4E48F98494D156 /* DisplayShaders.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = DisplayShaders.metal; sourceTree = ""; }; + 3B061F2A9CBA3011FBE7A640 /* d80.icns */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.icns; name = d80.icns; path = resources/d80.icns; sourceTree = SOURCE_ROOT; }; + 6B9DA7F77DF8F6DD5023E33A /* spc.icns */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.icns; name = spc.icns; path = resources/spc.icns; sourceTree = SOURCE_ROOT; }; + 6EE199DF1B56E0F5DC20ACDD /* opd.icns */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.icns; name = opd.icns; path = resources/opd.icns; sourceTree = SOURCE_ROOT; }; + 73634C6A823C65469329182E /* ltp.icns */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.icns; name = ltp.icns; path = resources/ltp.icns; sourceTree = SOURCE_ROOT; }; 8287F6EDEBAC4FFA8708CC4E /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = /System/Library/Frameworks/Metal.framework; sourceTree = ""; }; 9651D9A4AA56B244FA98440C /* FuseQLThumbnail.appex */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "wrapper.app-extension"; name = FuseQLThumbnail.appex; path = ../3rdparty/FuseGenerator/build/Deployment/FuseQLThumbnail.appex; sourceTree = ""; }; + A0EDEF7D7639C051DFFA7415 /* wav.icns */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.icns; name = wav.icns; path = resources/wav.icns; sourceTree = SOURCE_ROOT; }; + AC1A633A88D7CB61D74DA1D1 /* img.icns */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.icns; name = img.icns; path = resources/img.icns; sourceTree = SOURCE_ROOT; }; B6013811164692F5005FD3AE /* Fuse.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; name = Fuse.iconset; path = ../Fuse.iconset; sourceTree = ""; }; B6018479065A586900B0BE59 /* zxatasp.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = zxatasp.c; sourceTree = ""; }; B601847A065A586900B0BE59 /* zxatasp.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = zxatasp.h; sourceTree = ""; }; @@ -820,6 +846,10 @@ D1DF6DD726F8077F004A4AB7 /* debug.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = debug.png; sourceTree = ""; }; D1ECC73C2924069800147252 /* ttx2000s.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ttx2000s.h; sourceTree = ""; }; D1ECC73D2924069800147252 /* ttx2000s.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ttx2000s.c; sourceTree = ""; }; + D38E7769E2D2868BBA22FAF0 /* mgtsnp.icns */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.icns; name = mgtsnp.icns; path = resources/mgtsnp.icns; sourceTree = SOURCE_ROOT; }; + D90C923FA0D816592D66D6AB /* pok.icns */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.icns; name = pok.icns; path = resources/pok.icns; sourceTree = SOURCE_ROOT; }; + E1F94955E564E275BA43C35D /* opu.icns */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.icns; name = opu.icns; path = resources/opu.icns; sourceTree = SOURCE_ROOT; }; + E58E141DFD2813AA4F512B32 /* mgt.icns */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = image.icns; name = mgt.icns; path = resources/mgt.icns; sourceTree = SOURCE_ROOT; }; EAA54F20E902456BACB24998 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = /System/Library/Frameworks/MetalKit.framework; sourceTree = ""; }; F536B56503A0C275011517A0 /* utils.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = utils.c; path = ../utils.c; sourceTree = SOURCE_ROOT; }; F541FB5E03B0B33401FF8235 /* scaler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = scaler.h; path = ../ui/scaler/scaler.h; sourceTree = SOURCE_ROOT; }; @@ -1039,7 +1069,7 @@ name = Products; sourceTree = ""; }; - 29B97314FDCFA39411CA2CEA /* Fuse */ = { + 29B97314FDCFA39411CA2CEA = { isa = PBXGroup; children = ( FE8E3FE12FDB108A009FDB81 /* FuseQLThumbnail.appex */, @@ -1223,6 +1253,21 @@ B643BB980403A13600A864FD /* tzx.icns */, B6676DB0040C348F00B2BFEF /* z80.icns */, B6F0481A0952B5FD006D8005 /* zxs.icns */, + 0434807795A36A2ADBE801FD /* fdi.icns */, + A0EDEF7D7639C051DFFA7415 /* wav.icns */, + 23103D2BCD71D4B9DEC65FCF /* pzx.icns */, + 6B9DA7F77DF8F6DD5023E33A /* spc.icns */, + 1C8D4F4DD60D5C25EDFCCA5A /* sta.icns */, + 73634C6A823C65469329182E /* ltp.icns */, + D38E7769E2D2868BBA22FAF0 /* mgtsnp.icns */, + AC1A633A88D7CB61D74DA1D1 /* img.icns */, + E58E141DFD2813AA4F512B32 /* mgt.icns */, + 6EE199DF1B56E0F5DC20ACDD /* opd.icns */, + E1F94955E564E275BA43C35D /* opu.icns */, + D90C923FA0D816592D66D6AB /* pok.icns */, + 0DE6490BEE632A2E645C4086 /* d40.icns */, + 3B061F2A9CBA3011FBE7A640 /* d80.icns */, + 06FA366DDA50516B0E710919 /* mlt.icns */, ); path = resources; sourceTree = ""; @@ -1940,10 +1985,11 @@ French, German, ); - mainGroup = 29B97314FDCFA39411CA2CEA /* Fuse */; + mainGroup = 29B97314FDCFA39411CA2CEA; packageReferences = ( FE8E3FDD2FDAE9CA009FDB81 /* XCRemoteSwiftPackageReference "Sparkle" */, ); + productRefGroup = 19C28FACFE9D520D11CA2CBB /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( @@ -2035,6 +2081,21 @@ B629532E114FB265007808E0 /* libspectrum.h.in in Resources */, B61700F4163EAF8D00142336 /* PokeMemory.xib in Resources */, B6013812164692F5005FD3AE /* Fuse.iconset in Resources */, + 70C4AAF3348BCAAF406ABD72 /* fdi.icns in Resources */, + 83B45F940FB7799F67BC0C7E /* wav.icns in Resources */, + 58ED2BB163960C572FE0F3E3 /* pzx.icns in Resources */, + 133B0AD3B7A88DDE320CC90A /* spc.icns in Resources */, + 1B79AE9FC29230B4DE1FF5DC /* sta.icns in Resources */, + 77D4DC318FB2F3901F6F1F0C /* ltp.icns in Resources */, + 24B929685CC83115F56DC8C4 /* mgtsnp.icns in Resources */, + 45D5B2DAFBC8D29B19A693F0 /* img.icns in Resources */, + C56D1BEAC229ADB9FFF68BA0 /* mgt.icns in Resources */, + CA66F1720693EF645640178F /* opd.icns in Resources */, + C0C0617E40B5762CC966FBB0 /* opu.icns in Resources */, + 3838E5C60CA2380E55AD418B /* pok.icns in Resources */, + A077D12A865257945F8ED735 /* d40.icns in Resources */, + 7F7BB782D4AEBC99DC6AF1C8 /* d80.icns in Resources */, + 03A9A1325AFA09F88C578556 /* mlt.icns in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2059,8 +2120,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "make -"; + shellScript = "make\n"; }; /* End PBXShellScriptBuildPhase section */ diff --git a/fusepb/Info-FuseX.plist b/fusepb/Info-FuseX.plist index 98ccc5da..6bed9b1f 100644 --- a/fusepb/Info-FuseX.plist +++ b/fusepb/Info-FuseX.plist @@ -68,7 +68,7 @@ FDI CFBundleTypeIconFile - blank + fdi CFBundleTypeName ZX Spectrum Disk Image CFBundleTypeRole @@ -246,7 +246,7 @@ WAV CFBundleTypeIconFile - blank + wav CFBundleTypeName ZX Spectrum Tape Image CFBundleTypeRole @@ -314,7 +314,7 @@ PZX CFBundleTypeIconFile - blank + pzx CFBundleTypeName ZX Spectrum Tape Image CFBundleTypeRole @@ -352,7 +352,7 @@ SPC CFBundleTypeIconFile - blank + spc CFBundleTypeName ZX Spectrum Tape Image CFBundleTypeRole @@ -369,7 +369,7 @@ STA CFBundleTypeIconFile - blank + sta CFBundleTypeName ZX Spectrum Tape Image CFBundleTypeRole @@ -386,7 +386,7 @@ LTP CFBundleTypeIconFile - blank + ltp CFBundleTypeName ZX Spectrum Tape Image CFBundleTypeRole @@ -454,7 +454,7 @@ MGTSNP CFBundleTypeIconFile - blank + mgtsnp CFBundleTypeName ZX Spectrum Snapshot CFBundleTypeRole @@ -471,7 +471,7 @@ IMG CFBundleTypeIconFile - blank + img CFBundleTypeName ZX Spectrum Disk Image CFBundleTypeRole @@ -488,7 +488,7 @@ MGT CFBundleTypeIconFile - blank + mgt CFBundleTypeName ZX Spectrum Disk Image CFBundleTypeRole @@ -505,7 +505,7 @@ OPD CFBundleTypeIconFile - blank + opd CFBundleTypeName ZX Spectrum Disk Image CFBundleTypeRole @@ -522,7 +522,7 @@ OPU CFBundleTypeIconFile - blank + opu CFBundleTypeName ZX Spectrum Disk Image CFBundleTypeRole @@ -539,7 +539,7 @@ POK CFBundleTypeIconFile - blank + pok CFBundleTypeName ZX Spectrum Poke File CFBundleTypeRole @@ -556,7 +556,7 @@ D40 CFBundleTypeIconFile - blank + d40 CFBundleTypeName ZX Spectrum Disk Image CFBundleTypeRole @@ -573,7 +573,7 @@ D80 CFBundleTypeIconFile - blank + d80 CFBundleTypeName ZX Spectrum Disk Image CFBundleTypeRole @@ -590,7 +590,7 @@ MLT CFBundleTypeIconFile - blank + mlt CFBundleTypeName ZX Spectrum Screen Image CFBundleTypeRole @@ -750,7 +750,7 @@ UTTypeDescription ZX Spectrum FDI Disk Image UTTypeIconFile - blank + fdi UTTypeIdentifier net.sourceforge.projects.fuse-emulator.fdi UTTypeTagSpecification @@ -769,7 +769,7 @@ UTTypeDescription ZX Spectrum DISCiPLE/+D Disk Image UTTypeIconFile - blank + mgt UTTypeIdentifier net.sourceforge.projects.fuse-emulator.mgt UTTypeReferenceURL @@ -1077,7 +1077,7 @@ UTTypeDescription ZX Spectrum DISCiPLE/+D Disk Image UTTypeIconFile - blank + img UTTypeIdentifier net.sourceforge.projects.fuse-emulator.img UTTypeReferenceURL @@ -1117,7 +1117,7 @@ UTTypeDescription ZX Spectrum Opus Discovery Disk Image UTTypeIconFile - blank + opd UTTypeIdentifier net.sourceforge.projects.fuse-emulator.opd UTTypeReferenceURL @@ -1138,7 +1138,7 @@ UTTypeDescription ZX Spectrum Opus Discovery Disk Image UTTypeIconFile - blank + opu UTTypeIdentifier net.sourceforge.projects.fuse-emulator.opu UTTypeReferenceURL @@ -1159,7 +1159,7 @@ UTTypeDescription ZX Spectrum Screen Image UTTypeIconFile - blank + mlt UTTypeIdentifier net.sourceforge.projects.fuse-emulator.mlt UTTypeTagSpecification diff --git a/fusepb/Makefile b/fusepb/Makefile index 948b71ca..60323610 100644 --- a/fusepb/Makefile +++ b/fusepb/Makefile @@ -37,3 +37,9 @@ options.m: ../perl/cpp-perl.pl config.h ../ui/cocoa/options.pl ../ui/options.dat clean: rm options.h options_cocoa.h options.m settings.h settings.m ../z80/opcodes_base.c ../z80/z80_cb.c ../z80/z80_ddfd.c ../z80/z80_ddfdcb.c ../z80/z80_ed.c settings_cocoa.h + +# Generate a file-format icon, e.g. `make icon FORMAT=udi`. LABEL defaults to +# FORMAT uppercased. Writes resources/$(FORMAT).icns from resources/blank.icns. +icon: + @test -n "$(FORMAT)" || { echo "usage: make icon FORMAT= [LABEL=]"; exit 1; } + cd .. && swift fusepb/format-icon.swift "$(FORMAT)" "$(LABEL)" diff --git a/fusepb/format-icon.swift b/fusepb/format-icon.swift new file mode 100644 index 00000000..9bdb2c3a --- /dev/null +++ b/fusepb/format-icon.swift @@ -0,0 +1,105 @@ +#!/usr/bin/env swift +// +// format-icon.swift — generate a file-format .icns matching FuseX's existing set. +// +// Usage: swift fusepb/format-icon.swift [LABEL] +// output basename, e.g. "udi" -> fusepb/resources/udi.icns +// LABEL text drawn on the icon (default: uppercased) +// +// Method: every existing format icon is fusepb/resources/blank.icns plus an +// uppercase label, so this script reuses blank.icns as the base and stamps the +// matching label onto it. +// +import AppKit + +let fontName = "LucidaGrande-Bold" +let inkColor = NSColor(red: 0x62/255.0, green: 0x62/255.0, blue: 0x62/255.0, alpha: 1) + +// One entry per .icns layer. `pt` is the label point size and `textTop` the gap +// from the top edge to the top of the text rect. Both are specific to +// LucidaGrande-Bold — recompute them for any other font. +struct Layer { let px: Int; let pt: CGFloat; let textTop: CGFloat } +let layers = [ + Layer(px: 16, pt: 8.30, textTop: 7.97), + Layer(px: 32, pt: 8.30, textTop: 20.97), + Layer(px: 128, pt: 19.37, textTop: 95.27), +] + +func die(_ msg: String) -> Never { + FileHandle.standardError.write(Data(("error: " + msg + "\n").utf8)) + exit(1) +} + +func iconutil(_ args: String...) { + let p = Process() + p.executableURL = URL(fileURLWithPath: "/usr/bin/iconutil") + p.arguments = args + try? p.run(); p.waitUntilExit() + if p.terminationStatus != 0 { die("iconutil \(args.joined(separator: " ")) failed") } +} + +// Draw `label` onto the base PNG for one layer and write the result. The label is +// centered horizontally; its rect starts `textTop` pixels below the top edge. +func stamp(_ label: String, base basePNG: URL, layer: Layer, to outPNG: URL) { + let side = CGFloat(layer.px) + guard let base = NSImage(contentsOf: basePNG) else { die("missing base \(basePNG.lastPathComponent)") } + guard let out = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: layer.px, pixelsHigh: layer.px, + bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, + colorSpaceName: .deviceRGB, bytesPerRow: 0, bitsPerPixel: 0) + else { die("cannot allocate \(layer.px)px bitmap") } + guard let font = NSFont(name: fontName, size: layer.pt) else { die("font \(fontName) unavailable") } + + NSGraphicsContext.saveGraphicsState() + defer { NSGraphicsContext.restoreGraphicsState() } + // Top-left origin (flipped) context so textTop measures from the top. + guard let ctx = NSGraphicsContext(bitmapImageRep: out) else { die("cannot create drawing context") } + let cg = ctx.cgContext + NSGraphicsContext.current = NSGraphicsContext(cgContext: cg, flipped: true) + cg.translateBy(x: 0, y: side); cg.scaleBy(x: 1, y: -1) + + base.draw(in: NSRect(x: 0, y: 0, width: side, height: side)) + + let centered = NSMutableParagraphStyle(); centered.alignment = .center + let attrs: [NSAttributedString.Key: Any] = [ + .font: font, + .foregroundColor: inkColor, + .paragraphStyle: centered] + (label as NSString).draw(in: NSRect(x: 0, y: layer.textTop, width: side, height: side), withAttributes: attrs) + + guard let png = out.representation(using: .png, properties: [:]) else { die("PNG encode failed for \(outPNG.lastPathComponent)") } + do { try png.write(to: outPNG) } catch { die("write \(outPNG.lastPathComponent): \(error.localizedDescription)") } +} + +// --- run ---------------------------------------------------------------------- +let argv = CommandLine.arguments +guard argv.count >= 2 else { die("usage: swift format-icon.swift [LABEL]") } +let ext = argv[1] +let rawLabel = argv.count >= 3 ? argv[2] : ext +let label = (rawLabel.isEmpty ? ext : rawLabel).uppercased() + +let fm = FileManager.default +// blank.icns anchors the repo root, so the script works from any CWD. +var root = URL(fileURLWithPath: fm.currentDirectoryPath) +while !fm.fileExists(atPath: root.appendingPathComponent("fusepb/resources/blank.icns").path) { + let parent = root.deletingLastPathComponent() + if parent.path == root.path { die("fusepb/resources/blank.icns not found above \(fm.currentDirectoryPath)") } + root = parent +} +let resources = root.appendingPathComponent("fusepb/resources") + +let workDir = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("fmticon-\(ext)") +try? fm.removeItem(at: workDir) +let baseIconset = workDir.appendingPathComponent("base.iconset") +let outputIconset = workDir.appendingPathComponent("\(ext).iconset") +do { try fm.createDirectory(at: outputIconset, withIntermediateDirectories: true) } +catch { die("cannot create \(outputIconset.path): \(error.localizedDescription)") } + +iconutil("-c", "iconset", "-o", baseIconset.path, resources.appendingPathComponent("blank.icns").path) +for layer in layers { + let name = "icon_\(layer.px)x\(layer.px).png" + stamp(label, base: baseIconset.appendingPathComponent(name), layer: layer, to: outputIconset.appendingPathComponent(name)) +} +let outputIcon = resources.appendingPathComponent("\(ext).icns") +iconutil("-c", "icns", "-o", outputIcon.path, outputIconset.path) +try? fm.removeItem(at: workDir) +print("wrote \(outputIcon.path)") diff --git a/fusepb/resources/d40.icns b/fusepb/resources/d40.icns new file mode 100644 index 00000000..8e2ad718 Binary files /dev/null and b/fusepb/resources/d40.icns differ diff --git a/fusepb/resources/d80.icns b/fusepb/resources/d80.icns new file mode 100644 index 00000000..9ed0d7bd Binary files /dev/null and b/fusepb/resources/d80.icns differ diff --git a/fusepb/resources/fdi.icns b/fusepb/resources/fdi.icns new file mode 100644 index 00000000..f726358a Binary files /dev/null and b/fusepb/resources/fdi.icns differ diff --git a/fusepb/resources/img.icns b/fusepb/resources/img.icns new file mode 100644 index 00000000..73dd16df Binary files /dev/null and b/fusepb/resources/img.icns differ diff --git a/fusepb/resources/ltp.icns b/fusepb/resources/ltp.icns new file mode 100644 index 00000000..ddcbf0c9 Binary files /dev/null and b/fusepb/resources/ltp.icns differ diff --git a/fusepb/resources/mgt.icns b/fusepb/resources/mgt.icns new file mode 100644 index 00000000..f778e204 Binary files /dev/null and b/fusepb/resources/mgt.icns differ diff --git a/fusepb/resources/mgtsnp.icns b/fusepb/resources/mgtsnp.icns new file mode 100644 index 00000000..b2c78eef Binary files /dev/null and b/fusepb/resources/mgtsnp.icns differ diff --git a/fusepb/resources/mlt.icns b/fusepb/resources/mlt.icns new file mode 100644 index 00000000..130fb973 Binary files /dev/null and b/fusepb/resources/mlt.icns differ diff --git a/fusepb/resources/opd.icns b/fusepb/resources/opd.icns new file mode 100644 index 00000000..1297ae78 Binary files /dev/null and b/fusepb/resources/opd.icns differ diff --git a/fusepb/resources/opu.icns b/fusepb/resources/opu.icns new file mode 100644 index 00000000..8e64b6c8 Binary files /dev/null and b/fusepb/resources/opu.icns differ diff --git a/fusepb/resources/pok.icns b/fusepb/resources/pok.icns new file mode 100644 index 00000000..9d997b38 Binary files /dev/null and b/fusepb/resources/pok.icns differ diff --git a/fusepb/resources/pzx.icns b/fusepb/resources/pzx.icns new file mode 100644 index 00000000..92cc8b04 Binary files /dev/null and b/fusepb/resources/pzx.icns differ diff --git a/fusepb/resources/spc.icns b/fusepb/resources/spc.icns new file mode 100644 index 00000000..90c837e0 Binary files /dev/null and b/fusepb/resources/spc.icns differ diff --git a/fusepb/resources/sta.icns b/fusepb/resources/sta.icns new file mode 100644 index 00000000..632b3d6f Binary files /dev/null and b/fusepb/resources/sta.icns differ diff --git a/fusepb/resources/wav.icns b/fusepb/resources/wav.icns new file mode 100644 index 00000000..49a71df5 Binary files /dev/null and b/fusepb/resources/wav.icns differ