<commit_before>//
//  BaseIconLayerButton.swift
//  Material
//
//  Created by <NAME> on 12/22/18.
//  Copyright © 2017 CosmicMind. All rights reserved.
//

import UIKit
import Motion

/// Implements common logic for CheckButton and RadioButton
open class BaseIconLayerButton: Button {
    class var iconLayer: BaseIconLayer { fatalError("Has to be implemented by subclasses") }
    lazy var iconLayer: BaseIconLayer = type(of: self).iconLayer
    
    /// A Boolean value indicating whether the button is in the selected state
    ///
    /// Use `setSelected(_:, animated:)` if the state change needs to be animated
    open override var isSelected: Bool {
        didSet {
            iconLayer.setSelected(isSelected, animated: false)
        }
    }
    
    /// A Boolean value indicating whether the control is enabled.
    open override var isEnabled: Bool {
        didSet {
            iconLayer.isEnabled = isEnabled
        }
    }
    
    
    /// Sets the color of the icon to use for the specified state.
    ///
    /// - Parameters:
    ///   - color: The color of the icon to use for the specified state.
    ///   - state: The state that uses the specified color. Supports only (.normal, .selected, .disabled)
    open func setIconColor(_ color: UIColor, for state: UIControl.State) {
        switch state {
        case .normal:
            iconLayer.normalColor = color
        case .selected:
            iconLayer.selectedColor = color
        case .disabled:
            iconLayer.disabledColor = color
        default:
            fatalError("unsupported state")
        }
    }
    
    /// Returns the icon color used for a state.
    ///
    /// - Parameter state: The state that uses the icon color. Supports only (.normal, .selected, .disabled)
    /// - Returns: The color of the title for the specified state.
    open func iconColor(for state: UIControl.State) -> UIColor {
        switch state {
        case .normal:
            return iconLayer.normalColor
        case .selected:
            return iconLayer.selectedColor
        case .disabled:
            return iconLayer.disabledColor
        default:
            fatalError("unsupported state")
        }
    }
    
    /// A Boolean value indicating whether the button is being animated
    open var isAnimating: Bool { return iconLayer.isAnimating }
    
    
    /// Sets the `selected` state of the button, optionally animating the transition.
    ///
    /// - Parameters:
    ///   - isSelected: A Boolean value indicating new `selected` state
    ///   - animated: true if the state change should be animated, otherwise false.
    open func setSelected(_ isSelected: Bool, animated: Bool) {
        guard !isAnimating else { return }
        iconLayer.setSelected(isSelected, animated: animated)
        self.isSelected = isSelected
    }
    
    open override func prepare() {
        super.prepare()
        layer.addSublayer(iconLayer)
        iconLayer.prepare()
        contentHorizontalAlignment = .left // default was .center
        reloadImage()
    }
    
    open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        // pulse.animation set to .none so that when we call `super.touchesBegan`
        // pulse will not expand as there is a `guard` against .none case
        pulse.animation = .none
        super.touchesBegan(touches, with: event)
        pulse.animation = .point
        
        // expand pulse from the center of iconLayer/visualLayer (`point` is relative to self.view/self.layer)
        pulse.expand(point: iconLayer.frame.center)
    }
    
    open override func layoutSubviews() {
        super.layoutSubviews()
        
        // positioning iconLayer
        let insets = iconEdgeInsets
        iconLayer.frame.size = CGSize(width: iconSize, height: iconSize)
        iconLayer.frame.origin = CGPoint(x: imageView!.frame.minX + insets.left, y: imageView!.frame.minY + insets.top)
        
        // visualLayer is the layer where pulse layer is expanding.
        // So we position it at the center of iconLayer, and make it
        // small circle, so that the expansion of pulse layer is clipped off
        let w = iconSize + insets.left + insets.right
        let h = iconSize + insets.top + insets.bottom
        let pulseSize = min(w, h)
        visualLayer.bounds.size = CGSize(width: pulseSize, height: pulseSize)
        visualLayer.frame.center = iconLayer.frame.center
        visualLayer.cornerRadius = pulseSize / 2
    }
    
    /// Size of the icon
    ///
    /// This property affects `intrinsicContentSize` and `sizeThatFits(_:)`
    /// Use `iconEdgeInsets` to set margins.
    open var iconSize: CGFloat = 16 {
        didSet {
            reloadImage()
        }
    }
    
    /// The *outset* margins for the rectangle around the button’s icon.
    ///
    /// You can specify a different value for each of the four margins (top, left, bottom, right)
    /// This property affects `intrinsicContentSize` and `sizeThatFits(_:)` and position of the icon
    /// within the rectangle.
    ///
    /// You can use `iconSize` and this property, or `titleEdgeInsets` and `contentEdgeInsets` to position
    /// the icon however you want.
    /// For negative values, behavior is undefined. Default is `5.0` for all four margins
    open var iconEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5) {
        didSet {
            reloadImage()
        }
    }
  
  open override func apply(theme: Theme) {
    super.apply(theme: theme)
    
    setIconColor(theme.secondary, for: .selected)
    setIconColor(theme.onSurface.withAlphaComponent(0.38), for: .normal)
    titleColor = theme.onSurface.withAlphaComponent(0.60)
  }
    
    
    /// This might be considered as a hackish way, but it's just manipulation
    /// UIButton considers size of the `currentImage` to determine `intrinsicContentSize`<commit_msg>Adjusted CheckButton and RadioButton icon<commit_after>//
//  BaseIconLayerButton.swift
//  Material
//
//  Created by <NAME> on 12/22/18.
//  Copyright © 2017 CosmicMind. All rights reserved.
//

import UIKit
import Motion

/// Implements common logic for CheckButton and RadioButton
open class BaseIconLayerButton: Button {
    class var iconLayer: BaseIconLayer { fatalError("Has to be implemented by subclasses") }
    lazy var iconLayer: BaseIconLayer = type(of: self).iconLayer
    
    /// A Boolean value indicating whether the button is in the selected state
    ///
    /// Use `setSelected(_:, animated:)` if the state change needs to be animated
    open override var isSelected: Bool {
        didSet {
            iconLayer.setSelected(isSelected, animated: false)
        }
    }
    
    /// A Boolean value indicating whether the control is enabled.
    open override var isEnabled: Bool {
        didSet {
            iconLayer.isEnabled = isEnabled
        }
    }
    
    
    /// Sets the color of the icon to use for the specified state.
    ///
    /// - Parameters:
    ///   - color: The color of the icon to use for the specified state.
    ///   - state: The state that uses the specified color. Supports only (.normal, .selected, .disabled)
    open func setIconColor(_ color: UIColor, for state: UIControl.State) {
        switch state {
        case .normal:
            iconLayer.normalColor = color
        case .selected:
            iconLayer.selectedColor = color
        case .disabled:
            iconLayer.disabledColor = color
        default:
            fatalError("unsupported state")
        }
    }
    
    /// Returns the icon color used for a state.
    ///
    /// - Parameter state: The state that uses the icon color. Supports only (.normal, .selected, .disabled)
    /// - Returns: The color of the title for the specified state.
    open func iconColor(for state: UIControl.State) -> UIColor {
        switch state {
        case .normal:
            return iconLayer.normalColor
        case .selected:
            return iconLayer.selectedColor
        case .disabled:
            return iconLayer.disabledColor
        default:
            fatalError("unsupported state")
        }
    }
    
    /// A Boolean value indicating whether the button is being animated
    open var isAnimating: Bool { return iconLayer.isAnimating }
    
    
    /// Sets the `selected` state of the button, optionally animating the transition.
    ///
    /// - Parameters:
    ///   - isSelected: A Boolean value indicating new `selected` state
    ///   - animated: true if the state change should be animated, otherwise false.
    open func setSelected(_ isSelected: Bool, animated: Bool) {
        guard !isAnimating else { return }
        iconLayer.setSelected(isSelected, animated: animated)
        self.isSelected = isSelected
    }
    
    open override func prepare() {
        super.prepare()
        layer.addSublayer(iconLayer)
        iconLayer.prepare()
        contentHorizontalAlignment = .left // default was .center
        reloadImage()
    }
    
    open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        // pulse.animation set to .none so that when we call `super.touchesBegan`
        // pulse will not expand as there is a `guard` against .none case
        pulse.animation = .none
        super.touchesBegan(touches, with: event)
        pulse.animation = .point
        
        // expand pulse from the center of iconLayer/visualLayer (`point` is relative to self.view/self.layer)
        pulse.expand(point: iconLayer.frame.center)
    }
    
    open override func layoutSubviews() {
        super.layoutSubviews()
        
        // positioning iconLayer
        let insets = iconEdgeInsets
        iconLayer.frame.size = CGSize(width: iconSize, height: iconSize)
        iconLayer.frame.origin = CGPoint(x: imageView!.frame.minX + insets.left, y: imageView!.frame.minY + insets.top)
        
        // visualLayer is the layer where pulse layer is expanding.
        // So we position it at the center of iconLayer, and make it
        // small circle, so that the expansion of pulse layer is clipped off
        let w = iconSize + insets.left + insets.right
        let h = iconSize + insets.top + insets.bottom
        let pulseSize = min(w, h)
        visualLayer.bounds.size = CGSize(width: pulseSize, height: pulseSize)
        visualLayer.frame.center = iconLayer.frame.center
        visualLayer.cornerRadius = pulseSize / 2
    }
    
    /// Size of the icon
    ///
    /// This property affects `intrinsicContentSize` and `sizeThatFits(_:)`
    /// Use `iconEdgeInsets` to set margins.
    open var iconSize: CGFloat = 18 {
        didSet {
            reloadImage()
        }
    }
    
    /// The *outset* margins for the rectangle around the button’s icon.
    ///
    /// You can specify a different value for each of the four margins (top, left, bottom, right)
    /// This property affects `intrinsicContentSize` and `sizeThatFits(_:)` and position of the icon
    /// within the rectangle.
    ///
    /// You can use `iconSize` and this property, or `titleEdgeInsets` and `contentEdgeInsets` to position
    /// the icon however you want.
    /// For negative values, behavior is undefined. Default is `8.0` for all four margins
    open var iconEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) {
        didSet {
            reloadImage()
        }
    }
  
  open override func apply(theme: Theme) {
    super.apply(theme: theme)
    
    setIconColor(theme.secondary, for: .selected)
    setIconColor(theme.onSurface.withAlphaComponent(0.38), for: .normal)
    titleColor = theme.onSurface.withAlphaComponent(0.60)
  }
    
    
    /// This might be considered as a hackish way, but it's just manipulation
    /// UIButton considers size of the `currentImage` to determine `intrinsicContentSize`
{'fraction_non_alphanumeric': 0.08974358974358974, 'fraction_numerical': 0.004217273954116059, 'mean_word_length': 2.214150176199512, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '113175', 'n_tokens_mistral': 3252, 'n_tokens_neox': 3157, 'n_words': 1127}