├── LayerX
├── Assets.xcassets
│ ├── Contents.json
│ ├── lock.imageset
│ │ ├── lock.png
│ │ ├── Lock-16.png
│ │ ├── lock-32.png
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ ├── appIcon-1.png
│ │ ├── appIcon-2.png
│ │ ├── appIcon.png
│ │ ├── appIcon-128.png
│ │ ├── appIcon-16.png
│ │ ├── appIcon-256.png
│ │ ├── appIcon-257.png
│ │ ├── appIcon-32.png
│ │ ├── appIcon-34.png
│ │ ├── appIcon-64.png
│ │ └── Contents.json
├── Info.plist
├── MCWindow.swift
├── MCDragAndDropImageView.swift
├── ViewController.swift
├── AppDelegate.swift
└── Base.lproj
│ └── Main.storyboard
├── LayerX.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcuserdata
│ └── yuhua.xcuserdatad
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── LayerX.xcscheme
└── project.pbxproj
├── .gitignore
└── README.md
/LayerX/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/LayerX/Assets.xcassets/lock.imageset/lock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuhua-chen/LayerX/HEAD/LayerX/Assets.xcassets/lock.imageset/lock.png
--------------------------------------------------------------------------------
/LayerX/Assets.xcassets/lock.imageset/Lock-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuhua-chen/LayerX/HEAD/LayerX/Assets.xcassets/lock.imageset/Lock-16.png
--------------------------------------------------------------------------------
/LayerX/Assets.xcassets/lock.imageset/lock-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuhua-chen/LayerX/HEAD/LayerX/Assets.xcassets/lock.imageset/lock-32.png
--------------------------------------------------------------------------------
/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuhua-chen/LayerX/HEAD/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-1.png
--------------------------------------------------------------------------------
/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuhua-chen/LayerX/HEAD/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-2.png
--------------------------------------------------------------------------------
/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuhua-chen/LayerX/HEAD/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon.png
--------------------------------------------------------------------------------
/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuhua-chen/LayerX/HEAD/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-128.png
--------------------------------------------------------------------------------
/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuhua-chen/LayerX/HEAD/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-16.png
--------------------------------------------------------------------------------
/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuhua-chen/LayerX/HEAD/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-256.png
--------------------------------------------------------------------------------
/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-257.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuhua-chen/LayerX/HEAD/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-257.png
--------------------------------------------------------------------------------
/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuhua-chen/LayerX/HEAD/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-32.png
--------------------------------------------------------------------------------
/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-34.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuhua-chen/LayerX/HEAD/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-34.png
--------------------------------------------------------------------------------
/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yuhua-chen/LayerX/HEAD/LayerX/Assets.xcassets/AppIcon.appiconset/appIcon-64.png
--------------------------------------------------------------------------------
/LayerX.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LayerX/Assets.xcassets/lock.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "Lock-16.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "lock-32.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "lock.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/LayerX.xcodeproj/xcuserdata/yuhua.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | LayerX.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 8C09F9F01BDE2E5C00DD457E
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io/api/xcode,osx
2 |
3 | ### Xcode ###
4 | # Xcode
5 | #
6 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
7 |
8 | ## Build generated
9 | build/
10 | DerivedData
11 |
12 | ## Various settings
13 | *.pbxuser
14 | !default.pbxuser
15 | *.mode1v3
16 | !default.mode1v3
17 | *.mode2v3
18 | !default.mode2v3
19 | *.perspectivev3
20 | !default.perspectivev3
21 | xcuserdata
22 |
23 | ## Other
24 | *.xccheckout
25 | *.moved-aside
26 | *.xcuserstate
27 |
28 |
29 | ### OSX ###
30 | .DS_Store
31 | .AppleDouble
32 | .LSOverride
33 |
34 | # Icon must end with two \r
35 | Icon
36 |
37 |
38 | # Thumbnails
39 | ._*
40 |
41 | # Files that might appear in the root of a volume
42 | .DocumentRevisions-V100
43 | .fseventsd
44 | .Spotlight-V100
45 | .TemporaryItems
46 | .Trashes
47 | .VolumeIcon.icns
48 |
49 | # Directories potentially created on remote AFP share
50 | .AppleDB
51 | .AppleDesktop
52 | Network Trash Folder
53 | Temporary Items
54 | .apdisk
55 |
56 |
--------------------------------------------------------------------------------
/LayerX/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.2.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSMinimumSystemVersion
26 | $(MACOSX_DEPLOYMENT_TARGET)
27 | NSHumanReadableCopyright
28 | Copyright © 2015年 Michael Chen. All rights reserved.
29 | NSMainStoryboardFile
30 | Main
31 | NSPrincipalClass
32 | NSApplication
33 |
34 |
35 |
--------------------------------------------------------------------------------
/LayerX/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "16x16",
5 | "idiom" : "mac",
6 | "filename" : "appIcon-16.png",
7 | "scale" : "1x"
8 | },
9 | {
10 | "size" : "16x16",
11 | "idiom" : "mac",
12 | "filename" : "appIcon-32.png",
13 | "scale" : "2x"
14 | },
15 | {
16 | "size" : "32x32",
17 | "idiom" : "mac",
18 | "filename" : "appIcon-34.png",
19 | "scale" : "1x"
20 | },
21 | {
22 | "size" : "32x32",
23 | "idiom" : "mac",
24 | "filename" : "appIcon-64.png",
25 | "scale" : "2x"
26 | },
27 | {
28 | "size" : "128x128",
29 | "idiom" : "mac",
30 | "filename" : "appIcon-128.png",
31 | "scale" : "1x"
32 | },
33 | {
34 | "size" : "128x128",
35 | "idiom" : "mac",
36 | "filename" : "appIcon-257.png",
37 | "scale" : "2x"
38 | },
39 | {
40 | "size" : "256x256",
41 | "idiom" : "mac",
42 | "filename" : "appIcon-256.png",
43 | "scale" : "1x"
44 | },
45 | {
46 | "size" : "256x256",
47 | "idiom" : "mac",
48 | "filename" : "appIcon.png",
49 | "scale" : "2x"
50 | },
51 | {
52 | "size" : "512x512",
53 | "idiom" : "mac",
54 | "filename" : "appIcon-1.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "512x512",
59 | "idiom" : "mac",
60 | "filename" : "appIcon-2.png",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
--------------------------------------------------------------------------------
/LayerX/MCWindow.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MCWindow.swift
3 | // LayerX
4 | //
5 | // Created by Michael Chen on 2015/10/27.
6 | // Copyright © 2015年 Michael Chen. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class MCWIndow: NSWindow {
12 | override func awakeFromNib() {
13 | styleMask = [.borderless, .resizable]
14 | isOpaque = false
15 | backgroundColor = NSColor.clear
16 | isMovableByWindowBackground = true
17 | hasShadow = false
18 | }
19 |
20 | func moveBy(_ offset: CGPoint) {
21 | var frame = self.frame
22 | frame.origin.x += offset.x
23 | frame.origin.y += offset.y
24 |
25 | setFrame(frame, display: true)
26 | }
27 |
28 | func fitsWithSize(_ size: NSSize) {
29 | var frame = self.frame
30 | if frame.size.width < size.width || frame.size.height < size.height {
31 | frame.size = size
32 | setFrame(frame, display: true)
33 | }
34 | }
35 |
36 | func resizeTo(_ size: NSSize, animated: Bool) {
37 | var frame = self.frame
38 | frame.size = size
39 |
40 | if !animated {
41 | setFrame(frame, display: true)
42 | return
43 | }
44 |
45 | let resizeAnimation = [NSViewAnimation.Key.target: self, NSViewAnimation.Key.endFrame: NSValue(rect: frame)]
46 | let animations = NSViewAnimation(viewAnimations: [resizeAnimation])
47 | animations.animationBlockingMode = .blocking
48 | animations.animationCurve = .easeInOut
49 | animations.duration = 0.15
50 | animations.start()
51 | }
52 |
53 | override func constrainFrameRect(_ frameRect: NSRect, to screen: NSScreen?) -> NSRect {
54 | return frameRect
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LayerX
2 |
3 | An intuitive app to display transparent images on screen.
4 |
5 | [](http://www.youtube.com/watch?v=35KixjZBDjY)
6 |
7 | # System requirements
8 |
9 | Support Mac OS X 10.10 or later.
10 |
11 | # Features
12 |
13 | - [x] Drag and drop images
14 | - [x] Keyboard Shortcuts
15 | - [x] Adjust transparency
16 | - [x] Lock images
17 | - [X] Aspect ratio scaling
18 |
19 | # Keyboard Shortcuts
20 |
21 | ### Set image
22 |
23 | | Key | Action |
24 | |:--- |:--- |
25 | |`⌘ V`| Paste image or file from clipboard. |
26 |
27 | ### Scale
28 |
29 | | Key | Action |
30 | |:---|:---|
31 | |`⌘ 0`| Actual image size.|
32 | |`⌘ +`| Scale up 10%.|
33 | |`⌘ -`| Scale down 10%.|
34 | |`^ ⌘ +`| Scale up 1px.|
35 | |`^ ⌘ -`| Scale down 1px.|
36 |
37 | ### Move (Arrow keys)
38 |
39 | | Key | Action |
40 | |:---|:---|
41 | |`↑`| Move up 1px.|
42 | |`←`| Move left 1px.|
43 | |`→`| Move right 1px.|
44 | |`↓`| Move down 1px.|
45 |
46 | ### Alpha
47 |
48 | |Key|Action|
49 | |:---|:---|
50 | |`⌘ J`| Increase transparency.|
51 | |`⌘ K`| Reduce transparency.|
52 |
53 | ### Window
54 |
55 | |Key|Action|
56 | |:---|:---|
57 | |`⌘ L`| Lock images and make window always on top.|
58 | |`⌘ T`| Make window always on top.|
59 | |`⌘ A`| Keep window on all spaces.|
60 |
61 | # Mouse events
62 |
63 | | Event | Action |
64 | |:---|:---|
65 | | Scroll up on image | Reduce transparency. |
66 | | Scroll down on image | Increase transparency. |
67 |
68 | # Contact
69 |
70 | Any suggestions are welcome. Find me at [@yuhua_twit](https://twitter.com/yuhua_twit)
71 |
72 | # License
73 |
74 | Copyright (c) 2017 Michael Chen (a.k.a. Yuhua Chen)
75 |
76 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
77 |
78 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
79 |
80 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
81 |
--------------------------------------------------------------------------------
/LayerX/MCDragAndDropImageView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MCDragAndDropImageView.swift
3 | // LayerX
4 | //
5 | // Created by Michael Chen on 2015/10/26.
6 | // Copyright © 2015年 Michael Chen. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | protocol MCDragAndDropImageViewDelegate: class {
12 | func dragAndDropImageViewDidDrop(_ imageView: MCDragAndDropImageView)
13 | }
14 |
15 | class MCDragAndDropImageView: NSImageView {
16 |
17 | weak var delegate: MCDragAndDropImageViewDelegate?
18 |
19 | required init?(coder: NSCoder) {
20 | super.init(coder: coder)
21 |
22 | registerForDraggedTypes(NSImage.imageTypes.map(NSPasteboard.PasteboardType.init(rawValue:)))
23 |
24 | wantsLayer = true
25 | }
26 |
27 | override func setNeedsDisplay() {
28 | alphaValue = image == nil ? 1.0 : 0.6
29 | super.setNeedsDisplay()
30 | }
31 |
32 | override func draw(_ dirtyRect: NSRect) {
33 | super.draw(dirtyRect)
34 |
35 | if let _ = image {
36 | layer?.backgroundColor = NSColor.clear.cgColor
37 | return
38 | }
39 |
40 | layer?.backgroundColor = NSColor(white: isHighlighted ? 0.5 : 0.8, alpha: 1.0).cgColor
41 | }
42 |
43 | override var mouseDownCanMoveWindow:Bool {
44 | return true
45 | }
46 | }
47 |
48 | // MARK: - NSDraggingSource
49 |
50 | extension MCDragAndDropImageView: NSDraggingSource {
51 |
52 | override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
53 |
54 | if (NSImage.canInit(with: sender.draggingPasteboard)) {
55 | isHighlighted = true
56 |
57 | setNeedsDisplay()
58 |
59 | let sourceDragMask = sender.draggingSourceOperationMask
60 | let pboard = sender.draggingPasteboard
61 |
62 | if pboard.availableType(from: [.fileURL]) == .fileURL {
63 | if sourceDragMask.rawValue & NSDragOperation.copy.rawValue != 0 {
64 | return NSDragOperation.copy
65 | }
66 | }
67 | }
68 |
69 | return NSDragOperation()
70 | }
71 |
72 | override func draggingExited(_ sender: NSDraggingInfo?) {
73 | isHighlighted = false
74 | setNeedsDisplay()
75 | }
76 |
77 | override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
78 | isHighlighted = false
79 | setNeedsDisplay()
80 |
81 | return NSImage.canInit(with: sender.draggingPasteboard)
82 | }
83 |
84 | override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
85 | if (NSImage.canInit(with: sender.draggingPasteboard)) {
86 | image = NSImage(pasteboard: sender.draggingPasteboard)
87 | delegate?.dragAndDropImageViewDidDrop(self)
88 | setNeedsDisplay()
89 | }
90 |
91 | return true
92 | }
93 |
94 | func draggingSession(_ session: NSDraggingSession, sourceOperationMaskFor context: NSDraggingContext) -> NSDragOperation {
95 | switch context {
96 | case .outsideApplication: return NSDragOperation()
97 | case .withinApplication: return .copy
98 | @unknown default: return NSDragOperation()
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/LayerX/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // LayerX
4 | //
5 | // Created by Michael Chen on 2015/10/26.
6 | // Copyright © 2015年 Michael Chen. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | class ViewController: NSViewController {
12 |
13 | @IBOutlet weak var imageView: MCDragAndDropImageView!
14 | @IBOutlet weak var sizeTextField: NSTextField!
15 | @IBOutlet weak var placeholderTextField: NSTextField!
16 | @IBOutlet weak var lockIconImageView: NSImageView!
17 |
18 | override var acceptsFirstResponder: Bool {
19 | return true
20 | }
21 |
22 | lazy var trackingArea: NSTrackingArea = {
23 | let options: NSTrackingArea.Options = [.activeAlways, .mouseEnteredAndExited]
24 | return NSTrackingArea(rect: self.view.bounds, options: options, owner: self, userInfo: nil)
25 | }()
26 |
27 | deinit {
28 | NotificationCenter.default.removeObserver(self)
29 | }
30 |
31 | required init?(coder: NSCoder) {
32 | super.init(coder: coder)
33 | appDelegate().viewController = self
34 | }
35 |
36 | override func viewDidLoad() {
37 | super.viewDidLoad()
38 |
39 | imageView.delegate = self
40 |
41 | sizeTextField.layer?.cornerRadius = 3
42 | sizeTextField.layer?.masksToBounds = true
43 |
44 | lockIconImageView.wantsLayer = true
45 | lockIconImageView.layer?.backgroundColor = NSColor(white: 0.0, alpha: 0.5).cgColor
46 | lockIconImageView.layer?.cornerRadius = 5
47 | lockIconImageView.layer?.masksToBounds = true
48 |
49 | NotificationCenter.default.addObserver(self, selector: #selector(windowDidResize(_:)), name: NSWindow.didResizeNotification, object: appDelegate().window)
50 |
51 | view.addTrackingArea(trackingArea)
52 | }
53 |
54 | @objc func fadeOutSizeTextField() {
55 | let transition = CATransition()
56 | sizeTextField.layer?.add(transition, forKey: "fadeOut")
57 | sizeTextField.layer?.opacity = 0
58 | }
59 |
60 | @objc func windowDidResize(_ notification: Notification) {
61 | let window = notification.object as! NSWindow
62 | let size = window.frame.size
63 | sizeTextField.stringValue = "\(Int(size.width))x\(Int(size.height))"
64 | sizeTextField.layer?.opacity = 1
65 |
66 | NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(ViewController.fadeOutSizeTextField), object: nil)
67 | perform(#selector(ViewController.fadeOutSizeTextField), with: nil, afterDelay: 2)
68 | }
69 |
70 | // MARK: Mouse events
71 |
72 | override func scrollWheel(with theEvent: NSEvent) {
73 | guard let _ = imageView.image else { return }
74 |
75 | let delta = theEvent.deltaY * 0.005;
76 | var alpha = imageView.alphaValue - delta
77 | alpha = min(alpha, 1)
78 | alpha = max(alpha, 0.05)
79 | imageView.alphaValue = alpha
80 | }
81 |
82 | override func mouseEntered(with theEvent: NSEvent) {
83 | sizeTextField.layer?.opacity = 1
84 | }
85 |
86 | override func mouseExited(with theEvent: NSEvent) {
87 | fadeOutSizeTextField()
88 | }
89 | }
90 |
91 | // MARK: - MCDragAndDropImageViewDelegate
92 |
93 | extension ViewController: MCDragAndDropImageViewDelegate {
94 | func dragAndDropImageViewDidDrop(_ imageView: MCDragAndDropImageView) {
95 |
96 | sizeTextField.isHidden = false
97 | placeholderTextField.isHidden = true
98 |
99 | appDelegate().actualSize(nil)
100 | }
101 | }
102 |
103 | // MARK: - Movable NSView
104 |
105 | class MCMovableView: NSView{
106 | override var mouseDownCanMoveWindow:Bool {
107 | return true
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/LayerX.xcodeproj/xcuserdata/yuhua.xcuserdatad/xcschemes/LayerX.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/LayerX/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // LayerX
4 | //
5 | // Created by Michael Chen on 2015/10/26.
6 | // Copyright © 2015年 Michael Chen. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | @NSApplicationMain
12 | class AppDelegate: NSObject, NSApplicationDelegate {
13 |
14 | private let defaultSize = NSMakeSize(480, 320)
15 | private let resizeStep: CGFloat = 0.1
16 |
17 | var allSpaces = false
18 | var locked = false
19 | var onTop = false
20 |
21 | weak var window: MCWIndow!
22 | weak var viewController: ViewController!
23 | var isLockIconHiddenWhileLocked = false {
24 | didSet { viewController.lockIconImageView.isHidden = window.isMovable || isLockIconHiddenWhileLocked }
25 | }
26 | var isSizeHidden = false {
27 | didSet { viewController.sizeTextField.isHidden = isSizeHidden }
28 | }
29 |
30 | func applicationDidFinishLaunching(_ aNotification: Notification) {
31 | if let window = NSApp.windows.first as? MCWIndow {
32 | window.fitsWithSize(defaultSize)
33 | window.collectionBehavior = [.managed, .moveToActiveSpace]
34 | self.window = window
35 | }
36 | }
37 | }
38 |
39 | fileprivate enum ArrowTag: Int {
40 | case up = 20
41 | case left = 21
42 | case right = 22
43 | case down = 23
44 | }
45 |
46 | // MARK: - Hotkeys
47 |
48 | extension AppDelegate {
49 |
50 | private var originalSize: NSSize {
51 | viewController.imageView.image?.size ?? defaultSize
52 | }
53 |
54 | private func resizeAspectFit(calculator: (_ original: CGFloat, _ current: CGFloat) -> CGFloat) {
55 | let originalSize = self.originalSize
56 | let width = calculator(originalSize.width, window.frame.size.width)
57 | let height = width / originalSize.width * originalSize.height
58 |
59 | if width > 0 {
60 | window.resizeTo(NSSize(width: width, height: height), animated: true)
61 | }
62 | }
63 |
64 | @IBAction func actualSize(_ sender: AnyObject?) {
65 | window.resizeTo(originalSize, animated: true)
66 | }
67 |
68 | @IBAction func makeLarger(_ sender: AnyObject) {
69 | resizeAspectFit { $0 * ($1 / $0 + resizeStep) }
70 | }
71 |
72 | @IBAction func makeSmaller(_ sender: AnyObject) {
73 | resizeAspectFit { $0 * ($1 / $0 - resizeStep) }
74 | }
75 |
76 | @IBAction func makeLargerOnePixel(_ sender: AnyObject) {
77 | resizeAspectFit { $1 + 1 }
78 | }
79 |
80 | @IBAction func makeSmallerOnePixel(_ sender: AnyObject) {
81 | resizeAspectFit { $1 - 1 }
82 | }
83 |
84 | @IBAction func increaseTransparency(_ sender: AnyObject) {
85 | var alpha = viewController.imageView.alphaValue
86 | alpha -= 0.1
87 | viewController.imageView.alphaValue = max(alpha, 0.05)
88 | }
89 |
90 | @IBAction func reduceTransparency(_ sender: AnyObject) {
91 | var alpha = viewController.imageView.alphaValue
92 | alpha += 0.1
93 | viewController.imageView.alphaValue = min(alpha, 1.0)
94 | }
95 |
96 | func getPasteboardImage() -> NSImage? {
97 | let pasteboard = NSPasteboard.general;
98 | if let file = pasteboard.data(forType: NSPasteboard.PasteboardType.fileURL),
99 | let str = String(data: file, encoding: .utf8),
100 | let url = URL(string: str)
101 | {
102 | return NSImage(contentsOf: url)
103 | }
104 |
105 | if let tiff = pasteboard.data(forType: NSPasteboard.PasteboardType.tiff) {
106 | return NSImage(data: tiff)
107 | }
108 |
109 | if let png = pasteboard.data(forType: NSPasteboard.PasteboardType.png) {
110 | return NSImage(data: png)
111 | }
112 |
113 | return nil
114 | }
115 |
116 | @IBAction func paste(_ sender: AnyObject) {
117 | guard let image = getPasteboardImage() else { return }
118 | let rep = image.representations[0]
119 | viewController.imageView.image = image
120 | let size = NSMakeSize(CGFloat(rep.pixelsWide), CGFloat(rep.pixelsHigh))
121 | window.resizeTo(size, animated: true)
122 | viewController.sizeTextField.isHidden = false
123 | viewController.placeholderTextField.isHidden = true
124 |
125 | }
126 |
127 | @IBAction func toggleLockWindow(_ sender: AnyObject) {
128 | let menuItem = sender as! NSMenuItem
129 | locked = !locked
130 | onTop = locked
131 | if locked {
132 | menuItem.title = "Unlock"
133 | window.isMovable = false
134 | window.ignoresMouseEvents = true
135 | window.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.maximumWindow)))
136 | } else {
137 | menuItem.title = "Lock"
138 | window.isMovable = true
139 | window.ignoresMouseEvents = false
140 | window.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.normalWindow)))
141 | }
142 |
143 | viewController.lockIconImageView.isHidden = window.isMovable || isLockIconHiddenWhileLocked
144 | }
145 |
146 | @IBAction func toggleOnTop(_ sender: AnyObject) {
147 | let menuItem = sender as! NSMenuItem
148 | onTop = !onTop
149 | if onTop {
150 | menuItem.title = "Don't keep on top"
151 | window.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.maximumWindow)))
152 | } else if !locked {
153 | menuItem.title = "Keep on top"
154 | window.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.normalWindow)))
155 | }
156 | }
157 |
158 | @IBAction func toggleLockIconVisibility(_ sender: AnyObject) {
159 | let menuItem = sender as! NSMenuItem
160 | menuItem.state = menuItem.state == .on ? .off : .on
161 | isLockIconHiddenWhileLocked = menuItem.state == .on
162 | }
163 |
164 | @IBAction func toggleSizeVisibility(_ sender: AnyObject) {
165 | let menuItem = sender as! NSMenuItem
166 | menuItem.state = menuItem.state == .on ? .off : .on
167 | isSizeHidden = menuItem.state == .on
168 | }
169 |
170 | @IBAction func moveAround(_ sender: AnyObject) {
171 | let menuItem = sender as! NSMenuItem
172 |
173 | guard let arrow = ArrowTag(rawValue: menuItem.tag) else {
174 | return
175 | }
176 |
177 | switch arrow {
178 | case .up:
179 | window.moveBy(CGPoint(x: 0, y: 1))
180 | case .left:
181 | window.moveBy(CGPoint(x: -1, y: 0))
182 | case .right:
183 | window.moveBy(CGPoint(x: 1, y: 0))
184 | case .down:
185 | window.moveBy(CGPoint(x: 0, y: -1))
186 | }
187 | }
188 |
189 | @IBAction func toggleAllSpaces(_ sender: AnyObject) {
190 | let menuItem = sender as! NSMenuItem
191 | allSpaces = !allSpaces
192 | if allSpaces {
193 | menuItem.title = "Keep on this space"
194 | window.collectionBehavior = [.canJoinAllSpaces]
195 | } else {
196 | menuItem.title = "Keep on all spaces"
197 | window.collectionBehavior = [.managed, .moveToActiveSpace]
198 | }
199 | }
200 |
201 | func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
202 | return viewController.imageView.image != nil
203 | }
204 | }
205 |
206 | // MARK: - Helper
207 |
208 | func appDelegate() -> AppDelegate {
209 | return NSApp.delegate as! AppDelegate
210 | }
211 |
--------------------------------------------------------------------------------
/LayerX.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 8C09F9F51BDE2E5C00DD457E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C09F9F41BDE2E5C00DD457E /* AppDelegate.swift */; };
11 | 8C09F9F71BDE2E5C00DD457E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C09F9F61BDE2E5C00DD457E /* ViewController.swift */; };
12 | 8C09F9F91BDE2E5C00DD457E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8C09F9F81BDE2E5C00DD457E /* Assets.xcassets */; };
13 | 8C09F9FC1BDE2E5C00DD457E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8C09F9FA1BDE2E5C00DD457E /* Main.storyboard */; };
14 | 8C09FA041BDE324500DD457E /* MCDragAndDropImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C09FA031BDE324500DD457E /* MCDragAndDropImageView.swift */; };
15 | 8C09FA0C1BDF5F7300DD457E /* MCWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C09FA0B1BDF5F7300DD457E /* MCWindow.swift */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXFileReference section */
19 | 8C09F9F11BDE2E5C00DD457E /* LayerX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LayerX.app; sourceTree = BUILT_PRODUCTS_DIR; };
20 | 8C09F9F41BDE2E5C00DD457E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
21 | 8C09F9F61BDE2E5C00DD457E /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
22 | 8C09F9F81BDE2E5C00DD457E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
23 | 8C09F9FB1BDE2E5C00DD457E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
24 | 8C09F9FD1BDE2E5C00DD457E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
25 | 8C09FA031BDE324500DD457E /* MCDragAndDropImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MCDragAndDropImageView.swift; sourceTree = ""; };
26 | 8C09FA0B1BDF5F7300DD457E /* MCWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MCWindow.swift; sourceTree = ""; };
27 | /* End PBXFileReference section */
28 |
29 | /* Begin PBXFrameworksBuildPhase section */
30 | 8C09F9EE1BDE2E5C00DD457E /* Frameworks */ = {
31 | isa = PBXFrameworksBuildPhase;
32 | buildActionMask = 2147483647;
33 | files = (
34 | );
35 | runOnlyForDeploymentPostprocessing = 0;
36 | };
37 | /* End PBXFrameworksBuildPhase section */
38 |
39 | /* Begin PBXGroup section */
40 | 8C09F9E81BDE2E5C00DD457E = {
41 | isa = PBXGroup;
42 | children = (
43 | 8C09F9F31BDE2E5C00DD457E /* LayerX */,
44 | 8C09F9F21BDE2E5C00DD457E /* Products */,
45 | );
46 | sourceTree = "";
47 | };
48 | 8C09F9F21BDE2E5C00DD457E /* Products */ = {
49 | isa = PBXGroup;
50 | children = (
51 | 8C09F9F11BDE2E5C00DD457E /* LayerX.app */,
52 | );
53 | name = Products;
54 | sourceTree = "";
55 | };
56 | 8C09F9F31BDE2E5C00DD457E /* LayerX */ = {
57 | isa = PBXGroup;
58 | children = (
59 | 8C09F9F41BDE2E5C00DD457E /* AppDelegate.swift */,
60 | 8C09FA0B1BDF5F7300DD457E /* MCWindow.swift */,
61 | 8C09F9F61BDE2E5C00DD457E /* ViewController.swift */,
62 | 8C09FA031BDE324500DD457E /* MCDragAndDropImageView.swift */,
63 | 8C09F9F81BDE2E5C00DD457E /* Assets.xcassets */,
64 | 8C09F9FA1BDE2E5C00DD457E /* Main.storyboard */,
65 | 8C09F9FD1BDE2E5C00DD457E /* Info.plist */,
66 | );
67 | path = LayerX;
68 | sourceTree = "";
69 | };
70 | /* End PBXGroup section */
71 |
72 | /* Begin PBXNativeTarget section */
73 | 8C09F9F01BDE2E5C00DD457E /* LayerX */ = {
74 | isa = PBXNativeTarget;
75 | buildConfigurationList = 8C09FA001BDE2E5C00DD457E /* Build configuration list for PBXNativeTarget "LayerX" */;
76 | buildPhases = (
77 | 8C09F9ED1BDE2E5C00DD457E /* Sources */,
78 | 8C09F9EE1BDE2E5C00DD457E /* Frameworks */,
79 | 8C09F9EF1BDE2E5C00DD457E /* Resources */,
80 | );
81 | buildRules = (
82 | );
83 | dependencies = (
84 | );
85 | name = LayerX;
86 | productName = LayerX;
87 | productReference = 8C09F9F11BDE2E5C00DD457E /* LayerX.app */;
88 | productType = "com.apple.product-type.application";
89 | };
90 | /* End PBXNativeTarget section */
91 |
92 | /* Begin PBXProject section */
93 | 8C09F9E91BDE2E5C00DD457E /* Project object */ = {
94 | isa = PBXProject;
95 | attributes = {
96 | LastUpgradeCheck = 0700;
97 | ORGANIZATIONNAME = "Michael Chen";
98 | TargetAttributes = {
99 | 8C09F9F01BDE2E5C00DD457E = {
100 | CreatedOnToolsVersion = 7.0;
101 | LastSwiftMigration = 0800;
102 | };
103 | };
104 | };
105 | buildConfigurationList = 8C09F9EC1BDE2E5C00DD457E /* Build configuration list for PBXProject "LayerX" */;
106 | compatibilityVersion = "Xcode 3.2";
107 | developmentRegion = English;
108 | hasScannedForEncodings = 0;
109 | knownRegions = (
110 | English,
111 | en,
112 | Base,
113 | );
114 | mainGroup = 8C09F9E81BDE2E5C00DD457E;
115 | productRefGroup = 8C09F9F21BDE2E5C00DD457E /* Products */;
116 | projectDirPath = "";
117 | projectRoot = "";
118 | targets = (
119 | 8C09F9F01BDE2E5C00DD457E /* LayerX */,
120 | );
121 | };
122 | /* End PBXProject section */
123 |
124 | /* Begin PBXResourcesBuildPhase section */
125 | 8C09F9EF1BDE2E5C00DD457E /* Resources */ = {
126 | isa = PBXResourcesBuildPhase;
127 | buildActionMask = 2147483647;
128 | files = (
129 | 8C09F9F91BDE2E5C00DD457E /* Assets.xcassets in Resources */,
130 | 8C09F9FC1BDE2E5C00DD457E /* Main.storyboard in Resources */,
131 | );
132 | runOnlyForDeploymentPostprocessing = 0;
133 | };
134 | /* End PBXResourcesBuildPhase section */
135 |
136 | /* Begin PBXSourcesBuildPhase section */
137 | 8C09F9ED1BDE2E5C00DD457E /* Sources */ = {
138 | isa = PBXSourcesBuildPhase;
139 | buildActionMask = 2147483647;
140 | files = (
141 | 8C09F9F71BDE2E5C00DD457E /* ViewController.swift in Sources */,
142 | 8C09FA0C1BDF5F7300DD457E /* MCWindow.swift in Sources */,
143 | 8C09F9F51BDE2E5C00DD457E /* AppDelegate.swift in Sources */,
144 | 8C09FA041BDE324500DD457E /* MCDragAndDropImageView.swift in Sources */,
145 | );
146 | runOnlyForDeploymentPostprocessing = 0;
147 | };
148 | /* End PBXSourcesBuildPhase section */
149 |
150 | /* Begin PBXVariantGroup section */
151 | 8C09F9FA1BDE2E5C00DD457E /* Main.storyboard */ = {
152 | isa = PBXVariantGroup;
153 | children = (
154 | 8C09F9FB1BDE2E5C00DD457E /* Base */,
155 | );
156 | name = Main.storyboard;
157 | sourceTree = "";
158 | };
159 | /* End PBXVariantGroup section */
160 |
161 | /* Begin XCBuildConfiguration section */
162 | 8C09F9FE1BDE2E5C00DD457E /* Debug */ = {
163 | isa = XCBuildConfiguration;
164 | buildSettings = {
165 | ALWAYS_SEARCH_USER_PATHS = NO;
166 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
167 | CLANG_CXX_LIBRARY = "libc++";
168 | CLANG_ENABLE_MODULES = YES;
169 | CLANG_ENABLE_OBJC_ARC = YES;
170 | CLANG_WARN_BOOL_CONVERSION = YES;
171 | CLANG_WARN_CONSTANT_CONVERSION = YES;
172 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
173 | CLANG_WARN_EMPTY_BODY = YES;
174 | CLANG_WARN_ENUM_CONVERSION = YES;
175 | CLANG_WARN_INT_CONVERSION = YES;
176 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
177 | CLANG_WARN_UNREACHABLE_CODE = YES;
178 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
179 | CODE_SIGN_IDENTITY = "-";
180 | COPY_PHASE_STRIP = NO;
181 | DEBUG_INFORMATION_FORMAT = dwarf;
182 | ENABLE_STRICT_OBJC_MSGSEND = YES;
183 | ENABLE_TESTABILITY = YES;
184 | GCC_C_LANGUAGE_STANDARD = gnu99;
185 | GCC_DYNAMIC_NO_PIC = NO;
186 | GCC_NO_COMMON_BLOCKS = YES;
187 | GCC_OPTIMIZATION_LEVEL = 0;
188 | GCC_PREPROCESSOR_DEFINITIONS = (
189 | "DEBUG=1",
190 | "$(inherited)",
191 | );
192 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
193 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
194 | GCC_WARN_UNDECLARED_SELECTOR = YES;
195 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
196 | GCC_WARN_UNUSED_FUNCTION = YES;
197 | GCC_WARN_UNUSED_VARIABLE = YES;
198 | MACOSX_DEPLOYMENT_TARGET = 10.13;
199 | MTL_ENABLE_DEBUG_INFO = YES;
200 | ONLY_ACTIVE_ARCH = YES;
201 | SDKROOT = macosx;
202 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
203 | SWIFT_VERSION = 5.0;
204 | };
205 | name = Debug;
206 | };
207 | 8C09F9FF1BDE2E5C00DD457E /* Release */ = {
208 | isa = XCBuildConfiguration;
209 | buildSettings = {
210 | ALWAYS_SEARCH_USER_PATHS = NO;
211 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
212 | CLANG_CXX_LIBRARY = "libc++";
213 | CLANG_ENABLE_MODULES = YES;
214 | CLANG_ENABLE_OBJC_ARC = YES;
215 | CLANG_WARN_BOOL_CONVERSION = YES;
216 | CLANG_WARN_CONSTANT_CONVERSION = YES;
217 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
218 | CLANG_WARN_EMPTY_BODY = YES;
219 | CLANG_WARN_ENUM_CONVERSION = YES;
220 | CLANG_WARN_INT_CONVERSION = YES;
221 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
222 | CLANG_WARN_UNREACHABLE_CODE = YES;
223 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
224 | CODE_SIGN_IDENTITY = "-";
225 | COPY_PHASE_STRIP = NO;
226 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
227 | ENABLE_NS_ASSERTIONS = NO;
228 | ENABLE_STRICT_OBJC_MSGSEND = YES;
229 | GCC_C_LANGUAGE_STANDARD = gnu99;
230 | GCC_NO_COMMON_BLOCKS = YES;
231 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
232 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
233 | GCC_WARN_UNDECLARED_SELECTOR = YES;
234 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
235 | GCC_WARN_UNUSED_FUNCTION = YES;
236 | GCC_WARN_UNUSED_VARIABLE = YES;
237 | MACOSX_DEPLOYMENT_TARGET = 10.13;
238 | MTL_ENABLE_DEBUG_INFO = NO;
239 | SDKROOT = macosx;
240 | SWIFT_VERSION = 5.0;
241 | };
242 | name = Release;
243 | };
244 | 8C09FA011BDE2E5C00DD457E /* Debug */ = {
245 | isa = XCBuildConfiguration;
246 | buildSettings = {
247 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
248 | COMBINE_HIDPI_IMAGES = YES;
249 | INFOPLIST_FILE = LayerX/Info.plist;
250 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
251 | PRODUCT_BUNDLE_IDENTIFIER = io.michaelchen.LayerX;
252 | PRODUCT_NAME = "$(TARGET_NAME)";
253 | };
254 | name = Debug;
255 | };
256 | 8C09FA021BDE2E5C00DD457E /* Release */ = {
257 | isa = XCBuildConfiguration;
258 | buildSettings = {
259 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
260 | COMBINE_HIDPI_IMAGES = YES;
261 | INFOPLIST_FILE = LayerX/Info.plist;
262 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
263 | PRODUCT_BUNDLE_IDENTIFIER = io.michaelchen.LayerX;
264 | PRODUCT_NAME = "$(TARGET_NAME)";
265 | };
266 | name = Release;
267 | };
268 | /* End XCBuildConfiguration section */
269 |
270 | /* Begin XCConfigurationList section */
271 | 8C09F9EC1BDE2E5C00DD457E /* Build configuration list for PBXProject "LayerX" */ = {
272 | isa = XCConfigurationList;
273 | buildConfigurations = (
274 | 8C09F9FE1BDE2E5C00DD457E /* Debug */,
275 | 8C09F9FF1BDE2E5C00DD457E /* Release */,
276 | );
277 | defaultConfigurationIsVisible = 0;
278 | defaultConfigurationName = Release;
279 | };
280 | 8C09FA001BDE2E5C00DD457E /* Build configuration list for PBXNativeTarget "LayerX" */ = {
281 | isa = XCConfigurationList;
282 | buildConfigurations = (
283 | 8C09FA011BDE2E5C00DD457E /* Debug */,
284 | 8C09FA021BDE2E5C00DD457E /* Release */,
285 | );
286 | defaultConfigurationIsVisible = 0;
287 | defaultConfigurationName = Release;
288 | };
289 | /* End XCConfigurationList section */
290 | };
291 | rootObject = 8C09F9E91BDE2E5C00DD457E /* Project object */;
292 | }
293 |
--------------------------------------------------------------------------------
/LayerX/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
--------------------------------------------------------------------------------