diff --git a/XIONControlPanel.xcodeproj/project.pbxproj b/XIONControlPanel.xcodeproj/project.pbxproj index 83de131..bdde5f8 100644 --- a/XIONControlPanel.xcodeproj/project.pbxproj +++ b/XIONControlPanel.xcodeproj/project.pbxproj @@ -9,9 +9,14 @@ /* Begin PBXBuildFile section */ 0C20E2B91C33514100BA789B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C20E2B51C33514100BA789B /* AppDelegate.swift */; }; 0C20E2BB1C33529700BA789B /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C20E2BA1C33529700BA789B /* MainViewController.swift */; }; - 0C20E2BD1C33534F00BA789B /* BackgroundViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C20E2BC1C33534F00BA789B /* BackgroundViewController.swift */; }; + 0C20E2BD1C33534F00BA789B /* VisualizationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C20E2BC1C33534F00BA789B /* VisualizationViewController.swift */; }; 0C3CAEAF1C3350C800B856AD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0C3CAEAE1C3350C800B856AD /* Assets.xcassets */; }; 0C3CAEB21C3350C800B856AD /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0C3CAEB01C3350C800B856AD /* LaunchScreen.storyboard */; }; + 0C41EF4A1C34B51500AF847F /* ArcadeMachinesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C41EF491C34B51500AF847F /* ArcadeMachinesViewController.swift */; }; + 0C41EF4E1C34B81F00AF847F /* KSIRingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C41EF4D1C34B81F00AF847F /* KSIRingView.m */; }; + 0C41EF501C34B97700AF847F /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C41EF4F1C34B97700AF847F /* HeaderView.swift */; }; + 0C41EF521C34BA4E00AF847F /* Orbitron-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 0C41EF511C34BA4E00AF847F /* Orbitron-Medium.ttf */; }; + 0C41EF541C34BC9800AF847F /* XIONLogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C41EF531C34BC9800AF847F /* XIONLogoView.swift */; }; 0C63A8731C337381007E4B52 /* CubletsTechnique.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0C63A8721C337381007E4B52 /* CubletsTechnique.plist */; }; 0C63A8761C3373D1007E4B52 /* HorizontalBlur.vsh in Resources */ = {isa = PBXBuildFile; fileRef = 0C63A8751C3373D1007E4B52 /* HorizontalBlur.vsh */; }; 0C63A8781C3373D9007E4B52 /* HorizontalBlur.fsh in Resources */ = {isa = PBXBuildFile; fileRef = 0C63A8771C3373D9007E4B52 /* HorizontalBlur.fsh */; }; @@ -27,11 +32,17 @@ /* Begin PBXFileReference section */ 0C20E2B51C33514100BA789B /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 0C20E2BA1C33529700BA789B /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; - 0C20E2BC1C33534F00BA789B /* BackgroundViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundViewController.swift; sourceTree = ""; }; + 0C20E2BC1C33534F00BA789B /* VisualizationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VisualizationViewController.swift; sourceTree = ""; }; 0C3CAEA41C3350C800B856AD /* XIONControlPanel.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = XIONControlPanel.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0C3CAEAE1C3350C800B856AD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 0C3CAEB11C3350C800B856AD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 0C3CAEB31C3350C800B856AD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0C41EF491C34B51500AF847F /* ArcadeMachinesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArcadeMachinesViewController.swift; sourceTree = ""; }; + 0C41EF4C1C34B81F00AF847F /* KSIRingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSIRingView.h; sourceTree = ""; }; + 0C41EF4D1C34B81F00AF847F /* KSIRingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSIRingView.m; sourceTree = ""; }; + 0C41EF4F1C34B97700AF847F /* HeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = ""; }; + 0C41EF511C34BA4E00AF847F /* Orbitron-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Orbitron-Medium.ttf"; sourceTree = ""; }; + 0C41EF531C34BC9800AF847F /* XIONLogoView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XIONLogoView.swift; sourceTree = ""; }; 0C63A8721C337381007E4B52 /* CubletsTechnique.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = CubletsTechnique.plist; sourceTree = ""; }; 0C63A8751C3373D1007E4B52 /* HorizontalBlur.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = HorizontalBlur.vsh; sourceTree = ""; }; 0C63A8771C3373D9007E4B52 /* HorizontalBlur.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; path = HorizontalBlur.fsh; sourceTree = ""; }; @@ -61,8 +72,9 @@ isa = PBXGroup; children = ( 0C3CAEAE1C3350C800B856AD /* Assets.xcassets */, - 0C3CAEB01C3350C800B856AD /* LaunchScreen.storyboard */, 0C3CAEB31C3350C800B856AD /* Info.plist */, + 0C3CAEB01C3350C800B856AD /* LaunchScreen.storyboard */, + 0C63A87A1C33C655007E4B52 /* XIONControlPanel-Bridging-Header.h */, ); name = "Supporting Files"; path = SupportingFiles; @@ -79,8 +91,9 @@ 0C20E2B61C33514100BA789B /* Controllers */ = { isa = PBXGroup; children = ( - 0C20E2BC1C33534F00BA789B /* BackgroundViewController.swift */, + 0C41EF491C34B51500AF847F /* ArcadeMachinesViewController.swift */, 0C20E2BA1C33529700BA789B /* MainViewController.swift */, + 0C20E2BC1C33534F00BA789B /* VisualizationViewController.swift */, ); path = Controllers; sourceTree = ""; @@ -95,6 +108,8 @@ 0C20E2B81C33514100BA789B /* Views */ = { isa = PBXGroup; children = ( + 0C41EF4F1C34B97700AF847F /* HeaderView.swift */, + 0C41EF531C34BC9800AF847F /* XIONLogoView.swift */, ); path = Views; sourceTree = ""; @@ -103,6 +118,7 @@ isa = PBXGroup; children = ( 0C63A8721C337381007E4B52 /* CubletsTechnique.plist */, + 0C41EF511C34BA4E00AF847F /* Orbitron-Medium.ttf */, ); path = Resources; sourceTree = ""; @@ -128,6 +144,7 @@ children = ( 0C20E2B41C33514100BA789B /* Application */, 0C20E2B61C33514100BA789B /* Controllers */, + 0C41EF4B1C34B81F00AF847F /* External */, 0C20E2B71C33514100BA789B /* Models */, 0C63A8741C3373BC007E4B52 /* Shaders */, 0C20E2C81C336F2E00BA789B /* Resources */, @@ -138,6 +155,15 @@ path = XIONControlPanel; sourceTree = ""; }; + 0C41EF4B1C34B81F00AF847F /* External */ = { + isa = PBXGroup; + children = ( + 0C41EF4C1C34B81F00AF847F /* KSIRingView.h */, + 0C41EF4D1C34B81F00AF847F /* KSIRingView.m */, + ); + path = External; + sourceTree = ""; + }; 0C63A8741C3373BC007E4B52 /* Shaders */ = { isa = PBXGroup; children = ( @@ -158,7 +184,6 @@ children = ( 0C63A87B1C33C655007E4B52 /* NSValue+XIONAdditions.h */, 0C63A87C1C33C655007E4B52 /* NSValue+XIONAdditions.m */, - 0C63A87A1C33C655007E4B52 /* XIONControlPanel-Bridging-Header.h */, ); path = Utilities; sourceTree = ""; @@ -230,6 +255,7 @@ 0C3CAEB21C3350C800B856AD /* LaunchScreen.storyboard in Resources */, 0C3CAEAF1C3350C800B856AD /* Assets.xcassets in Resources */, 0C63A8841C33DC29007E4B52 /* VerticalBlur.fsh in Resources */, + 0C41EF521C34BA4E00AF847F /* Orbitron-Medium.ttf in Resources */, 0C63A8851C33DC29007E4B52 /* VerticalBlur.vsh in Resources */, 0C63A8891C33EB3B007E4B52 /* FinalRender.vsh in Resources */, 0C63A8781C3373D9007E4B52 /* HorizontalBlur.fsh in Resources */, @@ -243,10 +269,14 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 0C41EF4E1C34B81F00AF847F /* KSIRingView.m in Sources */, 0C63A87D1C33C655007E4B52 /* NSValue+XIONAdditions.m in Sources */, - 0C20E2BD1C33534F00BA789B /* BackgroundViewController.swift in Sources */, + 0C20E2BD1C33534F00BA789B /* VisualizationViewController.swift in Sources */, + 0C41EF4A1C34B51500AF847F /* ArcadeMachinesViewController.swift in Sources */, 0C20E2B91C33514100BA789B /* AppDelegate.swift in Sources */, 0C20E2BB1C33529700BA789B /* MainViewController.swift in Sources */, + 0C41EF501C34B97700AF847F /* HeaderView.swift in Sources */, + 0C41EF541C34BC9800AF847F /* XIONLogoView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -359,7 +389,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.xionsf.XIONControlPanel; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; - SWIFT_OBJC_BRIDGING_HEADER = "XIONControlPanel/Utilities/XIONControlPanel-Bridging-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "XIONControlPanel/SupportingFiles/XIONControlPanel-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; @@ -376,7 +406,7 @@ PRODUCT_BUNDLE_IDENTIFIER = com.xionsf.XIONControlPanel; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; - SWIFT_OBJC_BRIDGING_HEADER = "XIONControlPanel/Utilities/XIONControlPanel-Bridging-Header.h"; + SWIFT_OBJC_BRIDGING_HEADER = "XIONControlPanel/SupportingFiles/XIONControlPanel-Bridging-Header.h"; }; name = Release; }; diff --git a/XIONControlPanel/Application/AppDelegate.swift b/XIONControlPanel/Application/AppDelegate.swift index b46da2d..8270fcc 100644 --- a/XIONControlPanel/Application/AppDelegate.swift +++ b/XIONControlPanel/Application/AppDelegate.swift @@ -25,6 +25,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask { - return UIInterfaceOrientationMask.Portrait + return UIInterfaceOrientationMask.Landscape } } diff --git a/XIONControlPanel/Controllers/ArcadeMachinesViewController.swift b/XIONControlPanel/Controllers/ArcadeMachinesViewController.swift new file mode 100644 index 0000000..ddca4cc --- /dev/null +++ b/XIONControlPanel/Controllers/ArcadeMachinesViewController.swift @@ -0,0 +1,16 @@ +// +// ArcadeMachinesViewController.swift +// XIONControlPanel +// +// Created by Charles Magahern on 12/30/15. +// Copyright © 2015 XION. All rights reserved. +// + +import UIKit + +class ArcadeMachinesViewController: UIViewController { + override func viewDidLoad() + { + super.viewDidLoad() + } +} diff --git a/XIONControlPanel/Controllers/MainViewController.swift b/XIONControlPanel/Controllers/MainViewController.swift index 3bc7456..e701d9e 100644 --- a/XIONControlPanel/Controllers/MainViewController.swift +++ b/XIONControlPanel/Controllers/MainViewController.swift @@ -9,7 +9,9 @@ import UIKit class MainViewController: UIViewController { - private var _backgroundController: BackgroundViewController = BackgroundViewController() + private var _visualizationController: VisualizationViewController = VisualizationViewController() + private var _machinesController: ArcadeMachinesViewController = ArcadeMachinesViewController() + private var _headerView: HeaderView = HeaderView() // MARK: Overrides @@ -19,22 +21,13 @@ class MainViewController: UIViewController { self.view.backgroundColor = UIColor.blackColor() - self.addChildViewController(_backgroundController) - self.view.addSubview(_backgroundController.view) + self.addChildViewController(_visualizationController) + self.view.addSubview(_visualizationController.view) - let doubleTapGR = UITapGestureRecognizer(target: self, action: Selector("_handleDoubleFingerTap:")) - doubleTapGR.numberOfTouchesRequired = 2 - self.view.addGestureRecognizer(doubleTapGR) + self.addChildViewController(_machinesController) + self.view.addSubview(_machinesController.view) - let singleTapGR = UITapGestureRecognizer(target: self, action: Selector("_handleSingleFingerTap:")) - singleTapGR.numberOfTouchesRequired = 1 - singleTapGR.requireGestureRecognizerToFail(doubleTapGR) - self.view.addGestureRecognizer(singleTapGR) - } - - override func prefersStatusBarHidden() -> Bool - { - return true + self.view.addSubview(_headerView) } override func viewDidLayoutSubviews() @@ -42,19 +35,50 @@ class MainViewController: UIViewController { super.viewDidLayoutSubviews() let bounds = self.view.bounds - _backgroundController.view.frame = bounds + let headerBounds = CGRect( + x: 0.0, + y: 0.0, + width: bounds.size.width, + height: rint(bounds.size.height / 10.0) + ) + let bodyBounds = CGRect( + x: 0.0, + y: CGRectGetMaxY(headerBounds), + width: bounds.size.width, + height: bounds.size.height - headerBounds.size.height + ) + + _headerView.frame = headerBounds + + let visualizationFrame = CGRect( + x: bodyBounds.origin.x, + y: bodyBounds.origin.y, + width: rint((5.0 / 8.0) * bodyBounds.size.width), + height: bodyBounds.size.height + ) + _visualizationController.view.frame = visualizationFrame + + let machinesControllerFrame = CGRect( + x: CGRectGetMaxX(visualizationFrame), + y: bodyBounds.origin.y, + width: bodyBounds.size.width - visualizationFrame.size.width, + height: bodyBounds.size.height + ) + _machinesController.view.frame = machinesControllerFrame } - // MARK: Internal - - internal func _handleSingleFingerTap(gestureRecognizer: UITapGestureRecognizer) + override func viewDidAppear(animated: Bool) { - let randomPercentage = Float(arc4random()) / Float(UInt32.max) - _backgroundController.setPercentActivated(randomPercentage, animated: true) + _headerView.beginAnimating() } - internal func _handleDoubleFingerTap(gestureRecognizer: UITapGestureRecognizer) + override func viewDidDisappear(animated: Bool) { - _backgroundController.setPercentActivated(0.0, animated: true) + _headerView.stopAnimating() + } + + override func prefersStatusBarHidden() -> Bool + { + return true } } diff --git a/XIONControlPanel/Controllers/BackgroundViewController.swift b/XIONControlPanel/Controllers/VisualizationViewController.swift similarity index 92% rename from XIONControlPanel/Controllers/BackgroundViewController.swift rename to XIONControlPanel/Controllers/VisualizationViewController.swift index aa1fdc5..a874b6b 100644 --- a/XIONControlPanel/Controllers/BackgroundViewController.swift +++ b/XIONControlPanel/Controllers/VisualizationViewController.swift @@ -1,5 +1,5 @@ // -// BackgroundViewController.swift +// VisualizationViewController.swift // XIONControlPanel // // Created by Charles Magahern on 12/29/15. @@ -12,9 +12,9 @@ import GLKit import SceneKit import UIKit -let π = Float(M_PI) +let π = CGFloat(M_PI) -class BackgroundViewController: UIViewController { +class VisualizationViewController: UIViewController { private var _scene: SCNScene = SCNScene() private var _sceneView: SCNView? private var _cameraNode: SCNNode = SCNNode() @@ -34,7 +34,6 @@ class BackgroundViewController: UIViewController { view.backgroundColor = UIColor.blackColor() view.scene = _scene view.allowsCameraControl = false - view.showsStatistics = true _sceneView = view self.view = view @@ -88,7 +87,7 @@ class BackgroundViewController: UIViewController { let ry = Float(arc4random()) / Float(UInt32.max) let rz = Float(arc4random()) / Float(UInt32.max) let rotAxis = SCNVector3Make(rx, ry, rz) - let rotCoeff = Float(arc4random() % 2 == 0 ? -1.0 : 1.0) + let rotCoeff = CGFloat(arc4random() % 2 == 0 ? -1.0 : 1.0) let rotAngle = CGFloat(rotCoeff * π / 4.0) let rotAction = SCNAction.rotateByAngle(rotAngle, aroundAxis: rotAxis, duration: 0.8) @@ -108,7 +107,7 @@ class BackgroundViewController: UIViewController { let camera = SCNCamera() _cameraNode.camera = camera - _cameraNode.position = SCNVector3Make(0.0, 0.0, 50.0) + _cameraNode.position = SCNVector3Make(0.0, 0.0, 30.0) _scene.rootNode.addChildNode(_cameraNode) let centerNode = SCNNode() @@ -136,10 +135,10 @@ class BackgroundViewController: UIViewController { { _cublets.removeAll() - let sz = Float(BackgroundViewController.cubletsSize) - let dim = BackgroundViewController.cubletsDimensions + let sz = Float(VisualizationViewController.cubletsSize) + let dim = VisualizationViewController.cubletsDimensions let dimf = Float(dim) - let spacing = Float(BackgroundViewController.cubletsSpacing) + let spacing = Float(VisualizationViewController.cubletsSpacing) let volume = (dimf * sz) + ((dimf - 1.0) * spacing) let orig = -volume / 2.0 @@ -177,7 +176,7 @@ class BackgroundViewController: UIViewController { internal func _setupAnimation() { let rotAxis = SCNVector3Make(0.25, 1.75, 1.0) - let rotAngle = CGFloat(Float(2.0) * π) + let rotAngle = 2.0 * π let rotAction = SCNAction.repeatActionForever(SCNAction.rotateByAngle(rotAngle, aroundAxis: rotAxis, duration: 40.0)) _cubletsNode.runAction(rotAction) } diff --git a/XIONControlPanel/External/KSIRingView.h b/XIONControlPanel/External/KSIRingView.h new file mode 100644 index 0000000..91f61d2 --- /dev/null +++ b/XIONControlPanel/External/KSIRingView.h @@ -0,0 +1,47 @@ +// +// KSIRingView.h +// Kisai +// +// Created by Charles Magahern on 2/28/15. +// Copyright (c) 2015 zanneth. All rights reserved. +// + +#import + +@interface KSIRingPattern : NSObject + +@property (nonatomic, readonly) UIColor *color; +@property (nonatomic, readonly) CGFloat beginSegmentAngle; +@property (nonatomic, readonly) CGFloat segmentWidth; +@property (nonatomic, readonly) CGFloat segmentLengthRadians; +@property (nonatomic, readonly) CGFloat segmentIntervalRadians; +@property (nonatomic, readonly) NSUInteger segmentsCount; + +- (instancetype)initWithColor:(UIColor *)color + segmentLength:(CGFloat)segmentLengthInRadians + segmentsCount:(NSUInteger)segmentsCount; + +@end + +@interface KSIMutableRingPattern : KSIRingPattern + +@property (nonatomic, strong) UIColor *color; +@property (nonatomic, assign) CGFloat beginSegmentAngle; +@property (nonatomic, assign) CGFloat segmentWidth; +@property (nonatomic, assign) CGFloat segmentLengthRadians; +@property (nonatomic, assign) CGFloat segmentIntervalRadians; +@property (nonatomic, assign) NSUInteger segmentsCount; + +@end + +// ----------------------------------------------------------------------------- + +@interface KSIRingView : UIView + +@property (nonatomic, readonly) NSArray *ringPatterns; // KSIRingPattern(s) + +- (void)addRingPattern:(KSIRingPattern *)pattern; +- (void)insertRingPattern:(KSIRingPattern *)pattern atIndex:(NSUInteger)index; +- (void)removeAllRingPatterns; + +@end diff --git a/XIONControlPanel/External/KSIRingView.m b/XIONControlPanel/External/KSIRingView.m new file mode 100644 index 0000000..919421b --- /dev/null +++ b/XIONControlPanel/External/KSIRingView.m @@ -0,0 +1,169 @@ +// +// KSIRingView.m +// Kisai +// +// Created by Charles Magahern on 2/28/15. +// Copyright (c) 2015 zanneth. All rights reserved. +// + +#import "KSIRingView.h" + +@implementation KSIRingPattern { +@protected + UIColor *_color; + CGFloat _beginSegmentAngle; + CGFloat _segmentWidth; + CGFloat _segmentLengthRadians; + CGFloat _segmentIntervalRadians; + NSUInteger _segmentsCount; +} + +- (instancetype)initWithColor:(UIColor *)color + segmentLength:(CGFloat)segmentLengthInRadians + segmentsCount:(NSUInteger)segmentsCount +{ + self = [super init]; + if (self) { + _color = color; + _beginSegmentAngle = 0.0; + _segmentWidth = 5.0; + _segmentLengthRadians = segmentLengthInRadians; + _segmentIntervalRadians = 0.0; + _segmentsCount = segmentsCount; + } + return self; +} + +- (instancetype)init +{ + return [self initWithColor:[UIColor whiteColor] segmentLength:(2.0 * M_PI) segmentsCount:1]; +} + +- (id)copyWithZone:(NSZone *)zone +{ + return [self _copyWithZone:zone usingConcreteClass:[KSIRingPattern class]]; +} + +- (id)mutableCopyWithZone:(NSZone *)zone +{ + return [self _copyWithZone:zone usingConcreteClass:[KSIMutableRingPattern class]]; +} + +#pragma mark - Internal + +- (id)_copyWithZone:(NSZone *)zone usingConcreteClass:(Class)concreteClass +{ + KSIRingPattern *copy = [[concreteClass allocWithZone:zone] init]; + copy->_color = _color; + copy->_beginSegmentAngle = _beginSegmentAngle; + copy->_segmentWidth = _segmentWidth; + copy->_segmentLengthRadians = _segmentLengthRadians; + copy->_segmentIntervalRadians = _segmentIntervalRadians; + copy->_segmentsCount = _segmentsCount; + return copy; +} + +@end + +// ----------------------------------------------------------------------------- + +@implementation KSIMutableRingPattern +@dynamic color; +@dynamic beginSegmentAngle; +@dynamic segmentWidth; +@dynamic segmentLengthRadians; +@dynamic segmentIntervalRadians; +@dynamic segmentsCount; + + +- (void)setColor:(UIColor *)color { _color = color; } +- (void)setBeginSegmentAngle:(CGFloat)beginSegmentAngle { _beginSegmentAngle = beginSegmentAngle; } +- (void)setSegmentWidth:(CGFloat)segmentWidth { _segmentWidth = segmentWidth; } +- (void)setSegmentLengthRadians:(CGFloat)segmentLengthRadians { _segmentLengthRadians = segmentLengthRadians; } +- (void)setSegmentIntervalRadians:(CGFloat)segmentIntervalRadians { _segmentIntervalRadians = segmentIntervalRadians; } +- (void)setSegmentsCount:(NSUInteger)segmentsCount { _segmentsCount = segmentsCount; } + +@end + +// ----------------------------------------------------------------------------- + +@implementation KSIRingView { + NSMutableArray *_ringPatterns; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + _ringPatterns = [[NSMutableArray alloc] init]; + } + return self; +} + +#pragma mark - Accessors + +- (NSArray *)ringPatterns +{ + return _ringPatterns; +} + +#pragma mark - API + +- (void)addRingPattern:(KSIRingPattern *)pattern +{ + [_ringPatterns addObject:[pattern copy]]; + [self setNeedsDisplay]; +} + +- (void)insertRingPattern:(KSIRingPattern *)pattern atIndex:(NSUInteger)index +{ + [_ringPatterns insertObject:[pattern copy] atIndex:index]; + [self setNeedsDisplay]; +} + +- (void)removeAllRingPatterns +{ + [_ringPatterns removeAllObjects]; + [self setNeedsDisplay]; +} + +#pragma mark - Drawing + +- (void)drawRect:(CGRect)rect +{ + const CGFloat radius = rint(rect.size.height / 2.0 - 1.0); + const CGPoint center = { + .x = rint(rect.size.width / 2.0), + .y = rint(rect.size.height / 2.0) + }; + + CGContextRef ctx = UIGraphicsGetCurrentContext(); + CGFloat currentRadius = radius; + + for (KSIRingPattern *ringPattern in _ringPatterns) { + if (![ringPattern.color isEqual:[UIColor clearColor]]) { + NSUInteger segmentsCount = ringPattern.segmentsCount; + CGFloat currentAngle = ringPattern.beginSegmentAngle; + CGFloat segmentWidth = ringPattern.segmentWidth; + + [ringPattern.color setStroke]; + + for (unsigned i = 0; i < segmentsCount; ++i) { + CGFloat beginAngle = currentAngle; + CGFloat endAngle = beginAngle + ringPattern.segmentLengthRadians; + CGContextAddArc(ctx, center.x, center.y, currentRadius - (segmentWidth / 2.0), beginAngle, endAngle, NO); + + if (i < segmentsCount - 1) { + currentAngle += ringPattern.segmentIntervalRadians; + } + + CGContextSetLineWidth(ctx, segmentWidth); + CGContextStrokePath(ctx); + } + } + + currentRadius -= ringPattern.segmentWidth - 1.0; + } +} + +@end diff --git a/XIONControlPanel/Resources/Orbitron-Medium.ttf b/XIONControlPanel/Resources/Orbitron-Medium.ttf new file mode 100755 index 0000000..53cc94c Binary files /dev/null and b/XIONControlPanel/Resources/Orbitron-Medium.ttf differ diff --git a/XIONControlPanel/SupportingFiles/Assets.xcassets/Contents.json b/XIONControlPanel/SupportingFiles/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/XIONControlPanel/SupportingFiles/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogo.imageset/Contents.json b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogo.imageset/Contents.json new file mode 100644 index 0000000..ddf1a41 --- /dev/null +++ b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogo.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "XIONLogo.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogo.imageset/XIONLogo.png b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogo.imageset/XIONLogo.png new file mode 100644 index 0000000..5ad67af Binary files /dev/null and b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogo.imageset/XIONLogo.png differ diff --git a/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoInnerRing.imageset/Contents.json b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoInnerRing.imageset/Contents.json new file mode 100644 index 0000000..986f206 --- /dev/null +++ b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoInnerRing.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "XIONLogoInnerRing.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoInnerRing.imageset/XIONLogoInnerRing.png b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoInnerRing.imageset/XIONLogoInnerRing.png new file mode 100644 index 0000000..45af296 Binary files /dev/null and b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoInnerRing.imageset/XIONLogoInnerRing.png differ diff --git a/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoOuterRing.imageset/Contents.json b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoOuterRing.imageset/Contents.json new file mode 100644 index 0000000..e691f7d --- /dev/null +++ b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoOuterRing.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "XIONLogoOuterRing.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoOuterRing.imageset/XIONLogoOuterRing.png b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoOuterRing.imageset/XIONLogoOuterRing.png new file mode 100644 index 0000000..3940131 Binary files /dev/null and b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoOuterRing.imageset/XIONLogoOuterRing.png differ diff --git a/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoWithRing.imageset/Contents.json b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoWithRing.imageset/Contents.json new file mode 100644 index 0000000..c8d21ba --- /dev/null +++ b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoWithRing.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "XIONLogoWithRing.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoWithRing.imageset/XIONLogoWithRing.png b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoWithRing.imageset/XIONLogoWithRing.png new file mode 100644 index 0000000..862608b Binary files /dev/null and b/XIONControlPanel/SupportingFiles/Assets.xcassets/XIONLogoWithRing.imageset/XIONLogoWithRing.png differ diff --git a/XIONControlPanel/SupportingFiles/Info.plist b/XIONControlPanel/SupportingFiles/Info.plist index 96efb36..0e68bad 100644 --- a/XIONControlPanel/SupportingFiles/Info.plist +++ b/XIONControlPanel/SupportingFiles/Info.plist @@ -22,6 +22,10 @@ 1 LSRequiresIPhoneOS + UIAppFonts + + Orbitron-Medium.ttf + UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities @@ -34,7 +38,8 @@ UISupportedInterfaceOrientations - UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad diff --git a/XIONControlPanel/Utilities/XIONControlPanel-Bridging-Header.h b/XIONControlPanel/SupportingFiles/XIONControlPanel-Bridging-Header.h similarity index 85% rename from XIONControlPanel/Utilities/XIONControlPanel-Bridging-Header.h rename to XIONControlPanel/SupportingFiles/XIONControlPanel-Bridging-Header.h index 3df906e..295369d 100644 --- a/XIONControlPanel/Utilities/XIONControlPanel-Bridging-Header.h +++ b/XIONControlPanel/SupportingFiles/XIONControlPanel-Bridging-Header.h @@ -3,3 +3,4 @@ // #import "NSValue+XIONAdditions.h" +#import "KSIRingView.h" diff --git a/XIONControlPanel/Views/HeaderView.swift b/XIONControlPanel/Views/HeaderView.swift new file mode 100644 index 0000000..f1f77da --- /dev/null +++ b/XIONControlPanel/Views/HeaderView.swift @@ -0,0 +1,90 @@ +// +// HeaderView.swift +// XIONControlPanel +// +// Created by Charles Magahern on 12/30/15. +// Copyright © 2015 XION. All rights reserved. +// + +import Darwin +import Foundation +import UIKit + +class HeaderView: UIView { + private var _xionLogoView: XIONLogoView = XIONLogoView() + private var _xionTitleLabel: UILabel = UILabel() + private var _xionJapaneseLabel: UILabel = UILabel() + + override init(frame: CGRect) + { + super.init(frame: frame) + + self.backgroundColor = UIColor.blackColor() + self.addSubview(_xionLogoView) + + _xionTitleLabel.font = UIFont(name: "Orbitron-Medium", size: 16.0) + _xionTitleLabel.text = "XION arcade system control panel" + _xionTitleLabel.textColor = UIColor.whiteColor() + self.addSubview(_xionTitleLabel) + + _xionJapaneseLabel.font = UIFont(name: "Orbitron-Medium", size: 12.0) + _xionJapaneseLabel.text = "ザイーオンゲームセンターのシステム制御プログラム" + _xionJapaneseLabel.textColor = UIColor.whiteColor() + self.addSubview(_xionJapaneseLabel) + } + + required init?(coder aDecoder: NSCoder) + { + fatalError("unsupported") + } + + override func layoutSubviews() + { + super.layoutSubviews() + + let bounds = self.bounds + let hpadding = CGFloat(10.0) + + let logoDimensions = rint(bounds.size.height / 1.2) + let logoFrame = CGRect( + x: hpadding, + y: rint(bounds.size.height / 2.0 - logoDimensions / 2.0), + width: logoDimensions, + height: logoDimensions + ) + _xionLogoView.frame = logoFrame + + let titleJPVerticalMargin: CGFloat = 5.0 + let titleLabelSize = _xionTitleLabel.sizeThatFits(bounds.size) + let jpLabelSize = _xionJapaneseLabel.sizeThatFits(bounds.size) + let totalLabelsHeight = titleLabelSize.height + titleJPVerticalMargin + jpLabelSize.height + + let titleFrame = CGRect( + x: CGRectGetMaxX(logoFrame) + hpadding * 2.0, + y: rint(bounds.size.height / 2.0 - totalLabelsHeight / 2.0), + width: titleLabelSize.width, + height: titleLabelSize.height + ) + _xionTitleLabel.frame = titleFrame + + let jpTitleFrame = CGRect( + x: titleFrame.origin.x, + y: CGRectGetMaxY(titleFrame) + titleJPVerticalMargin, + width: jpLabelSize.width, + height: jpLabelSize.height + 2.0 + ) + _xionJapaneseLabel.frame = jpTitleFrame + } + + // MARK: API + + func beginAnimating() + { + _xionLogoView.beginAnimating() + } + + func stopAnimating() + { + _xionLogoView.stopAnimating() + } +} diff --git a/XIONControlPanel/Views/XIONLogoView.swift b/XIONControlPanel/Views/XIONLogoView.swift new file mode 100644 index 0000000..381083c --- /dev/null +++ b/XIONControlPanel/Views/XIONLogoView.swift @@ -0,0 +1,78 @@ +// +// XIONLogoView.swift +// XIONControlPanel +// +// Created by Charles Magahern on 12/30/15. +// Copyright © 2015 XION. All rights reserved. +// + +import UIKit + +class XIONLogoView: UIView { + private var _xionLogoImageView: UIImageView = UIImageView() + private var _logoInnerRingImageView: UIImageView = UIImageView() + private var _logoOuterRingImageView: UIImageView = UIImageView() + + override init(frame: CGRect) + { + super.init(frame: frame) + + self.backgroundColor = UIColor.blackColor() + + _xionLogoImageView.image = UIImage(named: "XIONLogoWithRing") + _xionLogoImageView.contentMode = .ScaleAspectFit + + _logoInnerRingImageView.image = UIImage(named: "XIONLogoInnerRing") + _logoInnerRingImageView.contentMode = .ScaleAspectFit + + _logoOuterRingImageView.image = UIImage(named: "XIONLogoOuterRing") + _logoOuterRingImageView.contentMode = .ScaleAspectFit + + self.addSubview(_logoOuterRingImageView) + self.addSubview(_logoInnerRingImageView) + self.addSubview(_xionLogoImageView) + } + + required init?(coder aDecoder: NSCoder) + { + fatalError("unsupported") + } + + override func layoutSubviews() + { + super.layoutSubviews() + + let bounds = self.bounds + _xionLogoImageView.frame = bounds + _logoInnerRingImageView.frame = bounds + _logoOuterRingImageView.frame = bounds + } + + // MARK: API + + func beginAnimating() + { + let duration: NSTimeInterval = 20.0 + + let clockwiseAnim = CABasicAnimation(keyPath: "transform.rotation") + clockwiseAnim.fromValue = 0.0 + clockwiseAnim.toValue = 2.0 * π + clockwiseAnim.duration = duration + clockwiseAnim.repeatCount = Float.infinity + + let counterClockwiseAnim = CABasicAnimation(keyPath: "transform.rotation") + counterClockwiseAnim.fromValue = 2.0 * π + counterClockwiseAnim.toValue = 0.0 + counterClockwiseAnim.duration = duration + counterClockwiseAnim.repeatCount = Float.infinity + + _logoInnerRingImageView.layer.addAnimation(clockwiseAnim, forKey: "") + _logoOuterRingImageView.layer.addAnimation(counterClockwiseAnim, forKey: "") + } + + func stopAnimating() + { + _logoInnerRingImageView.layer.removeAllAnimations() + _logoOuterRingImageView.layer.removeAllAnimations() + } +}