         }
     }
     
-    // MARK: - Color Preview popup
-    var previewDimension: CGFloat = 32
-    var previewAnimationDuration = 0.15
-    func showPreviewPopup(touch: UITouch) {
-        // Currently, this method needs to be called _after_ updateForTouch
-        // Create the preview view, set shape
-        let preview = UIView(frame: CGRect(x: 0, y: 0, width: previewDimension, height: previewDimension))
-        preview.layer.cornerRadius = previewDimension/2
-        previewView = preview
-        
+    // MARK: - Preview
+    func showPreview(touch: UITouch) {
+		if !previewEnabled { return }
+		
         // Initialize preview in proper position, save frame
         updatePreview(touch)
-        let endFrame = preview.frame
+        let endFrame = previewView.frame
         
         // Get frame for animation, set as current frame to navigate _from_
-        let startFrame = animationPositionForPreview(endFrame)
-        preview.frame = startFrame
-        
-        addSubview(preview)
+        previewView.frame = minimizedRectForRect(endFrame)
+        
+        addSubview(previewView)
         UIView.animateWithDuration(previewAnimationDuration, delay: 0, options: [.BeginFromCurrentState, .CurveEaseInOut], animations: { () -> Void in
-            preview.frame = endFrame
-            preview.layer.cornerRadius = self.previewDimension/2
+            self.previewView.frame = endFrame
 		}, completion: nil)
-        
-        let cornerAnimation = CABasicAnimation(keyPath: "cornerRadius")
-        cornerAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
-        cornerAnimation.fromValue = startFrame.size.height/2
-        cornerAnimation.toValue = previewDimension/2
-        cornerAnimation.duration = previewAnimationDuration
-        preview.layer.addAnimation(cornerAnimation, forKey: "cornerRadius")
     }
     
     func updatePreview(touch: UITouch) {
-        if let preview = previewView {
-            let frame = positionForPreview(touch)
-            preview.frame = frame
-            preview.backgroundColor = color
-        }
-    }
-    
+		if !previewEnabled { return }
+		let frame = positionForPreview(touch)
+		previewView.frame = frame
+		previewView.backgroundColor = color
+    }
+	
     func removePreview() {
-        if let preview = previewView {
-            // Move to bar for animation
-            let endFrame = animationPositionForPreview(preview.frame)
-            
-            UIView.animateWithDuration(previewAnimationDuration, delay: 0, options: [.BeginFromCurrentState, .CurveEaseInOut], animations: { () -> Void in
-                preview.frame = endFrame
-                }, completion: { (completed: Bool) -> Void in
-                    preview.removeFromSuperview()
-                    self.previewView = nil
-            })
-            let cornerAnimation = CABasicAnimation(keyPath: "cornerRadius")
-            cornerAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
-            cornerAnimation.toValue = endFrame.size.height/2
-            cornerAnimation.fromValue = previewDimension/2
-            cornerAnimation.duration = previewAnimationDuration
-            preview.layer.addAnimation(cornerAnimation, forKey: "cornerRadius")
-        }
-    }
-    
+		if !previewEnabled { return }
+		let endFrame = minimizedRectForRect(previewView.frame)
+		UIView.animateWithDuration(previewAnimationDuration, delay: 0, options: [.BeginFromCurrentState, .CurveEaseInOut], animations: { () -> Void in
+			self.previewView.frame = endFrame
+		}, completion: { (completed: Bool) -> Void in
+			self.previewView.removeFromSuperview()
+		})
+    }
+	
     func positionForPreview(touch: UITouch) -> CGRect {
         let location = touch.locationInView(self)
-        
+		
+		var x = -CGFloat(44)
+		var y = location.y
+		
+		// Restrict preview to slider bounds
         if orientation == .Vertical {
-            var y = location.y - (previewDimension/2)
-            // Prevent preview from running past bounds
-            if y < 0 { y = 0}
-            if y + previewDimension > CGRectGetHeight(bounds) {y = CGRectGetHeight(bounds) - previewDimension }
-            
-            let x = -(previewDimension + 8)
-            let frameInBounds = CGRect(x: x, y: y, width: previewDimension, height: previewDimension)
-            return frameInBounds
+			y = max(0, location.y - (previewDimension / 2))
+			y = min(bounds.height - previewDimension, y)
         } else {
-            var x = location.x - (previewDimension/2)
-            // Prevent preview from running past bounds
-            if x < 0 { x = 0}
-            if x+previewDimension > CGRectGetWidth(bounds) { x = CGRectGetWidth(bounds) - previewDimension }
-            
-            let y = -(previewDimension + 8)
-            let frameInBounds = CGRect(x: x, y: y, width: previewDimension, height: previewDimension)
-            return frameInBounds
-        }
-    }
-    
-    func animationPositionForPreview(position: CGRect) -> CGRect {
-        let animationSize: CGFloat = 5.0
-        if orientation == .Vertical {
-            let animationY = position.origin.y + ((previewDimension - animationSize) / 2)
-            let animationFrame = CGRect(x: CGRectGetWidth(bounds) / 2, y: animationY, width: animationSize, height: animationSize)
-            return animationFrame
-        } else {
-            let animationX = position.origin.x + ((previewDimension - animationSize) / 2)
-            let animationFrame = CGRect(x: animationX, y: CGRectGetHeight(bounds) / 2, width: animationSize, height: animationSize)
-            return animationFrame
-        }
+			x = max(0, location.x - (previewDimension / 2))
+			x = min(bounds.width - previewDimension, x)
+        }
+		
+		return CGRect(x: x, y: y, width: previewDimension, height: previewDimension)
+    }
+    
+    func minimizedRectForRect(rect: CGRect) -> CGRect {
+        let minimizedDimension: CGFloat = 5.0
+		let position = orientation == .Vertical ? rect.origin.y : rect.origin.x
+		let minimizedPosition = position + ((previewDimension - minimizedDimension) / 2)
+		let x = orientation == .Vertical ? bounds.width / 2 : minimizedPosition
+		let y = orientation == .Vertical ? minimizedPosition : bounds.height / 2
+		return CGRect(x: x, y: y, width: minimizedDimension, height: minimizedDimension)
     }
 }
+
+// MARK: -
 
 public extension UIColor {
     // Adapted from https://github.com/thisandagain/color

        }
    }
    @IBInspectable public var borderWidth: CGFloat = 1.0 {
        didSet {
            drawLayer.borderWidth = borderWidth
        }
    }
    @IBInspectable public var borderColor: UIColor = UIColor.blackColor() {
        didSet {
            drawLayer.borderColor = borderColor.CGColor
        }
    }
    @IBInspectable public var shadowOpacity: Float = 0.0 {
        didSet {
            drawLayer.shadowOpacity = shadowOpacity
        }
    }
    @IBInspectable public var shadowRadius: CGFloat = 0.0 {
        didSet {
            drawLayer.shadowRadius = shadowRadius
        }
    }
    @IBInspectable public var shadowColor: UIColor = UIColor.clearColor() {
        didSet {
            drawLayer.shadowColor = shadowColor.CGColor
        }
    }
    public var shadowOffset: CGSize = CGSizeMake(0.0, 0.0) {
        didSet {
            drawLayer.shadowOffset = shadowOffset
        }
    }
    @IBInspectable private var shadowOffsetX: CGFloat = 0.0 {
        didSet {
            drawLayer.shadowOffset = CGSizeMake(shadowOffsetX, shadowOffsetY)
        }
    }
    @IBInspectable private var shadowOffsetY: CGFloat = 0.0 {
        didSet {
            drawLayer.shadowOffset = CGSizeMake(shadowOffsetX, shadowOffsetY)
        }
    }
    
    public var orientation: ColorSliderOrientation = .Vertical {
        didSet {
            switch orientation {
            case .Vertical:
                drawLayer.startPoint = CGPointMake(0.5, 1)
                drawLayer.endPoint = CGPointMake(0.5, 0)
            case .Horizontal:
                drawLayer.startPoint = CGPointMake(0, 0.5)
                drawLayer.endPoint = CGPointMake(1, 0.5)
            }
        }
    }
    
    // MARK: Internal properties
    private var drawLayer: CAGradientLayer = CAGradientLayer()
    private var hue: CGFloat = 0.0
    private var lightness: CGFloat = 0.5
    private var previewView: UIView?
    
    // MARK: Initializers
	convenience init() {
        self.init()
        backgroundColor = UIColor.clearColor()
        clipsToBounds = false
    }
    
    public override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor.clearColor()
        clipsToBounds = false
    }
    
    public required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        backgroundColor = UIColor.clearColor()
        clipsToBounds = false
    }
    
    // MARK: UIControl methods
    public override func beginTrackingWithTouch(touch: UITouch, withEvent event: UIEvent?) -> Bool {
        super.beginTrackingWithTouch(touch, withEvent: event)
        
        updateForTouch(touch, modifyHue: true)
        showPreviewPopup(touch)
        
        sendActionsForControlEvents(.TouchDown)
        return true

}

@IBDesignable public class ColorSlider: UIControl {
    public var color: UIColor {
        return UIColor(h: hue, s: 1, l: lightness, alpha: 1)
    }
    
    // MARK: - Settable properties
    public var edgeInsets: UIEdgeInsets = UIEdgeInsetsMake(0, 20, 0, 20) {
        didSet { setNeedsDisplay() }
    }
    @IBInspectable public var cornerRadius: CGFloat = -1.0 {
        didSet {
            drawLayer.cornerRadius = cornerRadius
