disk and (empty) settings UI
@ -7,6 +7,8 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
28848B621CDE97D600B86C45 /* InsertDiskViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28848B611CDE97D600B86C45 /* InsertDiskViewController.m */; };
|
||||
28848B651CDE97E900B86C45 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28848B641CDE97E900B86C45 /* SettingsViewController.m */; };
|
||||
28CE8EB51CD4C3B200FE25A8 /* GLOBGLUE.c in Sources */ = {isa = PBXBuildFile; fileRef = 28CE8E931CD4C3B200FE25A8 /* GLOBGLUE.c */; };
|
||||
28CE8EB61CD4C3B200FE25A8 /* IWMEMDEV.c in Sources */ = {isa = PBXBuildFile; fileRef = 28CE8E961CD4C3B200FE25A8 /* IWMEMDEV.c */; };
|
||||
28CE8EB71CD4C3B200FE25A8 /* KBRDEMDV.c in Sources */ = {isa = PBXBuildFile; fileRef = 28CE8E981CD4C3B200FE25A8 /* KBRDEMDV.c */; };
|
||||
@ -34,6 +36,10 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
28848B601CDE97D600B86C45 /* InsertDiskViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InsertDiskViewController.h; sourceTree = "<group>"; };
|
||||
28848B611CDE97D600B86C45 /* InsertDiskViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InsertDiskViewController.m; sourceTree = "<group>"; };
|
||||
28848B631CDE97E900B86C45 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = "<group>"; };
|
||||
28848B641CDE97E900B86C45 /* SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = "<group>"; };
|
||||
28CE8E881CD4C33E00FE25A8 /* CNFGGLOB.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CNFGGLOB.h; sourceTree = "<group>"; };
|
||||
28CE8E891CD4C33E00FE25A8 /* CNFGRAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CNFGRAPI.h; sourceTree = "<group>"; };
|
||||
28CE8E8A1CD4C33E00FE25A8 /* EMCONFIG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMCONFIG.h; sourceTree = "<group>"; };
|
||||
@ -186,6 +192,10 @@
|
||||
28D5A3FC1CD6868E001A33F6 /* TouchScreen.m */,
|
||||
28F676C61CD15E0B00FC6FA6 /* ViewController.h */,
|
||||
28F676C71CD15E0B00FC6FA6 /* ViewController.m */,
|
||||
28848B601CDE97D600B86C45 /* InsertDiskViewController.h */,
|
||||
28848B611CDE97D600B86C45 /* InsertDiskViewController.m */,
|
||||
28848B631CDE97E900B86C45 /* SettingsViewController.h */,
|
||||
28848B641CDE97E900B86C45 /* SettingsViewController.m */,
|
||||
28F676C91CD15E0B00FC6FA6 /* Main.storyboard */,
|
||||
28F676CC1CD15E0B00FC6FA6 /* Assets.xcassets */,
|
||||
28F676CE1CD15E0B00FC6FA6 /* LaunchScreen.storyboard */,
|
||||
@ -286,9 +296,11 @@
|
||||
28CE8EBA1CD4C3B200FE25A8 /* MOUSEMDV.c in Sources */,
|
||||
28CE8EC31CD4C3B200FE25A8 /* VIAEMDEV.c in Sources */,
|
||||
28CE8EB81CD4C3B200FE25A8 /* M68KITAB.c in Sources */,
|
||||
28848B651CDE97E900B86C45 /* SettingsViewController.m in Sources */,
|
||||
28CE8EB71CD4C3B200FE25A8 /* KBRDEMDV.c in Sources */,
|
||||
28CE8EBC1CD4C3B200FE25A8 /* ROMEMDEV.c in Sources */,
|
||||
28CE8EBB1CD4C3B200FE25A8 /* PROGMAIN.c in Sources */,
|
||||
28848B621CDE97D600B86C45 /* InsertDiskViewController.m in Sources */,
|
||||
28F676C81CD15E0B00FC6FA6 /* ViewController.m in Sources */,
|
||||
28D5A3FD1CD6868F001A33F6 /* TouchScreen.m in Sources */,
|
||||
28CE8EC21CD4C3B200FE25A8 /* SONYEMDV.c in Sources */,
|
||||
|
@ -8,18 +8,27 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
extern NSString * const MNVMDidInsertDiskNotification;
|
||||
extern NSString * const MNVMDidEjectDiskNotification;
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (strong, nonatomic) UIWindow *window;
|
||||
@property (assign, nonatomic, getter=isEmulatorRunning) BOOL emulatorRunning;
|
||||
@property (nonatomic, readonly) NSString *documentsPath;
|
||||
@property (nonatomic, readonly) NSArray<NSString*> *diskImageExtensions;
|
||||
|
||||
+ (instancetype)sharedInstance;
|
||||
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message;
|
||||
- (IBAction)showInsertDisk:(id)sender;
|
||||
- (IBAction)showSettings:(id)sender;
|
||||
|
||||
- (void)setMouseX:(NSInteger)x Y:(NSInteger)y;
|
||||
- (void)moveMouseX:(NSInteger)x Y:(NSInteger)y;
|
||||
- (void)setMouseButton:(BOOL)down;
|
||||
|
||||
- (BOOL)insertDisk:(NSString*)path;
|
||||
- (BOOL)isDiskInserted:(NSString*)path;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -7,6 +7,8 @@
|
||||
//
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "SettingsViewController.h"
|
||||
#import "InsertDiskViewController.h"
|
||||
#include "CNFGRAPI.h"
|
||||
#include "SYSDEPNS.h"
|
||||
#include "MYOSGLUE.h"
|
||||
@ -17,8 +19,12 @@ IMPORTPROC SetSpeedStopped(blnr stopped);
|
||||
IMPORTPROC SetMouseButton(blnr down);
|
||||
IMPORTPROC SetMouseLoc(ui4r h, ui4r v);
|
||||
IMPORTPROC SetMouseDelta(ui4r dh, ui4r dv);
|
||||
IMPORTFUNC blnr Sony_Insert1(NSString *filePath, blnr silentfail);
|
||||
IMPORTFUNC blnr Sony_IsInserted(NSString *filePath);
|
||||
|
||||
static AppDelegate *sharedAppDelegate = nil;
|
||||
NSString * const MNVMDidInsertDiskNotification = @"MNVMDidInsertDisk";
|
||||
NSString * const MNVMDidEjectDiskNotification = @"MNVMDidEjectDisk";
|
||||
|
||||
@interface AppDelegate ()
|
||||
|
||||
@ -57,8 +63,64 @@ static AppDelegate *sharedAppDelegate = nil;
|
||||
[controller presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)showSettings:(id)sender {
|
||||
[self showModalPanel:@"settings" sender:sender];
|
||||
}
|
||||
|
||||
- (void)showInsertDisk:(id)sender {
|
||||
[self showModalPanel:@"disk" sender:sender];
|
||||
}
|
||||
|
||||
- (void)showModalPanel:(NSString*)name sender:(id)sender {
|
||||
Class classToShow, otherClass;
|
||||
if ([name isEqualToString:@"settings"]) {
|
||||
classToShow = [SettingsViewController class];
|
||||
otherClass = [InsertDiskViewController class];
|
||||
} else {
|
||||
classToShow = [InsertDiskViewController class];
|
||||
otherClass = [SettingsViewController class];
|
||||
}
|
||||
|
||||
UIViewController *rootViewController = self.window.rootViewController;
|
||||
UIViewController *presentedViewController = rootViewController.presentedViewController;
|
||||
UIViewController *presentedTopViewController = [presentedViewController isKindOfClass:[UINavigationController class]] ? [(UINavigationController*)presentedViewController topViewController] : nil;
|
||||
|
||||
if ([presentedTopViewController isKindOfClass:classToShow]) {
|
||||
return;
|
||||
} else if ([presentedTopViewController isKindOfClass:otherClass]) {
|
||||
// flip
|
||||
UIViewController *viewController = [rootViewController.storyboard instantiateViewControllerWithIdentifier:name];
|
||||
viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
|
||||
viewController.modalPresentationStyle = UIModalPresentationFormSheet;
|
||||
UIView *windowSnapshotView = [self.window snapshotViewAfterScreenUpdates:NO];
|
||||
[self.window addSubview:windowSnapshotView];
|
||||
UIView *oldPanelSnapshotView = [presentedViewController.view snapshotViewAfterScreenUpdates:NO];
|
||||
[viewController.view addSubview:oldPanelSnapshotView];
|
||||
[rootViewController dismissViewControllerAnimated:NO completion:^{
|
||||
[rootViewController presentViewController:viewController animated:NO completion:^{
|
||||
UIView *emptyView = [[UIView alloc] initWithFrame:viewController.view.bounds];
|
||||
[windowSnapshotView removeFromSuperview];
|
||||
viewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
|
||||
[UIView transitionFromView:oldPanelSnapshotView
|
||||
toView:emptyView
|
||||
duration:0.5
|
||||
options:UIViewAnimationOptionTransitionFlipFromRight
|
||||
completion:^(BOOL finished) {
|
||||
[emptyView removeFromSuperview];
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
} else {
|
||||
[self.window.rootViewController performSegueWithIdentifier:name sender:sender];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Files
|
||||
|
||||
- (NSArray<NSString *> *)diskImageExtensions {
|
||||
return @[@"dsk", @"img", @"dc42", @"diskcopy42"];
|
||||
}
|
||||
|
||||
- (NSString *)documentsPath {
|
||||
static dispatch_once_t onceToken;
|
||||
static NSString *documentsPath;
|
||||
@ -111,6 +173,8 @@ static AppDelegate *sharedAppDelegate = nil;
|
||||
SetSpeedStopped(emulatorRunning);
|
||||
}
|
||||
|
||||
#pragma mark - Mouse
|
||||
|
||||
- (void)setMouseX:(NSInteger)x Y:(NSInteger)y {
|
||||
SetMouseLoc(x, y);
|
||||
}
|
||||
@ -123,4 +187,14 @@ static AppDelegate *sharedAppDelegate = nil;
|
||||
SetMouseButton(down);
|
||||
}
|
||||
|
||||
#pragma mark - Disk Drive
|
||||
|
||||
- (BOOL)insertDisk:(NSString *)path {
|
||||
return Sony_Insert1(path.stringByStandardizingPath, falseblnr);
|
||||
}
|
||||
|
||||
- (BOOL)isDiskInserted:(NSString *)path {
|
||||
return Sony_IsInserted(path.stringByStandardizingPath);
|
||||
}
|
||||
|
||||
@end
|
||||
|
6
Mini vMac/Assets.xcassets/Contents.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
23
Mini vMac/Assets.xcassets/Settings.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Settings.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Settings@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Settings@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
Mini vMac/Assets.xcassets/Settings.imageset/Settings.png
vendored
Normal file
After Width: | Height: | Size: 577 B |
BIN
Mini vMac/Assets.xcassets/Settings.imageset/Settings@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Mini vMac/Assets.xcassets/Settings.imageset/Settings@3x.png
vendored
Normal file
After Width: | Height: | Size: 2.0 KiB |
23
Mini vMac/Assets.xcassets/document.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "document.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "document@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "document@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
Mini vMac/Assets.xcassets/document.imageset/document.png
vendored
Normal file
After Width: | Height: | Size: 133 B |
BIN
Mini vMac/Assets.xcassets/document.imageset/document@2x.png
vendored
Normal file
After Width: | Height: | Size: 177 B |
BIN
Mini vMac/Assets.xcassets/document.imageset/document@3x.png
vendored
Normal file
After Width: | Height: | Size: 229 B |
23
Mini vMac/Assets.xcassets/floppy.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "floppy.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "floppy@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "floppy@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
Mini vMac/Assets.xcassets/floppy.imageset/floppy.png
vendored
Normal file
After Width: | Height: | Size: 265 B |
BIN
Mini vMac/Assets.xcassets/floppy.imageset/floppy@2x.png
vendored
Normal file
After Width: | Height: | Size: 508 B |
BIN
Mini vMac/Assets.xcassets/floppy.imageset/floppy@3x.png
vendored
Normal file
After Width: | Height: | Size: 798 B |
23
Mini vMac/Assets.xcassets/floppy30.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "floppy30.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "floppy30@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "floppy30@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
Mini vMac/Assets.xcassets/floppy30.imageset/floppy30.png
vendored
Normal file
After Width: | Height: | Size: 251 B |
BIN
Mini vMac/Assets.xcassets/floppy30.imageset/floppy30@2x.png
vendored
Normal file
After Width: | Height: | Size: 477 B |
BIN
Mini vMac/Assets.xcassets/floppy30.imageset/floppy30@3x.png
vendored
Normal file
After Width: | Height: | Size: 736 B |
23
Mini vMac/Assets.xcassets/folder.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "folder.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "folder@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "folder@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
Mini vMac/Assets.xcassets/folder.imageset/folder.png
vendored
Normal file
After Width: | Height: | Size: 143 B |
BIN
Mini vMac/Assets.xcassets/folder.imageset/folder@2x.png
vendored
Normal file
After Width: | Height: | Size: 215 B |
BIN
Mini vMac/Assets.xcassets/folder.imageset/folder@3x.png
vendored
Normal file
After Width: | Height: | Size: 300 B |
23
Mini vMac/Assets.xcassets/hardDisk.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "hardDisk.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "hardDisk@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "hardDisk@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
Mini vMac/Assets.xcassets/hardDisk.imageset/hardDisk.png
vendored
Normal file
After Width: | Height: | Size: 139 B |
BIN
Mini vMac/Assets.xcassets/hardDisk.imageset/hardDisk@2x.png
vendored
Normal file
After Width: | Height: | Size: 218 B |
BIN
Mini vMac/Assets.xcassets/hardDisk.imageset/hardDisk@3x.png
vendored
Normal file
After Width: | Height: | Size: 357 B |
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10116" systemVersion="15E65" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15E65" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||
@ -19,7 +19,7 @@
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="70W-4V-tYr" customClass="ScreenView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
@ -32,11 +32,173 @@
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="screenView" destination="70W-4V-tYr" id="W9r-vA-9kk"/>
|
||||
<segue destination="DCD-sd-Fu5" kind="presentation" identifier="disk" modalPresentationStyle="formSheet" id="wkd-we-QI6"/>
|
||||
<segue destination="j8f-3L-8mp" kind="presentation" identifier="settings" modalPresentationStyle="formSheet" id="ak4-wm-owU"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="548" y="391"/>
|
||||
</scene>
|
||||
<!--Settings-->
|
||||
<scene sceneID="Lht-Fe-oRx">
|
||||
<objects>
|
||||
<tableViewController id="WUA-f8-k8g" customClass="SettingsViewController" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="9gA-gD-7Wx">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
|
||||
<sections>
|
||||
<tableViewSection id="fj2-dd-gR8">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="Mc2-kK-a9O">
|
||||
<rect key="frame" x="0.0" y="79" width="600" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Mc2-kK-a9O" id="stF-6e-bDy">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="WLf-oW-n9a">
|
||||
<rect key="frame" x="0.0" y="123" width="600" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WLf-oW-n9a" id="gFz-UO-ARA">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="U80-vD-nDD">
|
||||
<rect key="frame" x="0.0" y="167" width="600" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="U80-vD-nDD" id="6Of-5M-ffg">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</cells>
|
||||
</tableViewSection>
|
||||
</sections>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="WUA-f8-k8g" id="Cy8-ba-Ynt"/>
|
||||
<outlet property="delegate" destination="WUA-f8-k8g" id="mWB-FI-bec"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<navigationItem key="navigationItem" title="Settings" id="tWH-Og-D4U">
|
||||
<barButtonItem key="leftBarButtonItem" image="floppy30" id="I6Y-Q1-NZU">
|
||||
<connections>
|
||||
<action selector="showInsertDisk:" destination="WUA-f8-k8g" id="suC-dT-QUw"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem key="rightBarButtonItem" style="done" systemItem="done" id="JEh-Ow-9im">
|
||||
<connections>
|
||||
<action selector="dismiss:" destination="WUA-f8-k8g" id="ZIA-eK-bKG"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</navigationItem>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="FeB-pK-Fwo" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1996" y="31"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="UQ7-sc-pir">
|
||||
<objects>
|
||||
<navigationController storyboardIdentifier="settings" id="j8f-3L-8mp" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="7OA-7b-rux">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
<segue destination="WUA-f8-k8g" kind="relationship" relationship="rootViewController" id="Zpb-kg-HM5"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="8IW-lr-03G" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1318" y="31"/>
|
||||
</scene>
|
||||
<!--Insert Disk-->
|
||||
<scene sceneID="a1s-tB-X2g">
|
||||
<objects>
|
||||
<tableViewController id="mbX-kA-h6M" customClass="InsertDiskViewController" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="EFr-QR-Vqc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="cell" textLabel="8ef-Se-DXA" detailTextLabel="CbL-Kq-e9s" style="IBUITableViewCellStyleValue1" id="iZQ-DG-qho" customClass="FileTableViewCell">
|
||||
<rect key="frame" x="0.0" y="72" width="600" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="iZQ-DG-qho" id="pcB-3f-clB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="43.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.69999999999999996" adjustsLetterSpacingToFitWidth="YES" id="8ef-Se-DXA">
|
||||
<rect key="frame" x="15" y="12" width="31.5" height="19.5"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="16"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Detail" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" id="CbL-Kq-e9s">
|
||||
<rect key="frame" x="550" y="15" width="35" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="mbX-kA-h6M" id="k2s-F1-jx0"/>
|
||||
<outlet property="delegate" destination="mbX-kA-h6M" id="e1C-bZ-m6A"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<toolbarItems>
|
||||
<barButtonItem image="Settings" id="wKc-yt-7j5" userLabel="Settings">
|
||||
<connections>
|
||||
<action selector="showSettings:" destination="mbX-kA-h6M" id="dIs-rf-PeS"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</toolbarItems>
|
||||
<navigationItem key="navigationItem" title="Insert Disk" id="hjJ-Yt-wg8">
|
||||
<barButtonItem key="backBarButtonItem" title="Disk" id="pie-Ez-AWv"/>
|
||||
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="OG2-Vg-rfI">
|
||||
<connections>
|
||||
<action selector="dismiss:" destination="mbX-kA-h6M" id="UrO-BE-iVK"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</navigationItem>
|
||||
<simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="n7E-Ft-tEZ" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1996" y="735"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="V4m-xV-cjV">
|
||||
<objects>
|
||||
<navigationController storyboardIdentifier="disk" toolbarHidden="NO" id="DCD-sd-Fu5" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="jFP-L0-vQk">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<toolbar key="toolbar" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="TXk-M9-69L">
|
||||
<rect key="frame" x="0.0" y="556" width="600" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</toolbar>
|
||||
<connections>
|
||||
<segue destination="mbX-kA-h6M" kind="relationship" relationship="rootViewController" id="2hT-RO-fgU"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="oTI-h8-BGr" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1318" y="735"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="Settings" width="30" height="30"/>
|
||||
<image name="floppy30" width="30" height="30"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
16
Mini vMac/InsertDiskViewController.h
Normal file
@ -0,0 +1,16 @@
|
||||
//
|
||||
// InsertDiskViewController.h
|
||||
// Mini vMac
|
||||
//
|
||||
// Created by Jesús A. Álvarez on 07/05/2016.
|
||||
// Copyright © 2016 namedfork. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface InsertDiskViewController : UITableViewController
|
||||
|
||||
- (IBAction)showSettings:(id)sender;
|
||||
- (IBAction)dismiss:(id)sender;
|
||||
|
||||
@end
|
448
Mini vMac/InsertDiskViewController.m
Normal file
@ -0,0 +1,448 @@
|
||||
//
|
||||
// InsertDiskViewController.m
|
||||
// Mini vMac
|
||||
//
|
||||
// Created by Jesús A. Álvarez on 07/05/2016.
|
||||
// Copyright © 2016 namedfork. All rights reserved.
|
||||
//
|
||||
|
||||
#import "InsertDiskViewController.h"
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@interface InsertDiskViewController () <UITextFieldDelegate>
|
||||
|
||||
@end
|
||||
|
||||
@interface FileTableViewCell : UITableViewCell
|
||||
|
||||
@property (nonatomic, weak) InsertDiskViewController *controller;
|
||||
@property (nonatomic, strong) NSString *filePath;
|
||||
- (void)share:(id)sender;
|
||||
- (void)rename:(id)sender;
|
||||
- (void)delete:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
@implementation InsertDiskViewController
|
||||
{
|
||||
NSString *basePath;
|
||||
NSArray<NSString*> *diskImages, *otherFiles;
|
||||
UIAlertController *createDiskImageController;
|
||||
__block __weak UITextField *sizeTextField;
|
||||
__block __weak UITextField *nameTextField;
|
||||
}
|
||||
|
||||
+ (void)initialize {
|
||||
UIMenuController *menuController = [UIMenuController sharedMenuController];
|
||||
menuController.menuItems = @[[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Rename", @"Rename Context Menu Item") action:@selector(rename:)],
|
||||
[[UIMenuItem alloc] initWithTitle:NSLocalizedString(@"Share", @"Share Context Menu Item") action:@selector(share:)]];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
basePath = [AppDelegate sharedInstance].documentsPath;
|
||||
[self loadDirectoryContents];
|
||||
self.navigationItem.rightBarButtonItem = self.editButtonItem;
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc addObserver:self selector:@selector(reloadData:) name:MNVMDidInsertDiskNotification object:nil];
|
||||
[nc addObserver:self selector:@selector(reloadData:) name:MNVMDidEjectDiskNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated {
|
||||
[super viewDidDisappear:animated];
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
[nc removeObserver:self name:MNVMDidInsertDiskNotification object:nil];
|
||||
[nc removeObserver:self name:MNVMDidEjectDiskNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)loadDirectoryContents {
|
||||
NSArray *allFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:basePath error:NULL];
|
||||
diskImages = [allFiles pathsMatchingExtensions:[AppDelegate sharedInstance].diskImageExtensions];
|
||||
otherFiles = [allFiles filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSString* _Nonnull name, NSDictionary<NSString *,id> * _Nullable bindings) {
|
||||
BOOL isDiskImage = [diskImages containsObject:name];
|
||||
BOOL isDirectory;
|
||||
BOOL isHidden = [name hasPrefix:@"."];
|
||||
[[NSFileManager defaultManager] fileExistsAtPath:[basePath stringByAppendingPathComponent:name] isDirectory:&isDirectory];
|
||||
return !(isDirectory || isDiskImage || isHidden);
|
||||
}]];
|
||||
}
|
||||
|
||||
- (void)reloadData:(id)sender {
|
||||
[self loadDirectoryContents];
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)showSettings:(id)sender {
|
||||
[[AppDelegate sharedInstance] showSettings:sender];
|
||||
}
|
||||
|
||||
- (void)dismiss:(id)sender {
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
return self.editing ? 2 : 1;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
switch (section) {
|
||||
case 0: return diskImages.count + (self.editing ? 1 : 0);
|
||||
case 1: return otherFiles.count;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
||||
return section == 0 ? NSLocalizedString(@"Disk Images", nil) : NSLocalizedString(@"Other Files", nil);
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
|
||||
return self.editing ? UITableViewAutomaticDimension : 0.0;
|
||||
}
|
||||
|
||||
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
|
||||
[super setEditing:editing animated:animated];
|
||||
[self.tableView beginUpdates];
|
||||
[self loadDirectoryContents];
|
||||
self.tableView.tableHeaderView = nil;
|
||||
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
|
||||
if (editing) {
|
||||
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationFade];
|
||||
} else {
|
||||
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationFade];
|
||||
}
|
||||
[self.tableView endUpdates];
|
||||
}
|
||||
|
||||
- (NSString *)fileAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSArray<NSString*> *files = indexPath.section == 0 ? diskImages : otherFiles;
|
||||
if (indexPath.row < files.count) {
|
||||
NSString *fileName = files[indexPath.row];
|
||||
return [basePath stringByAppendingPathComponent:fileName];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSIndexPath *)indexPathForFile:(NSString *)filePath {
|
||||
NSString *fileName = filePath.lastPathComponent;
|
||||
if ([diskImages containsObject:fileName]) {
|
||||
return [NSIndexPath indexPathForRow:[diskImages indexOfObject:fileName] inSection:0];
|
||||
} else if ([otherFiles containsObject:fileName]) {
|
||||
return [NSIndexPath indexPathForRow:[otherFiles indexOfObject:fileName] inSection:1];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
FileTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
|
||||
NSString *filePath = [self fileAtIndexPath:indexPath];
|
||||
if (filePath) {
|
||||
cell.filePath = filePath;
|
||||
if ([[AppDelegate sharedInstance] isDiskInserted:filePath]) {
|
||||
cell.userInteractionEnabled = NO;
|
||||
cell.textLabel.enabled = NO;
|
||||
cell.imageView.alpha = 0.5;
|
||||
}
|
||||
} else {
|
||||
cell.textLabel.text = NSLocalizedString(@"Create Disk Image…", nil);
|
||||
cell.detailTextLabel.text = nil;
|
||||
}
|
||||
cell.controller = self;
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (self.editing == NO) {
|
||||
return UITableViewCellEditingStyleNone;
|
||||
} else if (indexPath.section == 0) {
|
||||
if (indexPath.row == diskImages.count) {
|
||||
return UITableViewCellEditingStyleInsert;
|
||||
}
|
||||
NSString *filePath = [self fileAtIndexPath:indexPath];
|
||||
BOOL isInserted = [[AppDelegate sharedInstance] isDiskInserted:filePath];
|
||||
return isInserted ? UITableViewCellEditingStyleNone : UITableViewCellEditingStyleDelete;
|
||||
} else {
|
||||
return UITableViewCellEditingStyleDelete;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete) {
|
||||
[self askDeleteFile:[self fileAtIndexPath:indexPath]];
|
||||
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
|
||||
[self createDiskImage];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
|
||||
return [self fileAtIndexPath:indexPath] != nil;
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
|
||||
return (action == @selector(share:) || action == @selector(rename:) || action == @selector(delete:));
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender {
|
||||
// menu will not be shown if this method doesn't exist
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSString *filePath = [self fileAtIndexPath:indexPath];
|
||||
if (filePath && ![[AppDelegate sharedInstance] isDiskInserted:filePath]) {
|
||||
[self dismissViewControllerAnimated:YES completion:^{
|
||||
[[AppDelegate sharedInstance] insertDisk:filePath];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - File Actions
|
||||
|
||||
- (void)askDeleteFile:(NSString*)filePath {
|
||||
NSString *fileName = filePath.lastPathComponent;
|
||||
NSString *message = [NSString stringWithFormat:NSLocalizedString(@"Are you sure you want to delete %@? This operation cannot be undone.", nil), fileName];
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Delete File", nil) message:message preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Delete", nil) style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
|
||||
NSError *error = nil;
|
||||
if ([[NSFileManager defaultManager] removeItemAtPath:filePath error:&error]) {
|
||||
NSIndexPath *indexPath = [self indexPathForFile:filePath];
|
||||
[self loadDirectoryContents];
|
||||
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
|
||||
} else {
|
||||
[[AppDelegate sharedInstance] showAlertWithTitle:NSLocalizedString(@"Could not delete file", nil) message:error.localizedDescription];
|
||||
}
|
||||
}]];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)askRenameFile:(NSString*)filePath {
|
||||
NSString *fileName = filePath.lastPathComponent;
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:fileName message:NSLocalizedString(@"Enter new name", nil) preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
|
||||
nameTextField = textField;
|
||||
textField.delegate = self;
|
||||
textField.placeholder = fileName;
|
||||
textField.text = fileName;
|
||||
}];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Rename", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
|
||||
NSError *error = nil;
|
||||
NSString *newName = alertController.textFields.firstObject.text;
|
||||
NSString *newPath = [filePath.stringByDeletingLastPathComponent stringByAppendingPathComponent:newName];
|
||||
if ([[NSFileManager defaultManager] moveItemAtPath:filePath toPath:newPath error:&error]) {
|
||||
NSIndexPath *oldIndexPath = [self indexPathForFile:filePath];
|
||||
[self loadDirectoryContents];
|
||||
NSIndexPath *newIndexPath = [self indexPathForFile:newPath];
|
||||
if (newIndexPath == nil) {
|
||||
[self.tableView deleteRowsAtIndexPaths:@[oldIndexPath] withRowAnimation:UITableViewRowAnimationFade];
|
||||
} else {
|
||||
[self.tableView moveRowAtIndexPath:oldIndexPath toIndexPath:newIndexPath];
|
||||
[self.tableView reloadRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
} else {
|
||||
[[AppDelegate sharedInstance] showAlertWithTitle:NSLocalizedString(@"Could not rename file", nil) message:error.localizedDescription];
|
||||
}
|
||||
}]];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil]];
|
||||
[self presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Disk Image Creation
|
||||
|
||||
- (void)createDiskImage {
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Create Disk Image", nil) message:nil preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
|
||||
textField.placeholder = NSLocalizedString(@"name", nil);
|
||||
[textField addTarget:self action:@selector(validateCreateDiskImageInput:) forControlEvents:UIControlEventAllEditingEvents];
|
||||
}];
|
||||
|
||||
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
|
||||
textField.placeholder = NSLocalizedString(@"size", nil);
|
||||
textField.keyboardType = UIKeyboardTypeDecimalPad;
|
||||
UILabel *unitLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 60.0, 32.0)];
|
||||
textField.rightViewMode = UITextFieldViewModeAlways;
|
||||
textField.rightView = unitLabel;
|
||||
unitLabel.textAlignment = NSTextAlignmentRight;
|
||||
UISegmentedControl *unitsControl = [[UISegmentedControl alloc] initWithFrame:CGRectMake(0, 0, 80.0, 16.0)];
|
||||
NSArray *units = @[NSLocalizedString(@"KB", nil), NSLocalizedString(@"MB", nil)];
|
||||
[units enumerateObjectsUsingBlock:^(NSString *title, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[unitsControl insertSegmentWithTitle:title atIndex:idx animated:NO];
|
||||
}];
|
||||
unitsControl.selectedSegmentIndex = 0;
|
||||
textField.rightView = unitsControl;
|
||||
sizeTextField = textField;
|
||||
textField.delegate = self;
|
||||
[textField addTarget:self action:@selector(validateCreateDiskImageInput:) forControlEvents:UIControlEventAllEditingEvents];
|
||||
[unitsControl addTarget:self action:@selector(validateCreateDiskImageInput:) forControlEvents:UIControlEventValueChanged];
|
||||
unitLabel.text = [unitsControl titleForSegmentAtIndex:unitsControl.selectedSegmentIndex];
|
||||
}];
|
||||
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:nil]];
|
||||
UIAlertAction *createAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"Create", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
|
||||
NSString *name = [self _newDiskImageName];
|
||||
off_t size = [self _newDiskImageSize];
|
||||
createDiskImageController = nil;
|
||||
[self createDiskImageWithName:name size:size];
|
||||
}];
|
||||
[alertController addAction:createAction];
|
||||
createAction.enabled = NO;
|
||||
[self presentViewController:alertController animated:YES completion:nil];
|
||||
createDiskImageController = alertController;
|
||||
}
|
||||
|
||||
- (BOOL)validateCreateDiskImageInput:(id)sender {
|
||||
BOOL valid = NO;
|
||||
if (self.presentedViewController == createDiskImageController) {
|
||||
NSString *name = [self _newDiskImageName];
|
||||
BOOL nameIsValid = (name.length > 0) && ![name hasPrefix:@"."] && ![name containsString:@"/"] && ![name containsString:@"*"];
|
||||
|
||||
off_t size = [self _newDiskImageSize];
|
||||
BOOL sizeIsValid = (size >= 400 * 1024) && (size <= 2LL * 1024 * 1024 * 1024);
|
||||
|
||||
valid = nameIsValid && sizeIsValid;
|
||||
UIAlertAction *createAction = createDiskImageController.actions[1];
|
||||
createAction.enabled = valid;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
- (NSString*)_newDiskImageName {
|
||||
return createDiskImageController ? createDiskImageController.textFields[0].text : nil;
|
||||
}
|
||||
|
||||
- (off_t)_newDiskImageSize {
|
||||
if (createDiskImageController == nil) {
|
||||
return 0;
|
||||
}
|
||||
UISegmentedControl *unitsControl = (UISegmentedControl*)createDiskImageController.textFields[1].rightView;
|
||||
off_t unitsMultiplier = (unitsControl.selectedSegmentIndex == 0) ? 1024 : 1024 * 1024;
|
||||
off_t size = createDiskImageController.textFields[1].text.floatValue * unitsMultiplier;
|
||||
return size;
|
||||
}
|
||||
|
||||
- (void)createDiskImageWithName:(NSString*)name size:(off_t)size {
|
||||
NSString *imageFileName = [[AppDelegate sharedInstance].diskImageExtensions containsObject:name.pathExtension.lowercaseString] ? name : [name stringByAppendingPathExtension:@"img"];
|
||||
NSString *imagePath = [basePath stringByAppendingPathComponent:imageFileName];
|
||||
|
||||
int fd = open(imagePath.fileSystemRepresentation, O_CREAT | O_TRUNC | O_EXCL | O_WRONLY, 0666);
|
||||
if (fd == -1) {
|
||||
[[AppDelegate sharedInstance] showAlertWithTitle:NSLocalizedString(@"Could not create disk image", nil) message:[[NSString alloc] initWithUTF8String:strerror(errno)]];
|
||||
return;
|
||||
}
|
||||
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"Creating Disk Image", nil) message:@"\n\n\n" preferredStyle:UIAlertControllerStyleAlert];
|
||||
[self presentViewController:alertController animated:true completion:^{
|
||||
UIView *alertView = alertController.view;
|
||||
UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
|
||||
activityView.color = [UIColor blackColor];
|
||||
activityView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
|
||||
activityView.center = CGPointMake(alertView.bounds.size.width / 2.0, alertView.bounds.size.height / 2.0 + 32.0);
|
||||
[alertView addSubview:activityView];
|
||||
[activityView startAnimating];
|
||||
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
|
||||
int error = 0;
|
||||
if (ftruncate(fd, size)) {
|
||||
error = errno;
|
||||
}
|
||||
close(fd);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[activityView stopAnimating];
|
||||
[self dismissViewControllerAnimated:YES completion:^{
|
||||
if (error) {
|
||||
[[AppDelegate sharedInstance] showAlertWithTitle:NSLocalizedString(@"Could not create disk image", nil) message:[[NSString alloc] initWithUTF8String:strerror(error)]];
|
||||
}
|
||||
}];
|
||||
[self.tableView beginUpdates];
|
||||
[self loadDirectoryContents];
|
||||
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
|
||||
[self.tableView endUpdates];
|
||||
});
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Text Field Delegate
|
||||
|
||||
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
|
||||
if (textField == sizeTextField) {
|
||||
UISegmentedControl *unitsControl = (UISegmentedControl*)textField.rightView;
|
||||
NSArray *unitShortcuts = @[@"k", @"m"];
|
||||
if (string.length == 0) {
|
||||
return YES;
|
||||
} else if (string.length == 1 && [unitShortcuts indexOfObject:string.lowercaseString] != NSNotFound) {
|
||||
unitsControl.selectedSegmentIndex = [unitShortcuts indexOfObject:string.lowercaseString];
|
||||
[unitsControl sendActionsForControlEvents:UIControlEventValueChanged];
|
||||
return NO;
|
||||
} else {
|
||||
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
|
||||
NSScanner *scanner = [NSScanner scannerWithString:newString];
|
||||
double value;
|
||||
return [scanner scanDouble:&value] && scanner.isAtEnd && value >= 0;
|
||||
}
|
||||
} else {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)textFieldDidBeginEditing:(UITextField *)textField {
|
||||
if (textField == nameTextField && textField.text.pathExtension.length > 0) {
|
||||
UITextPosition *beforeExtensionPosition = [textField positionFromPosition:textField.endOfDocument offset:-(textField.text.pathExtension.length + 1)];
|
||||
UITextRange *nameWithoutExtensionRange = [textField textRangeFromPosition:textField.beginningOfDocument toPosition:beforeExtensionPosition];
|
||||
[textField performSelector:@selector(setSelectedTextRange:) withObject:nameWithoutExtensionRange afterDelay:0.1];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation FileTableViewCell
|
||||
|
||||
- (void)prepareForReuse {
|
||||
[super prepareForReuse];
|
||||
self.userInteractionEnabled = YES;
|
||||
self.textLabel.text = nil;
|
||||
self.textLabel.enabled = YES;
|
||||
self.imageView.image = nil;
|
||||
self.imageView.alpha = 1.0;
|
||||
self.detailTextLabel.text = nil;
|
||||
}
|
||||
|
||||
- (void)setFilePath:(NSString *)filePath {
|
||||
_filePath = filePath;
|
||||
NSString *fileName = filePath.lastPathComponent;
|
||||
self.textLabel.text = self.editing ? fileName : fileName.stringByDeletingPathExtension;
|
||||
NSDictionary *attributes = [[NSURL fileURLWithPath:filePath] resourceValuesForKeys:@[NSURLTotalFileSizeKey] error:NULL];
|
||||
if (attributes && attributes[NSURLTotalFileSizeKey]) {
|
||||
BOOL isDiskImage = [[AppDelegate sharedInstance].diskImageExtensions containsObject:fileName.pathExtension.lowercaseString];
|
||||
self.imageView.image = [UIImage imageNamed:isDiskImage ? @"floppy" : @"document"];
|
||||
NSString *sizeString = [NSByteCountFormatter stringFromByteCount:[attributes[NSURLTotalFileSizeKey] longLongValue] countStyle:NSByteCountFormatterCountStyleBinary];
|
||||
self.detailTextLabel.text = sizeString;
|
||||
} else {
|
||||
self.imageView.image = nil;
|
||||
self.detailTextLabel.text = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)share:(id)sender {
|
||||
UIActivityViewController *avc = [[UIActivityViewController alloc] initWithActivityItems:@[[NSURL fileURLWithPath:self.filePath]] applicationActivities:nil];
|
||||
avc.modalPresentationStyle = UIModalPresentationPopover;
|
||||
avc.popoverPresentationController.sourceView = self.imageView;
|
||||
avc.popoverPresentationController.sourceRect = self.imageView.bounds;
|
||||
[self.controller presentViewController:avc animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)rename:(id)sender {
|
||||
[self.controller askRenameFile:self.filePath];
|
||||
}
|
||||
|
||||
- (void)delete:(id)sender {
|
||||
[self.controller askDeleteFile:self.filePath];
|
||||
}
|
||||
|
||||
@end
|
@ -451,6 +451,10 @@ LOCALPROC MyUnlockFile(FILE *refnum) {
|
||||
LOCALFUNC tMacErr vSonyEject0(tDrive Drive_No, blnr deleteit) {
|
||||
FILE *refnum = Drives[Drive_No];
|
||||
|
||||
NSDictionary *userInfo = @{@"path": DriveNames[Drive_No],
|
||||
@"drive": @(Drive_No),
|
||||
@"delete": @(deleteit)};
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MNVMDidEjectDiskNotification object:[AppDelegate sharedInstance] userInfo:userInfo];
|
||||
DiskEjectedNotify(Drive_No);
|
||||
|
||||
#if HaveAdvisoryLocks
|
||||
@ -524,6 +528,10 @@ LOCALFUNC blnr Sony_Insert0(FILE *refnum, blnr locked, NSString *filePath) {
|
||||
MacMsg(kStrTooManyImagesTitle, kStrTooManyImagesMessage,
|
||||
falseblnr);
|
||||
} else {
|
||||
NSDictionary *userInfo = @{@"path": filePath,
|
||||
@"drive": @(Drive_No)};
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MNVMDidInsertDiskNotification object:[AppDelegate sharedInstance] userInfo:userInfo];
|
||||
|
||||
/* printf("Sony_Insert0 %d\n", (int)Drive_No); */
|
||||
|
||||
#if HaveAdvisoryLocks
|
||||
@ -548,7 +556,18 @@ LOCALFUNC blnr Sony_Insert0(FILE *refnum, blnr locked, NSString *filePath) {
|
||||
return IsOk;
|
||||
}
|
||||
|
||||
LOCALFUNC blnr Sony_Insert1(NSString *filePath, blnr silentfail) {
|
||||
GLOBALFUNC blnr Sony_IsInserted(NSString *filePath) {
|
||||
#if IncludeSonyGetName
|
||||
for (int i=0; i < NumDrives; i++) {
|
||||
if (vSonyIsInserted(i) && [DriveNames[i] isEqualToString:filePath]) {
|
||||
return trueblnr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return falseblnr;
|
||||
}
|
||||
|
||||
GLOBALFUNC blnr Sony_Insert1(NSString *filePath, blnr silentfail) {
|
||||
/* const char *drivepath = [filePath UTF8String]; */
|
||||
const char *drivepath = [filePath fileSystemRepresentation];
|
||||
blnr locked = falseblnr;
|
||||
|
16
Mini vMac/SettingsViewController.h
Normal file
@ -0,0 +1,16 @@
|
||||
//
|
||||
// SettingsViewController.h
|
||||
// Mini vMac
|
||||
//
|
||||
// Created by Jesús A. Álvarez on 07/05/2016.
|
||||
// Copyright © 2016 namedfork. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface SettingsViewController : UITableViewController
|
||||
|
||||
- (IBAction)showInsertDisk:(id)sender;
|
||||
- (IBAction)dismiss:(id)sender;
|
||||
|
||||
@end
|
102
Mini vMac/SettingsViewController.m
Normal file
@ -0,0 +1,102 @@
|
||||
//
|
||||
// SettingsViewController.m
|
||||
// Mini vMac
|
||||
//
|
||||
// Created by Jesús A. Álvarez on 07/05/2016.
|
||||
// Copyright © 2016 namedfork. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SettingsViewController.h"
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@interface SettingsViewController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation SettingsViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// Uncomment the following line to preserve selection between presentations.
|
||||
// self.clearsSelectionOnViewWillAppear = NO;
|
||||
|
||||
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
|
||||
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
|
||||
}
|
||||
|
||||
- (void)showInsertDisk:(id)sender {
|
||||
[[AppDelegate sharedInstance] showInsertDisk:sender];
|
||||
}
|
||||
|
||||
- (void)dismiss:(id)sender {
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
#warning Incomplete implementation, return the number of sections
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
#warning Incomplete implementation, return the number of rows
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:<#@"reuseIdentifier"#> forIndexPath:indexPath];
|
||||
|
||||
// Configure the cell...
|
||||
|
||||
return cell;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// Override to support conditional editing of the table view.
|
||||
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
// Return NO if you do not want the specified item to be editable.
|
||||
return YES;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// Override to support editing the table view.
|
||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (editingStyle == UITableViewCellEditingStyleDelete) {
|
||||
// Delete the row from the data source
|
||||
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
|
||||
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
|
||||
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// Override to support rearranging the table view.
|
||||
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
// Override to support conditional rearranging of the table view.
|
||||
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
// Return NO if you do not want the item to be re-orderable.
|
||||
return YES;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
#pragma mark - Navigation
|
||||
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||
// Get the new view controller using [segue destinationViewController].
|
||||
// Pass the selected object to the new view controller.
|
||||
}
|
||||
*/
|
||||
|
||||
@end
|
@ -8,6 +8,7 @@
|
||||
|
||||
#import "ViewController.h"
|
||||
#import "TouchScreen.h"
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@interface ViewController ()
|
||||
|
||||
@ -37,4 +38,10 @@
|
||||
[self.view insertSubview:pointingDeviceView aboveSubview:self.screenView];
|
||||
}
|
||||
|
||||
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
|
||||
if (motion == UIEventSubtypeMotionShake) {
|
||||
[[AppDelegate sharedInstance] showInsertDisk:self];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|