Repository: yuhua-chen/LayerX
Branch: master
Commit: b96bfd477e2c
Files: 13
Total size: 56.4 KB
Directory structure:
gitextract_ov5xqwub/
├── .gitignore
├── LayerX/
│ ├── AppDelegate.swift
│ ├── Assets.xcassets/
│ │ ├── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ └── lock.imageset/
│ │ └── Contents.json
│ ├── Base.lproj/
│ │ └── Main.storyboard
│ ├── Info.plist
│ ├── MCDragAndDropImageView.swift
│ ├── MCWindow.swift
│ └── ViewController.swift
├── LayerX.xcodeproj/
│ ├── project.pbxproj
│ └── project.xcworkspace/
│ └── contents.xcworkspacedata
└── README.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Created by https://www.gitignore.io/api/xcode,osx
### Xcode ###
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
## Other
*.xccheckout
*.moved-aside
*.xcuserstate
### OSX ###
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
================================================
FILE: LayerX/AppDelegate.swift
================================================
//
// AppDelegate.swift
// LayerX
//
// Created by Michael Chen on 2015/10/26.
// Copyright © 2015年 Michael Chen. All rights reserved.
//
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
private let defaultSize = NSMakeSize(480, 320)
private let resizeStep: CGFloat = 0.1
var allSpaces = false
var locked = false
var onTop = false
weak var window: MCWIndow!
weak var viewController: ViewController!
var isLockIconHiddenWhileLocked = false {
didSet { viewController.lockIconImageView.isHidden = window.isMovable || isLockIconHiddenWhileLocked }
}
var isSizeHidden = false {
didSet { viewController.sizeTextField.isHidden = isSizeHidden }
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
if let window = NSApp.windows.first as? MCWIndow {
window.fitsWithSize(defaultSize)
window.collectionBehavior = [.managed, .moveToActiveSpace]
self.window = window
}
}
}
fileprivate enum ArrowTag: Int {
case up = 20
case left = 21
case right = 22
case down = 23
}
// MARK: - Hotkeys
extension AppDelegate {
private var originalSize: NSSize {
viewController.imageView.image?.size ?? defaultSize
}
private func resizeAspectFit(calculator: (_ original: CGFloat, _ current: CGFloat) -> CGFloat) {
let originalSize = self.originalSize
let width = calculator(originalSize.width, window.frame.size.width)
let height = width / originalSize.width * originalSize.height
if width > 0 {
window.resizeTo(NSSize(width: width, height: height), animated: true)
}
}
@IBAction func actualSize(_ sender: AnyObject?) {
window.resizeTo(originalSize, animated: true)
}
@IBAction func makeLarger(_ sender: AnyObject) {
resizeAspectFit { $0 * ($1 / $0 + resizeStep) }
}
@IBAction func makeSmaller(_ sender: AnyObject) {
resizeAspectFit { $0 * ($1 / $0 - resizeStep) }
}
@IBAction func makeLargerOnePixel(_ sender: AnyObject) {
resizeAspectFit { $1 + 1 }
}
@IBAction func makeSmallerOnePixel(_ sender: AnyObject) {
resizeAspectFit { $1 - 1 }
}
@IBAction func increaseTransparency(_ sender: AnyObject) {
var alpha = viewController.imageView.alphaValue
alpha -= 0.1
viewController.imageView.alphaValue = max(alpha, 0.05)
}
@IBAction func reduceTransparency(_ sender: AnyObject) {
var alpha = viewController.imageView.alphaValue
alpha += 0.1
viewController.imageView.alphaValue = min(alpha, 1.0)
}
func getPasteboardImage() -> NSImage? {
let pasteboard = NSPasteboard.general;
if let file = pasteboard.data(forType: NSPasteboard.PasteboardType.fileURL),
let str = String(data: file, encoding: .utf8),
let url = URL(string: str)
{
return NSImage(contentsOf: url)
}
if let tiff = pasteboard.data(forType: NSPasteboard.PasteboardType.tiff) {
return NSImage(data: tiff)
}
if let png = pasteboard.data(forType: NSPasteboard.PasteboardType.png) {
return NSImage(data: png)
}
return nil
}
@IBAction func paste(_ sender: AnyObject) {
guard let image = getPasteboardImage() else { return }
let rep = image.representations[0]
viewController.imageView.image = image
let size = NSMakeSize(CGFloat(rep.pixelsWide), CGFloat(rep.pixelsHigh))
window.resizeTo(size, animated: true)
viewController.sizeTextField.isHidden = false
viewController.placeholderTextField.isHidden = true
}
@IBAction func toggleLockWindow(_ sender: AnyObject) {
let menuItem = sender as! NSMenuItem
locked = !locked
onTop = locked
if locked {
menuItem.title = "Unlock"
window.isMovable = false
window.ignoresMouseEvents = true
window.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.maximumWindow)))
} else {
menuItem.title = "Lock"
window.isMovable = true
window.ignoresMouseEvents = false
window.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.normalWindow)))
}
viewController.lockIconImageView.isHidden = window.isMovable || isLockIconHiddenWhileLocked
}
@IBAction func toggleOnTop(_ sender: AnyObject) {
let menuItem = sender as! NSMenuItem
onTop = !onTop
if onTop {
menuItem.title = "Don't keep on top"
window.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.maximumWindow)))
} else if !locked {
menuItem.title = "Keep on top"
window.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.normalWindow)))
}
}
@IBAction func toggleLockIconVisibility(_ sender: AnyObject) {
let menuItem = sender as! NSMenuItem
menuItem.state = menuItem.state == .on ? .off : .on
isLockIconHiddenWhileLocked = menuItem.state == .on
}
@IBAction func toggleSizeVisibility(_ sender: AnyObject) {
let menuItem = sender as! NSMenuItem
menuItem.state = menuItem.state == .on ? .off : .on
isSizeHidden = menuItem.state == .on
}
@IBAction func moveAround(_ sender: AnyObject) {
let menuItem = sender as! NSMenuItem
guard let arrow = ArrowTag(rawValue: menuItem.tag) else {
return
}
switch arrow {
case .up:
window.moveBy(CGPoint(x: 0, y: 1))
case .left:
window.moveBy(CGPoint(x: -1, y: 0))
case .right:
window.moveBy(CGPoint(x: 1, y: 0))
case .down:
window.moveBy(CGPoint(x: 0, y: -1))
}
}
@IBAction func toggleAllSpaces(_ sender: AnyObject) {
let menuItem = sender as! NSMenuItem
allSpaces = !allSpaces
if allSpaces {
menuItem.title = "Keep on this space"
window.collectionBehavior = [.canJoinAllSpaces]
} else {
menuItem.title = "Keep on all spaces"
window.collectionBehavior = [.managed, .moveToActiveSpace]
}
}
func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
return viewController.imageView.image != nil
}
}
// MARK: - Helper
func appDelegate() -> AppDelegate {
return NSApp.delegate as! AppDelegate
}
================================================
FILE: LayerX/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "appIcon-16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "appIcon-32.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "appIcon-34.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "appIcon-64.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "appIcon-128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "appIcon-257.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "appIcon-256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "appIcon.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "appIcon-1.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "appIcon-2.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: LayerX/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: LayerX/Assets.xcassets/lock.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "Lock-16.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "lock-32.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "lock.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: LayerX/Base.lproj/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="11201" systemVersion="15F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11201"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
</dependencies>
<scenes>
<!--Application-->
<scene sceneID="JPo-4y-FX3">
<objects>
<application id="hnw-xV-0zn" sceneMemberID="viewController">
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
<items>
<menuItem title="LayerX" id="1Xt-HY-uBw">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="LayerX" systemMenu="apple" id="uQy-DD-JDr">
<items>
<menuItem title="About LayerX" id="5kV-Vb-QxS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
<menuItem title="Hide LayerX" keyEquivalent="h" id="Olw-nP-bQN">
<connections>
<action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
</connections>
</menuItem>
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
</connections>
</menuItem>
<menuItem title="Show All" id="Kd2-mp-pUS">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit LayerX" keyEquivalent="q" id="4sb-4s-VLi">
<connections>
<action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="File" id="dMs-cI-mzQ">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="File" id="bib-Uj-vzu">
<items>
<menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
<connections>
<action selector="newDocument:" target="Ady-hI-5gd" id="4Si-XN-c54"/>
</connections>
</menuItem>
<menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
<connections>
<action selector="openDocument:" target="Ady-hI-5gd" id="bVn-NM-KNZ"/>
</connections>
</menuItem>
<menuItem title="Open Recent" id="tXI-mr-wws">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
<items>
<menuItem title="Clear Menu" id="vNY-rz-j42">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="clearRecentDocuments:" target="Ady-hI-5gd" id="Daa-9d-B3U"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
<connections>
<action selector="performClose:" target="Ady-hI-5gd" id="HmO-Ls-i7Q"/>
</connections>
</menuItem>
<menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
<connections>
<action selector="saveDocument:" target="Ady-hI-5gd" id="teZ-XB-qJY"/>
</connections>
</menuItem>
<menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
<connections>
<action selector="saveDocumentAs:" target="Ady-hI-5gd" id="mDf-zr-I0C"/>
</connections>
</menuItem>
<menuItem title="Revert to Saved" id="KaW-ft-85H">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="revertDocumentToSaved:" target="Ady-hI-5gd" id="iJ3-Pv-kwq"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
<menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="runPageLayout:" target="Ady-hI-5gd" id="Din-rz-gC5"/>
</connections>
</menuItem>
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
<connections>
<action selector="print:" target="Ady-hI-5gd" id="qaZ-4w-aoO"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="dAm-Da-fWl">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Edit" id="aeY-sH-oUd">
<items>
<menuItem title="Paste" keyEquivalent="v" id="Wup-uR-bUt">
<connections>
<action selector="paste:" target="Voe-Tx-rLC" id="mh3-X2-sMC"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="H8h-7b-M4v">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="View" id="HyV-fh-RgO">
<items>
<menuItem title="Actual Size" keyEquivalent="0" id="snW-S8-Cw5">
<connections>
<action selector="actualSize:" target="Voe-Tx-rLC" id="Rr0-Sv-VSe"/>
</connections>
</menuItem>
<menuItem title="Scale Up 10%" keyEquivalent="+" id="Ed8-Vk-OS6">
<connections>
<action selector="makeLarger:" target="Voe-Tx-rLC" id="ldh-JS-1g5"/>
</connections>
</menuItem>
<menuItem title="Scale Down 10%" keyEquivalent="-" id="trE-Hj-Y6i">
<connections>
<action selector="makeSmaller:" target="Voe-Tx-rLC" id="gWX-vc-gSr"/>
</connections>
</menuItem>
<menuItem title="Scale Up 1px" keyEquivalent="=" id="QFF-N1-xBx">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="makeLargerOnePixel:" target="Voe-Tx-rLC" id="a6e-El-RWw"/>
</connections>
</menuItem>
<menuItem title="Scale Down 1px" keyEquivalent="-" id="mKa-lu-KYo">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="makeSmallerOnePixel:" target="Voe-Tx-rLC" id="lBc-iQ-i2i"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="S7H-4j-wWG"/>
<menuItem title="Move up 1px" tag="20" keyEquivalent="" id="xt1-zP-8lE">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="moveAround:" target="Voe-Tx-rLC" id="qks-64-WYp"/>
</connections>
</menuItem>
<menuItem title="Move left 1px" tag="21" keyEquivalent="" id="Ud7-FA-vtA">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="moveAround:" target="Voe-Tx-rLC" id="RxY-3b-ZPJ"/>
</connections>
</menuItem>
<menuItem title="Move right 1px" tag="22" keyEquivalent="" id="SC9-Za-3te">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="moveAround:" target="Voe-Tx-rLC" id="7UQ-dw-xVi"/>
</connections>
</menuItem>
<menuItem title="Move down 1px" tag="23" keyEquivalent="" id="T88-KV-33B">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="moveAround:" target="Voe-Tx-rLC" id="gZw-Fh-AIF"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="Uol-cd-eOj"/>
<menuItem title="Increase Transparency" keyEquivalent="j" id="PLz-nj-Geg">
<connections>
<action selector="increaseTransparency:" target="Voe-Tx-rLC" id="O9E-CS-NRG"/>
</connections>
</menuItem>
<menuItem title="Reduce Transparency" keyEquivalent="k" id="P7g-e7-fyw">
<connections>
<action selector="reduceTransparency:" target="Voe-Tx-rLC" id="6jy-Px-MpF"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="4H8-5J-P5x"/>
<menuItem title="Hide Lock Icon" id="MeZ-fZ-1OL">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleLockIconVisibility:" target="Voe-Tx-rLC" id="RCB-nJ-o0E"/>
</connections>
</menuItem>
<menuItem title="Hide Size" id="JXi-GL-qzz">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleSizeVisibility:" target="Voe-Tx-rLC" id="e8c-Wd-zRh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
<items>
<menuItem title="Lock" keyEquivalent="l" id="OY7-WF-poV">
<connections>
<action selector="toggleLockWindow:" target="Voe-Tx-rLC" id="Mfc-bV-lDx"/>
</connections>
</menuItem>
<menuItem title="Keep on top" keyEquivalent="t" id="WZF-Ql-Ptb">
<connections>
<action selector="toggleOnTop:" target="Voe-Tx-rLC" id="1mS-lL-oZG"/>
</connections>
</menuItem>
<menuItem title="Keep on all spaces" keyEquivalent="a" id="pZ0-jf-Hps">
<connections>
<action selector="toggleAllSpaces:" target="Voe-Tx-rLC" id="N0L-4A-TpV"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="wpr-3q-Mcd">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
<items>
<menuItem title="LayerX Help" keyEquivalent="?" id="FKE-Sm-Kum">
<connections>
<action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
<connections>
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
</connections>
</application>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="LayerX" customModuleProvider="target"/>
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="75" y="0.0"/>
</scene>
<!--Window Controller-->
<scene sceneID="R2V-B0-nI4">
<objects>
<windowController id="B8D-0N-5wS" sceneMemberID="viewController">
<window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA" customClass="MCWIndow" customModule="LayerX" customModuleProvider="target">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="515" y="487" width="480" height="270"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<connections>
<outlet property="delegate" destination="B8D-0N-5wS" id="Ikp-UW-Prj"/>
</connections>
</window>
<connections>
<segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/>
</connections>
</windowController>
<customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="75" y="250"/>
</scene>
<!--View Controller-->
<scene sceneID="hIz-AP-VOD">
<objects>
<viewController id="XfG-lQ-9wD" customClass="ViewController" customModule="LayerX" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" id="m2S-Jp-Qdl" customClass="MCMovableView" customModule="LayerX" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="249" verticalCompressionResistancePriority="249" translatesAutoresizingMaskIntoConstraints="NO" id="pOu-B0-2Yd" customClass="MCDragAndDropImageView" customModule="LayerX" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="axesIndependently" id="55W-zB-lko"/>
</imageView>
<textField hidden="YES" wantsLayer="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JAT-ZL-8HB">
<rect key="frame" x="454" y="243" width="16" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" refusesFirstResponder="YES" sendsActionOnEndEditing="YES" alignment="center" title="0" drawsBackground="YES" id="Mmp-Eh-bBs">
<font key="font" metaFont="system"/>
<color key="textColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.59999999999999998" colorSpace="calibratedRGB"/>
</textFieldCell>
</textField>
<textField wantsLayer="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8Vs-Az-CYd">
<rect key="frame" x="148" y="123" width="184" height="25"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Drop Images here." id="vTq-g5-aKV">
<font key="font" size="20" name="HelveticaNeue-Bold"/>
<color key="textColor" name="scrollBarColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="calibratedRGB"/>
</textFieldCell>
</textField>
<imageView hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="3I3-1H-JKb">
<rect key="frame" x="446" y="10" width="24" height="24"/>
<constraints>
<constraint firstAttribute="width" secondItem="3I3-1H-JKb" secondAttribute="height" multiplier="1:1" id="BQz-pm-nY9"/>
<constraint firstAttribute="width" constant="24" id="x71-Sn-2Dl"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="lock" id="4Zf-oV-Kj0"/>
</imageView>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="3I3-1H-JKb" secondAttribute="bottom" constant="10" id="64H-0g-nnO"/>
<constraint firstItem="8Vs-Az-CYd" firstAttribute="centerY" secondItem="m2S-Jp-Qdl" secondAttribute="centerY" id="6fI-na-pdX"/>
<constraint firstItem="8Vs-Az-CYd" firstAttribute="centerX" secondItem="m2S-Jp-Qdl" secondAttribute="centerX" id="RwW-eB-OYh"/>
<constraint firstItem="JAT-ZL-8HB" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" constant="10" id="WnK-c6-NWw"/>
<constraint firstItem="pOu-B0-2Yd" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" id="aC7-xh-2BR"/>
<constraint firstItem="pOu-B0-2Yd" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" id="lhy-17-EcM"/>
<constraint firstAttribute="trailing" secondItem="pOu-B0-2Yd" secondAttribute="trailing" id="qbm-Dq-jeg"/>
<constraint firstAttribute="bottom" secondItem="pOu-B0-2Yd" secondAttribute="bottom" id="r2U-99-hj5"/>
<constraint firstAttribute="trailing" secondItem="3I3-1H-JKb" secondAttribute="trailing" constant="10" id="und-pJ-9Mz"/>
<constraint firstAttribute="trailing" secondItem="JAT-ZL-8HB" secondAttribute="trailing" constant="10" id="xlU-hc-l09"/>
</constraints>
</view>
<connections>
<outlet property="imageView" destination="pOu-B0-2Yd" id="OT9-S1-m4L"/>
<outlet property="lockIconImageView" destination="3I3-1H-JKb" id="Nka-rj-tDO"/>
<outlet property="placeholderTextField" destination="8Vs-Az-CYd" id="env-Po-Bb7"/>
<outlet property="sizeTextField" destination="JAT-ZL-8HB" id="vIP-80-PVG"/>
</connections>
</viewController>
<customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="75" y="655"/>
</scene>
</scenes>
<resources>
<image name="lock" width="32" height="32"/>
</resources>
</document>
================================================
FILE: LayerX/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.2.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2015年 Michael Chen. All rights reserved.</string>
<key>NSMainStoryboardFile</key>
<string>Main</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
================================================
FILE: LayerX/MCDragAndDropImageView.swift
================================================
//
// MCDragAndDropImageView.swift
// LayerX
//
// Created by Michael Chen on 2015/10/26.
// Copyright © 2015年 Michael Chen. All rights reserved.
//
import Cocoa
protocol MCDragAndDropImageViewDelegate: class {
func dragAndDropImageViewDidDrop(_ imageView: MCDragAndDropImageView)
}
class MCDragAndDropImageView: NSImageView {
weak var delegate: MCDragAndDropImageViewDelegate?
required init?(coder: NSCoder) {
super.init(coder: coder)
registerForDraggedTypes(NSImage.imageTypes.map(NSPasteboard.PasteboardType.init(rawValue:)))
wantsLayer = true
}
override func setNeedsDisplay() {
alphaValue = image == nil ? 1.0 : 0.6
super.setNeedsDisplay()
}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
if let _ = image {
layer?.backgroundColor = NSColor.clear.cgColor
return
}
layer?.backgroundColor = NSColor(white: isHighlighted ? 0.5 : 0.8, alpha: 1.0).cgColor
}
override var mouseDownCanMoveWindow:Bool {
return true
}
}
// MARK: - NSDraggingSource
extension MCDragAndDropImageView: NSDraggingSource {
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
if (NSImage.canInit(with: sender.draggingPasteboard)) {
isHighlighted = true
setNeedsDisplay()
let sourceDragMask = sender.draggingSourceOperationMask
let pboard = sender.draggingPasteboard
if pboard.availableType(from: [.fileURL]) == .fileURL {
if sourceDragMask.rawValue & NSDragOperation.copy.rawValue != 0 {
return NSDragOperation.copy
}
}
}
return NSDragOperation()
}
override func draggingExited(_ sender: NSDraggingInfo?) {
isHighlighted = false
setNeedsDisplay()
}
override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
isHighlighted = false
setNeedsDisplay()
return NSImage.canInit(with: sender.draggingPasteboard)
}
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
if (NSImage.canInit(with: sender.draggingPasteboard)) {
image = NSImage(pasteboard: sender.draggingPasteboard)
delegate?.dragAndDropImageViewDidDrop(self)
setNeedsDisplay()
}
return true
}
func draggingSession(_ session: NSDraggingSession, sourceOperationMaskFor context: NSDraggingContext) -> NSDragOperation {
switch context {
case .outsideApplication: return NSDragOperation()
case .withinApplication: return .copy
@unknown default: return NSDragOperation()
}
}
}
================================================
FILE: LayerX/MCWindow.swift
================================================
//
// MCWindow.swift
// LayerX
//
// Created by Michael Chen on 2015/10/27.
// Copyright © 2015年 Michael Chen. All rights reserved.
//
import Cocoa
class MCWIndow: NSWindow {
override func awakeFromNib() {
styleMask = [.borderless, .resizable]
isOpaque = false
backgroundColor = NSColor.clear
isMovableByWindowBackground = true
hasShadow = false
}
func moveBy(_ offset: CGPoint) {
var frame = self.frame
frame.origin.x += offset.x
frame.origin.y += offset.y
setFrame(frame, display: true)
}
func fitsWithSize(_ size: NSSize) {
var frame = self.frame
if frame.size.width < size.width || frame.size.height < size.height {
frame.size = size
setFrame(frame, display: true)
}
}
func resizeTo(_ size: NSSize, animated: Bool) {
var frame = self.frame
frame.size = size
if !animated {
setFrame(frame, display: true)
return
}
let resizeAnimation = [NSViewAnimation.Key.target: self, NSViewAnimation.Key.endFrame: NSValue(rect: frame)]
let animations = NSViewAnimation(viewAnimations: [resizeAnimation])
animations.animationBlockingMode = .blocking
animations.animationCurve = .easeInOut
animations.duration = 0.15
animations.start()
}
override func constrainFrameRect(_ frameRect: NSRect, to screen: NSScreen?) -> NSRect {
return frameRect
}
}
================================================
FILE: LayerX/ViewController.swift
================================================
//
// ViewController.swift
// LayerX
//
// Created by Michael Chen on 2015/10/26.
// Copyright © 2015年 Michael Chen. All rights reserved.
//
import Cocoa
class ViewController: NSViewController {
@IBOutlet weak var imageView: MCDragAndDropImageView!
@IBOutlet weak var sizeTextField: NSTextField!
@IBOutlet weak var placeholderTextField: NSTextField!
@IBOutlet weak var lockIconImageView: NSImageView!
override var acceptsFirstResponder: Bool {
return true
}
lazy var trackingArea: NSTrackingArea = {
let options: NSTrackingArea.Options = [.activeAlways, .mouseEnteredAndExited]
return NSTrackingArea(rect: self.view.bounds, options: options, owner: self, userInfo: nil)
}()
deinit {
NotificationCenter.default.removeObserver(self)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
appDelegate().viewController = self
}
override func viewDidLoad() {
super.viewDidLoad()
imageView.delegate = self
sizeTextField.layer?.cornerRadius = 3
sizeTextField.layer?.masksToBounds = true
lockIconImageView.wantsLayer = true
lockIconImageView.layer?.backgroundColor = NSColor(white: 0.0, alpha: 0.5).cgColor
lockIconImageView.layer?.cornerRadius = 5
lockIconImageView.layer?.masksToBounds = true
NotificationCenter.default.addObserver(self, selector: #selector(windowDidResize(_:)), name: NSWindow.didResizeNotification, object: appDelegate().window)
view.addTrackingArea(trackingArea)
}
@objc func fadeOutSizeTextField() {
let transition = CATransition()
sizeTextField.layer?.add(transition, forKey: "fadeOut")
sizeTextField.layer?.opacity = 0
}
@objc func windowDidResize(_ notification: Notification) {
let window = notification.object as! NSWindow
let size = window.frame.size
sizeTextField.stringValue = "\(Int(size.width))x\(Int(size.height))"
sizeTextField.layer?.opacity = 1
NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(ViewController.fadeOutSizeTextField), object: nil)
perform(#selector(ViewController.fadeOutSizeTextField), with: nil, afterDelay: 2)
}
// MARK: Mouse events
override func scrollWheel(with theEvent: NSEvent) {
guard let _ = imageView.image else { return }
let delta = theEvent.deltaY * 0.005;
var alpha = imageView.alphaValue - delta
alpha = min(alpha, 1)
alpha = max(alpha, 0.05)
imageView.alphaValue = alpha
}
override func mouseEntered(with theEvent: NSEvent) {
sizeTextField.layer?.opacity = 1
}
override func mouseExited(with theEvent: NSEvent) {
fadeOutSizeTextField()
}
}
// MARK: - MCDragAndDropImageViewDelegate
extension ViewController: MCDragAndDropImageViewDelegate {
func dragAndDropImageViewDidDrop(_ imageView: MCDragAndDropImageView) {
sizeTextField.isHidden = false
placeholderTextField.isHidden = true
appDelegate().actualSize(nil)
}
}
// MARK: - Movable NSView
class MCMovableView: NSView{
override var mouseDownCanMoveWindow:Bool {
return true
}
}
================================================
FILE: LayerX.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
8C09F9F51BDE2E5C00DD457E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C09F9F41BDE2E5C00DD457E /* AppDelegate.swift */; };
8C09F9F71BDE2E5C00DD457E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C09F9F61BDE2E5C00DD457E /* ViewController.swift */; };
8C09F9F91BDE2E5C00DD457E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8C09F9F81BDE2E5C00DD457E /* Assets.xcassets */; };
8C09F9FC1BDE2E5C00DD457E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8C09F9FA1BDE2E5C00DD457E /* Main.storyboard */; };
8C09FA041BDE324500DD457E /* MCDragAndDropImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C09FA031BDE324500DD457E /* MCDragAndDropImageView.swift */; };
8C09FA0C1BDF5F7300DD457E /* MCWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C09FA0B1BDF5F7300DD457E /* MCWindow.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
8C09F9F11BDE2E5C00DD457E /* LayerX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LayerX.app; sourceTree = BUILT_PRODUCTS_DIR; };
8C09F9F41BDE2E5C00DD457E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
8C09F9F61BDE2E5C00DD457E /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
8C09F9F81BDE2E5C00DD457E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
8C09F9FB1BDE2E5C00DD457E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
8C09F9FD1BDE2E5C00DD457E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8C09FA031BDE324500DD457E /* MCDragAndDropImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MCDragAndDropImageView.swift; sourceTree = "<group>"; };
8C09FA0B1BDF5F7300DD457E /* MCWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MCWindow.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
8C09F9EE1BDE2E5C00DD457E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
8C09F9E81BDE2E5C00DD457E = {
isa = PBXGroup;
children = (
8C09F9F31BDE2E5C00DD457E /* LayerX */,
8C09F9F21BDE2E5C00DD457E /* Products */,
);
sourceTree = "<group>";
};
8C09F9F21BDE2E5C00DD457E /* Products */ = {
isa = PBXGroup;
children = (
8C09F9F11BDE2E5C00DD457E /* LayerX.app */,
);
name = Products;
sourceTree = "<group>";
};
8C09F9F31BDE2E5C00DD457E /* LayerX */ = {
isa = PBXGroup;
children = (
8C09F9F41BDE2E5C00DD457E /* AppDelegate.swift */,
8C09FA0B1BDF5F7300DD457E /* MCWindow.swift */,
8C09F9F61BDE2E5C00DD457E /* ViewController.swift */,
8C09FA031BDE324500DD457E /* MCDragAndDropImageView.swift */,
8C09F9F81BDE2E5C00DD457E /* Assets.xcassets */,
8C09F9FA1BDE2E5C00DD457E /* Main.storyboard */,
8C09F9FD1BDE2E5C00DD457E /* Info.plist */,
);
path = LayerX;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
8C09F9F01BDE2E5C00DD457E /* LayerX */ = {
isa = PBXNativeTarget;
buildConfigurationList = 8C09FA001BDE2E5C00DD457E /* Build configuration list for PBXNativeTarget "LayerX" */;
buildPhases = (
8C09F9ED1BDE2E5C00DD457E /* Sources */,
8C09F9EE1BDE2E5C00DD457E /* Frameworks */,
8C09F9EF1BDE2E5C00DD457E /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = LayerX;
productName = LayerX;
productReference = 8C09F9F11BDE2E5C00DD457E /* LayerX.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
8C09F9E91BDE2E5C00DD457E /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0700;
ORGANIZATIONNAME = "Michael Chen";
TargetAttributes = {
8C09F9F01BDE2E5C00DD457E = {
CreatedOnToolsVersion = 7.0;
LastSwiftMigration = 0800;
};
};
};
buildConfigurationList = 8C09F9EC1BDE2E5C00DD457E /* Build configuration list for PBXProject "LayerX" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
Base,
);
mainGroup = 8C09F9E81BDE2E5C00DD457E;
productRefGroup = 8C09F9F21BDE2E5C00DD457E /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
8C09F9F01BDE2E5C00DD457E /* LayerX */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
8C09F9EF1BDE2E5C00DD457E /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8C09F9F91BDE2E5C00DD457E /* Assets.xcassets in Resources */,
8C09F9FC1BDE2E5C00DD457E /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
8C09F9ED1BDE2E5C00DD457E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8C09F9F71BDE2E5C00DD457E /* ViewController.swift in Sources */,
8C09FA0C1BDF5F7300DD457E /* MCWindow.swift in Sources */,
8C09F9F51BDE2E5C00DD457E /* AppDelegate.swift in Sources */,
8C09FA041BDE324500DD457E /* MCDragAndDropImageView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
8C09F9FA1BDE2E5C00DD457E /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
8C09F9FB1BDE2E5C00DD457E /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
8C09F9FE1BDE2E5C00DD457E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
8C09F9FF1BDE2E5C00DD457E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_VERSION = 5.0;
};
name = Release;
};
8C09FA011BDE2E5C00DD457E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = LayerX/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = io.michaelchen.LayerX;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
8C09FA021BDE2E5C00DD457E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = LayerX/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = io.michaelchen.LayerX;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
8C09F9EC1BDE2E5C00DD457E /* Build configuration list for PBXProject "LayerX" */ = {
isa = XCConfigurationList;
buildConfigurations = (
8C09F9FE1BDE2E5C00DD457E /* Debug */,
8C09F9FF1BDE2E5C00DD457E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
8C09FA001BDE2E5C00DD457E /* Build configuration list for PBXNativeTarget "LayerX" */ = {
isa = XCConfigurationList;
buildConfigurations = (
8C09FA011BDE2E5C00DD457E /* Debug */,
8C09FA021BDE2E5C00DD457E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 8C09F9E91BDE2E5C00DD457E /* Project object */;
}
================================================
FILE: LayerX.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:LayerX.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: README.md
================================================
# LayerX
An intuitive app to display transparent images on screen.
[](http://www.youtube.com/watch?v=35KixjZBDjY)
# System requirements
Support Mac OS X 10.10 or later.
# Features
- [x] Drag and drop images
- [x] Keyboard Shortcuts
- [x] Adjust transparency
- [x] Lock images
- [X] Aspect ratio scaling
# Keyboard Shortcuts
### Set image
| Key | Action |
|:--- |:--- |
|`⌘ V`| Paste image or file from clipboard. |
### Scale
| Key | Action |
|:---|:---|
|`⌘ 0`| Actual image size.|
|`⌘ +`| Scale up 10%.|
|`⌘ -`| Scale down 10%.|
|`^ ⌘ +`| Scale up 1px.|
|`^ ⌘ -`| Scale down 1px.|
### Move (Arrow keys)
| Key | Action |
|:---|:---|
|`↑`| Move up 1px.|
|`←`| Move left 1px.|
|`→`| Move right 1px.|
|`↓`| Move down 1px.|
### Alpha
|Key|Action|
|:---|:---|
|`⌘ J`| Increase transparency.|
|`⌘ K`| Reduce transparency.|
### Window
|Key|Action|
|:---|:---|
|`⌘ L`| Lock images and make window always on top.|
|`⌘ T`| Make window always on top.|
|`⌘ A`| Keep window on all spaces.|
# Mouse events
| Event | Action |
|:---|:---|
| Scroll up on image | Reduce transparency. |
| Scroll down on image | Increase transparency. |
# Contact
Any suggestions are welcome. Find me at [@yuhua_twit](https://twitter.com/yuhua_twit)
# License
Copyright (c) 2017 Michael Chen (a.k.a. Yuhua Chen)
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:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
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.
gitextract_ov5xqwub/ ├── .gitignore ├── LayerX/ │ ├── AppDelegate.swift │ ├── Assets.xcassets/ │ │ ├── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── lock.imageset/ │ │ └── Contents.json │ ├── Base.lproj/ │ │ └── Main.storyboard │ ├── Info.plist │ ├── MCDragAndDropImageView.swift │ ├── MCWindow.swift │ └── ViewController.swift ├── LayerX.xcodeproj/ │ ├── project.pbxproj │ └── project.xcworkspace/ │ └── contents.xcworkspacedata └── README.md
Condensed preview — 13 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (63K chars).
[
{
"path": ".gitignore",
"chars": 798,
"preview": "# Created by https://www.gitignore.io/api/xcode,osx\n\n### Xcode ###\n# Xcode\n#\n# gitignore contributors: remember to updat"
},
{
"path": "LayerX/AppDelegate.swift",
"chars": 5732,
"preview": "//\n// AppDelegate.swift\n// LayerX\n//\n// Created by Michael Chen on 2015/10/26.\n// Copyright © 2015年 Michael Chen. Al"
},
{
"path": "LayerX/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 1271,
"preview": "{\n \"images\" : [\n {\n \"size\" : \"16x16\",\n \"idiom\" : \"mac\",\n \"filename\" : \"appIcon-16.png\",\n \"scale\""
},
{
"path": "LayerX/Assets.xcassets/Contents.json",
"chars": 62,
"preview": "{\n \"info\" : {\n \"version\" : 1,\n \"author\" : \"xcode\"\n }\n}"
},
{
"path": "LayerX/Assets.xcassets/lock.imageset/Contents.json",
"chars": 369,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"universal\",\n \"filename\" : \"Lock-16.png\",\n \"scale\" : \"1x\"\n },\n {\n"
},
{
"path": "LayerX/Base.lproj/Main.storyboard",
"chars": 28280,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB\""
},
{
"path": "LayerX/Info.plist",
"chars": 1089,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "LayerX/MCDragAndDropImageView.swift",
"chars": 2423,
"preview": "//\n// MCDragAndDropImageView.swift\n// LayerX\n//\n// Created by Michael Chen on 2015/10/26.\n// Copyright © 2015年 Micha"
},
{
"path": "LayerX/MCWindow.swift",
"chars": 1358,
"preview": "//\n// MCWindow.swift\n// LayerX\n//\n// Created by Michael Chen on 2015/10/27.\n// Copyright © 2015年 Michael Chen. All r"
},
{
"path": "LayerX/ViewController.swift",
"chars": 2957,
"preview": "//\n// ViewController.swift\n// LayerX\n//\n// Created by Michael Chen on 2015/10/26.\n// Copyright © 2015年 Michael Chen."
},
{
"path": "LayerX.xcodeproj/project.pbxproj",
"chars": 10915,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "LayerX.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 151,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:LayerX.xcodepro"
},
{
"path": "README.md",
"chars": 2381,
"preview": "# LayerX\n\nAn intuitive app to display transparent images on screen.\n\n[. The extraction includes 13 files (56.4 KB), approximately 15.0k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.