Initial commit

This commit is contained in:
Louis D'hauwe 2018-04-02 15:09:23 +02:00
commit ed4077e9a8
21 changed files with 1638 additions and 0 deletions

5
.editorconfig Normal file
View File

@ -0,0 +1,5 @@
root = true
[*]
indent_style = tab
indent_size = 4

20
.gitignore vendored Normal file
View File

@ -0,0 +1,20 @@
# Xcode
#
.DS_Store
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate

1
.swift-version Executable file
View File

@ -0,0 +1 @@
4.0

View File

@ -0,0 +1,397 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
BE5C1E1C1F3266B600B0080C /* HueKit.h in Headers */ = {isa = PBXBuildFile; fileRef = BE5C1E1A1F3266B600B0080C /* HueKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
BE5C1E361F326E2500B0080C /* RGB.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE5C1E351F326E2500B0080C /* RGB.swift */; };
BE5C1E381F326E3300B0080C /* HSV.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE5C1E371F326E3300B0080C /* HSV.swift */; };
BE5C1E3B1F326EE600B0080C /* UIColor+Values.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE5C1E3A1F326EE600B0080C /* UIColor+Values.swift */; };
BE5C1E3D1F3270CE00B0080C /* CGFloat+Pin.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE5C1E3C1F3270CE00B0080C /* CGFloat+Pin.swift */; };
BE5C1E3F1F32710B00B0080C /* HSBComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE5C1E3E1F32710B00B0080C /* HSBComponent.swift */; };
BE5C1E471F3271D600B0080C /* ColorBarPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE5C1E401F3271D600B0080C /* ColorBarPicker.swift */; };
BE5C1E481F3271D600B0080C /* ColorBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE5C1E411F3271D600B0080C /* ColorBarView.swift */; };
BE5C1E491F3271D600B0080C /* ColorIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE5C1E421F3271D600B0080C /* ColorIndicatorView.swift */; };
BE5C1E4A1F3271D600B0080C /* ColorSquarePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE5C1E431F3271D600B0080C /* ColorSquarePicker.swift */; };
BE5C1E4B1F3271D600B0080C /* ColorSquareView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE5C1E441F3271D600B0080C /* ColorSquareView.swift */; };
BE5C1E4D1F3271D600B0080C /* SourceColorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE5C1E461F3271D600B0080C /* SourceColorView.swift */; };
BE5C1E4F1F3271E900B0080C /* HSBGen.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE5C1E4E1F3271E900B0080C /* HSBGen.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
BE5C1E171F3266B600B0080C /* HueKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = HueKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BE5C1E1A1F3266B600B0080C /* HueKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HueKit.h; sourceTree = "<group>"; };
BE5C1E1B1F3266B600B0080C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
BE5C1E351F326E2500B0080C /* RGB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RGB.swift; path = Model/RGB.swift; sourceTree = "<group>"; };
BE5C1E371F326E3300B0080C /* HSV.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HSV.swift; path = Model/HSV.swift; sourceTree = "<group>"; };
BE5C1E3A1F326EE600B0080C /* UIColor+Values.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIColor+Values.swift"; path = "Util/UIColor+Values.swift"; sourceTree = "<group>"; };
BE5C1E3C1F3270CE00B0080C /* CGFloat+Pin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "CGFloat+Pin.swift"; path = "Util/CGFloat+Pin.swift"; sourceTree = "<group>"; };
BE5C1E3E1F32710B00B0080C /* HSBComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HSBComponent.swift; path = Model/HSBComponent.swift; sourceTree = "<group>"; };
BE5C1E401F3271D600B0080C /* ColorBarPicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ColorBarPicker.swift; path = View/ColorBarPicker.swift; sourceTree = "<group>"; };
BE5C1E411F3271D600B0080C /* ColorBarView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ColorBarView.swift; path = View/ColorBarView.swift; sourceTree = "<group>"; };
BE5C1E421F3271D600B0080C /* ColorIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ColorIndicatorView.swift; path = View/ColorIndicatorView.swift; sourceTree = "<group>"; };
BE5C1E431F3271D600B0080C /* ColorSquarePicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ColorSquarePicker.swift; path = View/ColorSquarePicker.swift; sourceTree = "<group>"; };
BE5C1E441F3271D600B0080C /* ColorSquareView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ColorSquareView.swift; path = View/ColorSquareView.swift; sourceTree = "<group>"; };
BE5C1E461F3271D600B0080C /* SourceColorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SourceColorView.swift; path = View/SourceColorView.swift; sourceTree = "<group>"; };
BE5C1E4E1F3271E900B0080C /* HSBGen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HSBGen.swift; path = Util/HSBGen.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
BE5C1E131F3266B600B0080C /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
BE5C1E0D1F3266B600B0080C = {
isa = PBXGroup;
children = (
BE5C1E191F3266B600B0080C /* HueKit */,
BE5C1E181F3266B600B0080C /* Products */,
);
sourceTree = "<group>";
};
BE5C1E181F3266B600B0080C /* Products */ = {
isa = PBXGroup;
children = (
BE5C1E171F3266B600B0080C /* HueKit.framework */,
);
name = Products;
sourceTree = "<group>";
};
BE5C1E191F3266B600B0080C /* HueKit */ = {
isa = PBXGroup;
children = (
BE5C1E391F326E9300B0080C /* Util */,
BE5C1E221F326BF500B0080C /* Model */,
BE5C1E231F326BFD00B0080C /* View */,
BE5C1E1A1F3266B600B0080C /* HueKit.h */,
BE5C1E1B1F3266B600B0080C /* Info.plist */,
);
path = HueKit;
sourceTree = "<group>";
};
BE5C1E221F326BF500B0080C /* Model */ = {
isa = PBXGroup;
children = (
BE5C1E351F326E2500B0080C /* RGB.swift */,
BE5C1E371F326E3300B0080C /* HSV.swift */,
BE5C1E3E1F32710B00B0080C /* HSBComponent.swift */,
);
name = Model;
sourceTree = "<group>";
};
BE5C1E231F326BFD00B0080C /* View */ = {
isa = PBXGroup;
children = (
BE5C1E401F3271D600B0080C /* ColorBarPicker.swift */,
BE5C1E411F3271D600B0080C /* ColorBarView.swift */,
BE5C1E421F3271D600B0080C /* ColorIndicatorView.swift */,
BE5C1E431F3271D600B0080C /* ColorSquarePicker.swift */,
BE5C1E441F3271D600B0080C /* ColorSquareView.swift */,
BE5C1E461F3271D600B0080C /* SourceColorView.swift */,
);
name = View;
sourceTree = "<group>";
};
BE5C1E391F326E9300B0080C /* Util */ = {
isa = PBXGroup;
children = (
BE5C1E4E1F3271E900B0080C /* HSBGen.swift */,
BE5C1E3A1F326EE600B0080C /* UIColor+Values.swift */,
BE5C1E3C1F3270CE00B0080C /* CGFloat+Pin.swift */,
);
name = Util;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
BE5C1E141F3266B600B0080C /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
BE5C1E1C1F3266B600B0080C /* HueKit.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
BE5C1E161F3266B600B0080C /* HueKit */ = {
isa = PBXNativeTarget;
buildConfigurationList = BE5C1E1F1F3266B600B0080C /* Build configuration list for PBXNativeTarget "HueKit" */;
buildPhases = (
BE5C1E121F3266B600B0080C /* Sources */,
BE5C1E131F3266B600B0080C /* Frameworks */,
BE5C1E141F3266B600B0080C /* Headers */,
BE5C1E151F3266B600B0080C /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = HueKit;
productName = HueKit;
productReference = BE5C1E171F3266B600B0080C /* HueKit.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
BE5C1E0E1F3266B600B0080C /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0900;
ORGANIZATIONNAME = "Silver Fox";
TargetAttributes = {
BE5C1E161F3266B600B0080C = {
CreatedOnToolsVersion = 8.3.3;
DevelopmentTeam = 6G5LMQ72D8;
LastSwiftMigration = 0900;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = BE5C1E111F3266B600B0080C /* Build configuration list for PBXProject "HueKit" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = BE5C1E0D1F3266B600B0080C;
productRefGroup = BE5C1E181F3266B600B0080C /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
BE5C1E161F3266B600B0080C /* HueKit */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
BE5C1E151F3266B600B0080C /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
BE5C1E121F3266B600B0080C /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
BE5C1E3B1F326EE600B0080C /* UIColor+Values.swift in Sources */,
BE5C1E471F3271D600B0080C /* ColorBarPicker.swift in Sources */,
BE5C1E4F1F3271E900B0080C /* HSBGen.swift in Sources */,
BE5C1E4D1F3271D600B0080C /* SourceColorView.swift in Sources */,
BE5C1E4A1F3271D600B0080C /* ColorSquarePicker.swift in Sources */,
BE5C1E491F3271D600B0080C /* ColorIndicatorView.swift in Sources */,
BE5C1E381F326E3300B0080C /* HSV.swift in Sources */,
BE5C1E3F1F32710B00B0080C /* HSBComponent.swift in Sources */,
BE5C1E361F326E2500B0080C /* RGB.swift in Sources */,
BE5C1E4B1F3271D600B0080C /* ColorSquareView.swift in Sources */,
BE5C1E3D1F3270CE00B0080C /* CGFloat+Pin.swift in Sources */,
BE5C1E481F3271D600B0080C /* ColorBarView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
BE5C1E1D1F3266B600B0080C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
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;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
BE5C1E1E1F3266B600B0080C /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
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;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
BE5C1E201F3266B600B0080C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 6G5LMQ72D8;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = HueKit/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = be.silverfox.HueKit;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
};
name = Debug;
};
BE5C1E211F3266B600B0080C /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 6G5LMQ72D8;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = HueKit/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = be.silverfox.HueKit;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
BE5C1E111F3266B600B0080C /* Build configuration list for PBXProject "HueKit" */ = {
isa = XCConfigurationList;
buildConfigurations = (
BE5C1E1D1F3266B600B0080C /* Debug */,
BE5C1E1E1F3266B600B0080C /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
BE5C1E1F1F3266B600B0080C /* Build configuration list for PBXNativeTarget "HueKit" */ = {
isa = XCConfigurationList;
buildConfigurations = (
BE5C1E201F3266B600B0080C /* Debug */,
BE5C1E211F3266B600B0080C /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = BE5C1E0E1F3266B600B0080C /* Project object */;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:HueKit.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

7
HueKit/HueKit.h Normal file
View File

@ -0,0 +1,7 @@
//
// HueKit.h
// HueKit
//
// Created by Louis D'hauwe on 02/08/2017.
// Copyright © 2017 Silver Fox. All rights reserved.
//

24
HueKit/Info.plist Normal file
View File

@ -0,0 +1,24 @@
<?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>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>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -0,0 +1,15 @@
//
// HSBComponent.swift
// HueKit
//
// Created by Louis D'hauwe on 02/08/2017.
// Copyright © 2017 Silver Fox. All rights reserved.
//
import Foundation
enum HSBComponent: Int {
case hue = 0
case saturation = 1
case brightness = 2
}

97
HueKit/Model/HSV.swift Normal file
View File

@ -0,0 +1,97 @@
//
// HSV.swift
// HueKit
//
// Created by Louis D'hauwe on 02/08/2017.
// Copyright © 2017 Silver Fox. All rights reserved.
//
import Foundation
import CoreGraphics
public struct HSV {
/// In degrees (range 0...360)
public var h: CGFloat
/// Percentage in range 0...1
public var s: CGFloat
/// Percentage in range 0...1
/// Also known as "brightness" (B)
public var v: CGFloat
}
extension HSV {
/// These functions convert between an RGB value with components in the
/// 0.0..1.0 range to HSV where Hue is 0 .. 360 and Saturation and
/// Value (aka Brightness) are percentages expressed as 0.0..1.0.
//
/// Note that HSB (B = Brightness) and HSV (V = Value) are interchangeable
/// names that mean the same thing. I use V here as it is unambiguous
/// relative to the B in RGB, which is Blue.
func toRGB() -> RGB {
var rgb = self.hueToRGB()
let c = v * s
let m = v - c
rgb.r = rgb.r * c + m
rgb.g = rgb.g * c + m
rgb.b = rgb.b * c + m
return rgb
}
func hueToRGB() -> RGB {
let hPrime = h / 60.0
let x = 1.0 - abs(hPrime.truncatingRemainder(dividingBy: 2.0) - 1.0)
let r: CGFloat
let g: CGFloat
let b: CGFloat
if hPrime < 1.0 {
r = 1
g = x
b = 0
} else if hPrime < 2.0 {
r = x
g = 1
b = 0
} else if hPrime < 3.0 {
r = 0
g = 1
b = x
} else if hPrime < 4.0 {
r = 0
g = x
b = 1
} else if hPrime < 5.0 {
r = x
g = 0
b = 1
} else {
r = 1
g = 0
b = x
}
return RGB(r: r, g: g, b: b)
}
}

114
HueKit/Model/RGB.swift Normal file
View File

@ -0,0 +1,114 @@
//
// RGB.swift
// HueKit
//
// Created by Louis D'hauwe on 02/08/2017.
// Copyright © 2017 Silver Fox. All rights reserved.
//
import Foundation
import CoreGraphics
public struct RGB {
/// In range 0...1
public var r: CGFloat
/// In range 0...1
public var g: CGFloat
/// In range 0...1
public var b: CGFloat
}
public extension RGB {
func toHSV(preserveHS: Bool, h: CGFloat = 0, s: CGFloat = 0) -> HSV {
var h = h
var s = s
var v: CGFloat = 0
var max = r
if max < g {
max = g
}
if max < b {
max = b
}
var min = r
if min > g {
min = g
}
if min > b {
min = b
}
// Brightness (aka Value)
v = max
// Saturation
var sat: CGFloat = 0.0
if max != 0.0 {
sat = (max - min) / max
s = sat
} else {
sat = 0.0
// Black, so sat is undefined, use 0
if !preserveHS {
s = 0.0
}
}
// Hue
var delta: CGFloat = 0
if sat == 0.0 {
// No color, so hue is undefined, use 0
if !preserveHS {
h = 0.0
}
} else {
delta = max - min
var hue: CGFloat = 0
if r == max {
hue = (g - b) / delta
} else if g == max {
hue = 2 + (b - r) / delta
} else {
hue = 4 + (r - g) / delta
}
hue /= 6.0
if hue < 0.0 {
hue += 1.0
}
// 0.0 and 1.0 hues are actually both the same (red)
if !preserveHS || abs(hue - h) != 1.0 {
h = hue
}
}
return HSV(h: h, s: s, v: v)
}
}

View File

@ -0,0 +1,25 @@
//
// CGFloat+Pin.swift
// HueKit
//
// Created by Louis D'hauwe on 02/08/2017.
// Copyright © 2017 Silver Fox. All rights reserved.
//
import Foundation
import CoreGraphics
extension CGFloat {
func pinned(between minValue: CGFloat, and maxValue: CGFloat) -> CGFloat {
if self < minValue {
return minValue
} else if self > maxValue {
return maxValue
} else {
return self
}
}
}

143
HueKit/Util/HSBGen.swift Normal file
View File

@ -0,0 +1,143 @@
//
// HSBGen.swift
// HueKit
//
// Created by Louis D'hauwe on 29/07/2017.
// Copyright © 2017 Silver Fox. All rights reserved.
//
import Foundation
import CoreGraphics
class HSBGen {
static func createBGRxImageContext(w: Int, h: Int) -> CGContext? {
let colorSpace = CGColorSpaceCreateDeviceRGB()
// BGRA is the most efficient on the iPhone.
var bitmapInfo = CGBitmapInfo(rawValue: CGImageByteOrderInfo.order32Little.rawValue)
let noneSkipFirst = CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipFirst.rawValue)
bitmapInfo.formUnion(noneSkipFirst)
let context = CGContext(data: nil, width: w, height: h, bitsPerComponent: 8, bytesPerRow: w * 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
return context
}
/// Generates an image where the specified barComponentIndex (0=H, 1=S, 2=V)
/// varies across the x-axis of the 256x1 pixel image and the other components
/// remain at the constant value specified in the hsv array.
static func createHSVBarContentImage(hsbComponent: HSBComponent, hsv: [CGFloat]) -> CGImage? {
var hsv = hsv
guard let context = createBGRxImageContext(w: 256, h: 1) else {
return nil
}
guard var ptr = context.data?.assumingMemoryBound(to: UInt8.self) else {
return nil
}
for x in 0..<256 {
hsv[hsbComponent.rawValue] = CGFloat(x) / 255.0
let hsvVal = HSV(h: hsv[0] * 360.0, s: hsv[1], v: hsv[2])
let rgb = hsvVal.toRGB()
ptr[0] = UInt8(rgb.b * 255.0)
ptr[1] = UInt8(rgb.g * 255.0)
ptr[2] = UInt8(rgb.r * 255.0)
ptr = ptr.advanced(by: 4)
}
let image = context.makeImage()
return image
}
static private func blend(_ value: UInt, _ percentIn255: UInt) -> UInt {
return (value) * (percentIn255) / 255
}
// Generates a 256x256 image with the specified constant hue where the
// Saturation and value vary in the X and Y axes respectively.
static func createSaturationBrightnessSquareContentImageWithHue(hue: CGFloat) -> CGImage? {
guard let context = createBGRxImageContext(w: 256, h: 256) else {
return nil
}
guard var dataPtr = context.data?.assumingMemoryBound(to: UInt8.self) else {
return nil
}
let rowBytes = context.bytesPerRow
let hsv = HSV(h: hue, s: 0, v: 0)
let rgb = hsv.hueToRGB()
let r = rgb.r
let g = rgb.g
let b = rgb.b
let r_s = (UInt) ((1.0 - r) * 255)
let g_s = (UInt) ((1.0 - g) * 255)
let b_s = (UInt) ((1.0 - b) * 255)
// This doesn't use Swift ranges because those are pretty slow in debug builds
var s: UInt = 0
while true {
var ptr = dataPtr
let r_hs: UInt = 255 - blend(s, r_s)
let g_hs: UInt = 255 - blend(s, g_s)
let b_hs: UInt = 255 - blend(s, b_s)
var v: UInt = 255
while true {
// Really, these should all be of the form used in blend(),
// which does a divide by 255. However, integer divide is
// implemented in software on ARM, so a divide by 256
// (done as a bit shift) will be *nearly* the same value,
// and is faster. The more-accurate versions would look like:
// ptr[0] = blend(v, b_hs);
ptr[0] = UInt8((v * b_hs) >> 8)
ptr[1] = UInt8((v * g_hs) >> 8)
ptr[2] = UInt8((v * r_hs) >> 8)
ptr = ptr.advanced(by: rowBytes)
if v == 0 {
break
}
v -= 1
}
dataPtr = dataPtr.advanced(by: 4)
if s == 255 {
break
}
s += 1
}
let image = context.makeImage()
return image
}
}

View File

@ -0,0 +1,57 @@
//
// UIColor+Values.swift
// HueKit
//
// Created by Louis D'hauwe on 02/08/2017.
// Copyright © 2017 Silver Fox. All rights reserved.
//
import Foundation
import UIKit
extension UIColor {
public var rgbValue: RGB? {
guard let components = cgColor.components else {
return nil
}
let numComponents = cgColor.numberOfComponents
let r: CGFloat
let g: CGFloat
let b: CGFloat
if numComponents < 3 {
r = components[0]
g = components[0]
b = components[0]
} else {
r = components[0]
g = components[1]
b = components[2]
}
return RGB(r: r, g: g, b: b)
}
public var hsvValue: HSV? {
guard let rgb = rgbValue else {
return nil
}
return rgb.toHSV(preserveHS: true)
}
public func hsvValue(preservingHue hue: CGFloat, preservingSat sat: CGFloat) -> HSV? {
guard let rgb = rgbValue else {
return nil
}
return rgb.toHSV(preserveHS: true, h: hue, s: sat)
}
}

View File

@ -0,0 +1,297 @@
//
// ColorBarPicker.swift
// HueKit
//
// Created by Louis D'hauwe on 30/07/2017.
// Copyright © 2017 Silver Fox. All rights reserved.
//
import Foundation
import UIKit
@IBDesignable
public class ColorBarPicker: UIControl {
private var isVertical: Bool = false {
didSet {
if isVertical != oldValue {
updateOrientation()
}
}
}
private func updateVerticalState() {
// let bounds = self.layer.presentation()?.bounds ?? self.bounds
isVertical = bounds.height > bounds.width
}
private let contentInset: CGFloat = 20.0
private static let indicatorSizeInactive = CGSize(width: 24.0, height: 24.0)
private static let indicatorSizeActive = CGSize(width: 40.0, height: 40.0)
@IBInspectable
public var hue: CGFloat {
get {
if isVertical {
return 1.0 - value
} else {
return value
}
}
set {
if isVertical {
value = 1.0 - newValue
} else {
value = newValue
}
}
}
private var value: CGFloat = 0.0 {
didSet {
if oldValue != value {
self.sendActions(for: .valueChanged)
self.setNeedsLayout()
}
}
}
private lazy var colorBarView: ColorBarView = {
return ColorBarView()
}()
private lazy var indicator: ColorIndicatorView = {
let frame = CGRect(origin: .zero, size: ColorBarPicker.indicatorSizeInactive)
let indicator = ColorIndicatorView(frame: frame)
return indicator
}()
func updateOrientation() {
guard colorBarView.superview != nil else {
return
}
if isVertical {
colorBarView.transform = .identity
var rect = self.bounds
rect.size.width = bounds.height - contentInset * 2
rect.size.height = bounds.width
colorBarView.frame = rect
colorBarView.transform = CGAffineTransform(rotationAngle: -.pi / 2.0)
colorBarView.frame.origin = CGPoint(x: 0, y: contentInset)
} else {
var rect = self.bounds
rect.size.width -= contentInset * 2
colorBarView.frame = rect
colorBarView.transform = .identity
colorBarView.frame.origin = CGPoint(x: contentInset, y: 0)
}
}
// MARK: - Drawing
override public func layoutSubviews() {
if colorBarView.superview == nil {
colorBarView.isUserInteractionEnabled = false
colorBarView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(colorBarView)
updateOrientation()
}
if indicator.superview == nil {
self.addSubview(indicator)
}
let wasVertical = isVertical
updateVerticalState()
if wasVertical != isVertical {
value = 1.0 - value
}
updateOrientation()
// colorBarView.setNeedsDisplay()
indicator.color = UIColor(hue: hue,
saturation: 1.0,
brightness: 1.0,
alpha: 1.0)
if isVertical {
let indicatorLoc = contentInset + (self.value * (self.bounds.size.height - 2 * contentInset))
indicator.center = CGPoint(x: self.bounds.midX, y: indicatorLoc)
} else {
let indicatorLoc = contentInset + (self.value * (self.bounds.size.width - 2 * contentInset))
indicator.center = CGPoint(x: indicatorLoc, y: self.bounds.midY)
}
}
// MARK: - Tracking
private func trackIndicator(with touch: UITouch) {
let touchLocation = touch.location(in: self)
let percent: CGFloat
if isVertical {
percent = (touchLocation.y - contentInset) / (self.bounds.size.height - 2 * contentInset)
} else {
percent = (touchLocation.x - contentInset) / (self.bounds.size.width - 2 * contentInset)
}
self.value = percent.pinned(between: 0, and: 1)
}
override public func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
self.trackIndicator(with: touch)
growIndicator()
return true
}
override public func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
self.trackIndicator(with: touch)
return true
}
override public func endTracking(_ touch: UITouch?, with event: UIEvent?) {
super.endTracking(touch, with: event)
shrinkIndicator()
}
override public func cancelTracking(with event: UIEvent?) {
super.cancelTracking(with: event)
shrinkIndicator()
}
private func changeIndicatorSize(to size: CGSize) {
let center = self.indicator.center
let indicatorRect = CGRect(origin: .zero, size: size)
self.indicator.frame = indicatorRect
self.indicator.center = center
}
private func growIndicator() {
UIView.animate(withDuration: 0.15, delay: 0.0, options: [.curveEaseIn], animations: {
self.changeIndicatorSize(to: ColorBarPicker.indicatorSizeActive)
}) { (finished) in
}
}
private func shrinkIndicator() {
UIView.animate(withDuration: 0.15, delay: 0.0, options: [.curveEaseOut], animations: {
self.changeIndicatorSize(to: ColorBarPicker.indicatorSizeInactive)
self.indicator.setNeedsDisplay()
}) { (finished) in
self.indicator.setNeedsDisplay()
}
}
// MARK: - Accessibility
private let accessibilityInterval: CGFloat = 0.05
public override var accessibilityTraits: UIAccessibilityTraits {
get {
var t = super.accessibilityTraits
t |= UIAccessibilityTraitAdjustable
return t
}
set {
super.accessibilityTraits = newValue
}
}
public override func accessibilityIncrement() {
var newValue = self.value + accessibilityInterval
if newValue > 1.0 {
newValue -= 1.0
}
self.value = newValue
}
public override func accessibilityDecrement() {
var newValue = self.value - accessibilityInterval
if newValue < 0 {
newValue += 1.0
}
self.value = newValue
}
public override var accessibilityValue: String? {
get {
return String(format: "%d degrees hue", (self.value * 360.0))
}
set {
super.accessibilityValue = newValue
}
}
}

View File

@ -0,0 +1,36 @@
//
// ColorBarView.swift
// HueKit
//
// Created by Louis D'hauwe on 29/07/2017.
// Copyright © 2017 Silver Fox. All rights reserved.
//
import Foundation
import UIKit
@IBDesignable
class ColorBarView: UIView {
private static func createContentImage() -> CGImage? {
let hsv: [CGFloat] = [0.0, 1.0, 1.0]
return HSBGen.createHSVBarContentImage(hsbComponent: .hue, hsv: hsv)
}
override func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else {
return
}
guard let image = ColorBarView.createContentImage() else {
return
}
context.draw(image, in: self.bounds)
}
}

View File

@ -0,0 +1,69 @@
//
// ColorIndicatorView.swift
// HueKit
//
// Created by Louis D'hauwe on 30/07/2017.
// Copyright © 2017 Silver Fox. All rights reserved.
//
import Foundation
import UIKit
@IBDesignable
public class ColorIndicatorView: UIView {
@IBInspectable
public var color: UIColor = .black {
didSet {
if oldValue != color {
self.setNeedsDisplay()
}
}
}
override public init(frame: CGRect) {
super.init(frame: frame)
self.isOpaque = false
self.isUserInteractionEnabled = false
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func draw(_ rect: CGRect) {
guard let context = UIGraphicsGetCurrentContext() else {
return
}
let center = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
let radius = self.bounds.midX
// Fill it:
context.addArc(center: center, radius: radius - 1.0, startAngle: 0.0, endAngle: 2.0 * .pi, clockwise: true)
self.color.setFill()
context.fillPath()
// Stroke it (black transucent, inner):
context.addArc(center: center, radius: radius - 1.0, startAngle: 0.0, endAngle: 2.0 * .pi, clockwise: true)
context.setStrokeColor(gray: 0.0, alpha: 0.5)
context.setLineWidth(2.0)
context.strokePath()
// Stroke it (white, outer):
context.addArc(center: center, radius: radius - 2.0, startAngle: 0.0, endAngle: 2.0 * .pi, clockwise: true)
context.setStrokeColor(gray: 1.0, alpha: 1.0)
context.setLineWidth(2.0)
context.strokePath()
}
}

View File

@ -0,0 +1,170 @@
//
// ColorSquarePicker.swift
// HueKit
//
// Created by Louis D'hauwe on 30/07/2017.
// Copyright © 2017 Silver Fox. All rights reserved.
//
import Foundation
import UIKit
@IBDesignable
public class ColorSquarePicker: UIControl {
private let contentInsetX: CGFloat = 20
private let contentInsetY: CGFloat = 20
private let indicatorSizeInactive: CGFloat = 24
private let indicatorSizeActive: CGFloat = 40
private lazy var colorSquareView: ColorSquareView = {
return ColorSquareView()
}()
private lazy var indicator: ColorIndicatorView = {
let size = CGSize(width: self.indicatorSizeInactive, height: self.indicatorSizeInactive)
let indicatorRect = CGRect(origin: .zero, size: size)
return ColorIndicatorView(frame: indicatorRect)
}()
@IBInspectable
public var hue: CGFloat = 0.0 {
didSet {
if oldValue != hue {
self.setIndicatorColor()
}
}
}
@IBInspectable
public var value: CGPoint = .zero {
didSet {
if oldValue != value {
self.sendActions(for: .valueChanged)
self.setNeedsLayout()
}
}
}
private func setIndicatorColor() {
colorSquareView.hue = hue
indicator.color = UIColor(hue: hue, saturation: value.x, brightness: value.y, alpha: 1.0)
}
public override func layoutSubviews() {
if colorSquareView.superview == nil {
colorSquareView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(colorSquareView)
colorSquareView.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: contentInsetX).isActive = true
colorSquareView.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -contentInsetX).isActive = true
colorSquareView.topAnchor.constraint(equalTo: self.topAnchor, constant: contentInsetY).isActive = true
colorSquareView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -contentInsetY).isActive = true
}
if indicator.superview == nil {
self.addSubview(indicator)
}
self.setIndicatorColor()
let indicatorX = contentInsetX + (self.value.x * (self.bounds.size.width - 2 * contentInsetX))
let indicatorY = self.bounds.size.height - contentInsetY - (self.value.y * (self.bounds.size.height - 2 * contentInsetY))
indicator.center = CGPoint(x: indicatorX, y: indicatorY)
}
// MARK: - Tracking
private func trackIndicator(with touch: UITouch) {
let bounds = self.bounds
var touchValue = CGPoint(x: 0, y: 0)
touchValue.x = (touch.location(in: self).x - contentInsetX) / (bounds.size.width - 2 * contentInsetX)
touchValue.y = (touch.location(in: self).y - contentInsetY) / (bounds.size.height - 2 * contentInsetY)
touchValue.x = touchValue.x.pinned(between: 0, and: 1)
touchValue.y = 1.0 - touchValue.y.pinned(between: 0, and: 1)
self.value = touchValue
}
override public func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
self.trackIndicator(with: touch)
growIndicator()
return true
}
override public func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
self.trackIndicator(with: touch)
return true
}
override public func endTracking(_ touch: UITouch?, with event: UIEvent?) {
super.endTracking(touch, with: event)
shrinkIndicator()
}
override public func cancelTracking(with event: UIEvent?) {
super.cancelTracking(with: event)
shrinkIndicator()
}
private func changeIndicatorSize(to size: CGFloat) {
let center = self.indicator.center
let size = CGSize(width: size, height: size)
let indicatorRect = CGRect(origin: .zero, size: size)
self.indicator.frame = indicatorRect
self.indicator.center = center
}
private func growIndicator() {
UIView.animate(withDuration: 0.15, delay: 0.0, options: [.curveEaseIn], animations: {
self.changeIndicatorSize(to: self.indicatorSizeActive)
}) { (finished) in
}
}
private func shrinkIndicator() {
UIView.animate(withDuration: 0.15, delay: 0.0, options: [.curveEaseOut], animations: {
self.changeIndicatorSize(to: self.indicatorSizeInactive)
self.indicator.setNeedsDisplay()
}) { (finished) in
self.indicator.setNeedsDisplay()
}
}
}

View File

@ -0,0 +1,36 @@
//
// ColorSquareView.swift
// HueKit
//
// Created by Louis D'hauwe on 25/07/2017.
// Copyright © 2017 Silver Fox. All rights reserved.
//
import UIKit
@IBDesignable
class ColorSquareView: UIImageView {
private var drawnHue: CGFloat = 0.0
@IBInspectable
var hue: CGFloat = 0.0 {
didSet {
if abs(drawnHue - hue) <= 1e-10 {
return
}
let cgImage = HSBGen.createSaturationBrightnessSquareContentImageWithHue(hue: self.hue * 360.0)
if let cgImage = cgImage {
self.image = UIImage(cgImage: cgImage)
} else {
assertionFailure("Expected CGImage")
}
drawnHue = hue
}
}
}

View File

@ -0,0 +1,89 @@
//
// SourceColorView.swift
// HueKit
//
// Created by Louis D'hauwe on 30/07/2017.
// Copyright © 2017 Silver Fox. All rights reserved.
//
import Foundation
import UIKit
@IBDesignable
public class SourceColorView: UIControl {
@IBInspectable
public var isTrackingInside: Bool = false {
didSet {
if oldValue != isTrackingInside {
self.setNeedsDisplay()
}
}
}
@IBInspectable
public var dontShrinkWhenPressed: Bool = false {
didSet {
if oldValue != dontShrinkWhenPressed {
self.setNeedsDisplay()
}
}
}
public override func draw(_ rect: CGRect) {
super.draw(rect)
guard isEnabled && isTrackingInside && !dontShrinkWhenPressed else {
return
}
guard let context = UIGraphicsGetCurrentContext() else {
return
}
let bounds = self.bounds
UIColor.white.set()
context.stroke(bounds.insetBy(dx: 1, dy: 1), width: 2)
UIColor.black.set()
UIRectFrame(bounds.insetBy(dx: 2, dy: 2))
}
// MARK: - UIControl overrides
public override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
guard self.isEnabled else {
return false
}
self.isTrackingInside = true
return super.beginTracking(touch, with: event)
}
public override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
let isTrackingInside = self.bounds.contains(touch.location(in: self))
self.isTrackingInside = isTrackingInside
return super.continueTracking(touch, with: event)
}
public override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
self.isTrackingInside = false
super.endTracking(touch, with: event)
}
public override func cancelTracking(with event: UIEvent?) {
self.isTrackingInside = false
super.cancelTracking(with: event)
}
}

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Louis D'hauwe
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.