             checkboxLayer.frame = checkboxFrame
             
             checkLayer.frame = checkboxFrame
+            checkBgLayer.frame = checkboxFrame
             
             // default setting
+            setPresetStyle(style, baseColor: baseColor)
+        }
+    }
+    var checkboxBorderWidth: CGFloat! = 0.0 {
+        didSet {
+            checkboxLayer.borderWidth = checkboxBorderWidth
+            let rectCornerRadius = (checkboxCornerRadius > checkboxBorderWidth / 2) ? checkboxCornerRadius - checkboxBorderWidth / 2 : 0
+            checkboxLayer.path = CGPathCreateWithRoundedRect(CGRectMake(checkboxBorderWidth / 2, checkboxBorderWidth / 2, checkboxFrame.width - checkboxBorderWidth, checkboxFrame.height - checkboxBorderWidth), rectCornerRadius, rectCornerRadius, nil)
+        }
+    }
+    var checkboxCornerRadius: CGFloat! = 0.0 {
+        didSet {
+            checkboxLayer.cornerRadius = checkboxCornerRadius
+            let rectCornerRadius = (checkboxCornerRadius > checkboxBorderWidth / 2) ? checkboxCornerRadius - checkboxBorderWidth / 2 : 0
+            checkboxLayer.path = CGPathCreateWithRoundedRect(CGRectMake(checkboxBorderWidth / 2, checkboxBorderWidth / 2, checkboxFrame.width - checkboxBorderWidth, checkboxFrame.height - checkboxBorderWidth), rectCornerRadius, rectCornerRadius, nil)
+        }
+    }
+    var checkWidth: CGFloat! {
+        didSet {
+            checkLayer.lineWidth = checkWidth
+            checkLayer.miterLimit = checkWidth
+            checkBgLayer.lineWidth = checkWidth
+            checkBgLayer.miterLimit = checkWidth
+        }
+    }
+    var checkboxBgColor: UIColor! {
+        didSet { checkboxLayer.fillColor = checkboxBgColor.CGColor }
+    }
+    var checkboxBorderColor: UIColor! {
+        didSet { checkboxLayer.borderColor = checkboxBorderColor.CGColor }
+    }
+    var checkColor: UIColor! {
+        didSet { checkLayer.strokeColor = checkColor.CGColor }
+    }
+    var checkBgColor: UIColor! {
+        didSet { checkBgLayer.strokeColor = checkBgColor.CGColor }
+    }
+    
+    private(set) var ratio: CGFloat = 1.0
+    let checkboxLayer: CAShapeLayer! = CAShapeLayer()
+    let checkLayer: CAShapeLayer! = CAShapeLayer()
+    let checkBgLayer: CAShapeLayer! = CAShapeLayer()
+    
+    override var selected: Bool {
+        didSet {
+            if (selected != oldValue) {
+                let strokeStart = CABasicAnimation(keyPath: "strokeStart")
+                let strokeEnd = CABasicAnimation(keyPath: "strokeEnd")
+                if self.selected {
+                    // check animation
+                    strokeStart.fromValue = 0.0
+                    strokeStart.toValue = 0.0
+                    strokeStart.duration = 0.1
+                    strokeEnd.fromValue = 0.0
+                    strokeEnd.toValue = 1.0
+                    strokeEnd.duration = 0.1
+                } else {
+                    // uncheck animation
+                    strokeStart.fromValue = 0.0
+                    strokeStart.toValue = 1.0
+                    strokeStart.duration = 0.1
+                    strokeEnd.fromValue = 1.0
+                    strokeEnd.toValue = 1.0
+                    strokeEnd.duration = 0.1
+                    strokeEnd.fillMode = kCAFillModeBackwards
+                }
+                self.checkLayer.ocb_applyAnimation(strokeStart)
+                self.checkLayer.ocb_applyAnimation(strokeEnd)
+            }
+        }
+    }
+    
+    required init(coder aDecoder: NSCoder) {
+        super.init(coder: aDecoder)
+    }
+    
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        layout(frame, checkboxFrame: CGRectMake(0, 0, frame.width, frame.height))
+    }
+    
+    init(frame: CGRect, checkboxFrame: CGRect) {
+        super.init(frame: frame)
+        layout(frame, checkboxFrame: checkboxFrame)
+    }
+    
+    func layout(frame: CGRect, checkboxFrame: CGRect) {
+        
+        // checkbox
+        self.checkboxFrame = checkboxFrame
+        checkboxLayer.masksToBounds = true
+        self.layer.addSublayer(checkboxLayer)
+        
+        // background check
+        checkBgLayer.fillColor = nil
+        checkBgLayer.masksToBounds = true
+        checkBgLayer.strokeStart = 0.0
+        checkBgLayer.strokeEnd = 1.0
+        self.layer.addSublayer(checkBgLayer)
+        
+        // check
+        checkLayer.fillColor = nil
+        checkLayer.masksToBounds = true
+        checkLayer.actions = ["strokeStart": NSNull(), "strokeEnd": NSNull()]
+        checkLayer.strokeStart = 0.0
+        checkLayer.strokeEnd = 0.0
+        self.layer.addSublayer(checkLayer)
+        
+        // add target for TouchUpInside event
+        self.addTarget(self, action: "toggleSelected:", forControlEvents:.TouchUpInside)
+    }
+    
+    func toggleSelected(sender: AnyObject) {
+        self.selected = !self.selected
+    }
+    
+    func setPresetStyle(style: DOCheckboxStyle?, baseColor: UIColor?) {
+        if (style != nil) {
+            self.style = style!
+        }
+        if (baseColor != nil) {
+            self.baseColor = baseColor!
+        }
+        
+        // checkbox
+        switch (self.style!) {
+        case .Default, .Square, .SquareFill:
+            checkboxBorderWidth = round(5 * ratio * 10) / 10
+            checkboxCornerRadius = 0
+            
+        case .RoundedSquare, .RoundedSquareFill:
+            checkboxBorderWidth = round(5 * ratio * 10) / 10
+            checkboxCornerRadius = round(15 * ratio * 10) / 10
+            
+        case .Circle, .CircleFill:
+            checkboxBorderWidth = round(5 * ratio * 10) / 10
+            checkboxCornerRadius = round(50 * ratio * 10) / 10
+        }
+        
+        // check
+        switch (self.style!) {
+        case .Default, .Square, .SquareFill, .RoundedSquare, .RoundedSquareFill, .Circle, .CircleFill:
+            checkWidth = round(15 * ratio * 10) / 10
+            checkBgLayer.path = {
+                let path = CGPathCreateMutable()
+                CGPathMoveToPoint(path, nil, 27 * self.ratio, 53 * self.ratio)
+                CGPathAddLineToPoint(path, nil, 42 * self.ratio, 68 * self.ratio)
+                CGPathAddLineToPoint(path, nil, 75 * self.ratio, 34 * self.ratio)
+                return path
+                }()
+            checkBgLayer.lineCap = kCALineCapSquare
+            checkBgLayer.lineJoin = kCALineJoinMiter
             checkLayer.path = {
                 let path = CGPathCreateMutable()
                 CGPathMoveToPoint(path, nil, 27 * self.ratio, 53 * self.ratio)

                CGPathAddLineToPoint(path, nil, 75 * self.ratio, 34 * self.ratio)
                return path
                }()
            checkboxBackgroundColor = UIColor.whiteColor()
            checkboxBorderColor = UIColor(red: 100/255, green: 100/255, blue: 100/255, alpha: 1.0)
            checkboxBorderWidth = 5 * ratio
            checkboxCornerRadius = 15 * ratio
            checkColor = UIColor(red: 100/255, green: 100/255, blue: 100/255, alpha: 1.0)
            checkWidth = 15 * ratio
        }
    }
    var checkboxBorderWidth: CGFloat! = 0.0 {
        didSet {
            println("checkboxBorderWidth didSet")
            checkboxLayer.borderWidth = checkboxBorderWidth
            let rectCornerRadius = (checkboxCornerRadius > checkboxBorderWidth / 2) ? checkboxCornerRadius - checkboxBorderWidth / 2 : 0
            checkboxLayer.path = CGPathCreateWithRoundedRect(CGRectMake(checkboxBorderWidth / 2, checkboxBorderWidth / 2, checkboxFrame.width - checkboxBorderWidth, checkboxFrame.height - checkboxBorderWidth), rectCornerRadius, rectCornerRadius, nil)
        }
    }
    var checkboxCornerRadius: CGFloat! = 0.0 {
        didSet {
            println("checkboxCornerRadius didSet")
            checkboxLayer.cornerRadius = checkboxCornerRadius
            let rectCornerRadius = (checkboxCornerRadius > checkboxBorderWidth / 2) ? checkboxCornerRadius - checkboxBorderWidth / 2 : 0
            checkboxLayer.path = CGPathCreateWithRoundedRect(CGRectMake(checkboxBorderWidth / 2, checkboxBorderWidth / 2, checkboxFrame.width - checkboxBorderWidth, checkboxFrame.height - checkboxBorderWidth), rectCornerRadius, rectCornerRadius, nil)
        }
    }
    var checkWidth: CGFloat! {
        didSet {
            checkLayer.lineWidth = checkWidth
            checkLayer.miterLimit = checkWidth
        }
    }
    var checkboxBackgroundColor: UIColor! {
        didSet {
            checkboxLayer.fillColor = checkboxBackgroundColor.CGColor
        }
    }
    var checkboxBorderColor: UIColor! {
        didSet {
            checkboxLayer.borderColor = checkboxBorderColor.CGColor
        }
    }
    var checkColor: UIColor! {
        didSet {
            checkLayer.strokeColor = checkColor.CGColor
        }
    }
    
    private(set) var ratio: CGFloat = 1.0
    let checkLayer: CAShapeLayer! = CAShapeLayer()
    let checkboxLayer: CAShapeLayer! = CAShapeLayer()
    
    override var selected: Bool {
        didSet {
            let strokeEnd = CABasicAnimation(keyPath: "strokeEnd")
            if self.selected {
                strokeEnd.toValue = 1.0
                strokeEnd.duration = 0.1
            } else {
                strokeEnd.toValue = 0.0
                strokeEnd.duration = 0.1
                strokeEnd.fillMode = kCAFillModeBackwards
            }
            self.checkLayer.ocb_applyAnimation(strokeEnd)
        }
    }
    
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        layout(frame, checkboxFrame: CGRectMake(0, 0, frame.width, frame.height))
    }
    
    init(frame: CGRect, checkboxFrame: CGRect) {
        super.init(frame: frame)
        layout(frame, checkboxFrame: checkboxFrame)
    }
    
    func layout(frame: CGRect, checkboxFrame: CGRect) {
        
        // checkbox
        self.checkboxFrame = checkboxFrame
        checkboxLayer.masksToBounds = true
        self.layer.addSublayer(checkboxLayer)
        
        // check
        checkLayer.fillColor = nil
        checkLayer.lineCap = kCALineCapSquare //kCALineCapRound
        checkLayer.lineJoin = kCALineJoinMiter //kCALineJoinRound
        checkLayer.masksToBounds = true
        checkLayer.actions = ["strokeEnd": NSNull()]
        checkLayer.strokeStart = 0.0
        checkLayer.strokeEnd = 0.0
        self.layer.addSublayer(checkLayer)
        
        // add target for TouchUpInside event
        self.addTarget(nil, action: "switchSelected", forControlEvents:.TouchUpInside)
    }
    
    // switch selected
    func switchSelected() {
        self.selected = !self.selected
    }
}


import UIKit

enum DOCheckboxStyle : Int {
    case Default // Rect
    case Square
    case SquareFill
    case RoundedSquare
    case RoundedSquareFill
    case Circle
    case CircleFill
}

class DOCheckbox: UIButton {
    
    private var style: DOCheckboxStyle! = .Default
    private var baseColor: UIColor = UIColor.blackColor()
    
    var checkboxFrame: CGRect! {
        didSet {
            // reset checkbox
            let ratioW = checkboxFrame.width / 100.0
            let ratioH = checkboxFrame.height / 100.0
            ratio = (ratioW > ratioH) ? ratioH : ratioW
