// // GridViewController.swift // CapCollector // // Created by Christoph on 07.01.19. // Copyright © 2019 CH. All rights reserved. // import UIKit class GridViewController: UIViewController { private let columns = 40 static let len: CGFloat = 60 private lazy var rowHeight = GridViewController.len * 0.866 private lazy var margin = GridViewController.len - rowHeight private var myView: UIView! private var canvasSize: CGSize = .zero @IBOutlet weak var scrollView: UIScrollView! private var selectedTile: Int? = nil private weak var selectionView: RoundedButton! override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return .portrait } override var shouldAutorotate: Bool { return true } override func viewDidLoad() { super.viewDidLoad() let width = CGFloat(columns) * GridViewController.len + GridViewController.len / 2 let height = (CGFloat(Cap.totalCapCount) / CGFloat(columns)).rounded(.up) * rowHeight + margin canvasSize = CGSize(width: width, height: height) myView = UIView(frame: CGRect(origin: .zero, size: canvasSize)) scrollView.addSubview(myView) scrollView.contentSize = canvasSize scrollView.delegate = self scrollView.zoomScale = 0.5 scrollView.maximumZoomScale = 1 setZoomRange() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) updateTiles() let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap)) myView.addGestureRecognizer(tapRecognizer) } override func viewDidLayoutSubviews() { setZoomRange() updateTiles() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) Cap.save() } private func setZoomRange() { let size = scrollView.frame.size let a = size.width / canvasSize.width let b = size.height / canvasSize.height let scale = min(a,b) scrollView.minimumZoomScale = min(a,b) if scrollView.zoomScale < scale { scrollView.setZoomScale(scale, animated: true) } } @objc func handleTap(_ sender: UITapGestureRecognizer) { let loc = sender.location(in: myView) let y = loc.y let s = y.truncatingRemainder(dividingBy: rowHeight) let row = Int(y / rowHeight) guard s > margin else { return } let column: CGFloat if row.isEven { column = loc.x / GridViewController.len } else { column = (loc.x - GridViewController.len / 2) / GridViewController.len } handleTileTapped(tile: row * columns + Int(column)) } private func handleTileTapped(tile: Int) { if let selected = selectedTile { switchTiles(oldTile: selected, newTile: tile) } else { showSelection(tile: tile) } } private var installedTiles = [Int : RoundedImageView]() private func showSelection(tile: Int) { clearTileSelection() if let view = installedTiles[tile] { view.borderWidth = 3 view.borderColor = AppDelegate.tintColor selectedTile = tile } else { selectedTile = nil } } private func tileIsVisible(tile: Int, in rect: CGRect) -> Bool { return rect.intersects(frame(for: tile)) } private func makeTile(_ tile: Int) { let view = RoundedImageView(frame: frame(for: tile)) myView.addSubview(view) view.image = Cap.tileImage(tile: tile) installedTiles[tile] = view } private func frame(for tile: Int) -> CGRect { let row = tile / columns let column = tile - row * columns let x = CGFloat(column) * GridViewController.len + (row.isEven ? 0 : GridViewController.len / 2) let y = CGFloat(row) * rowHeight return CGRect(x: x, y: y, width: GridViewController.len, height: GridViewController.len) } private func switchTiles(oldTile: Int, newTile: Int) { if oldTile != newTile { Cap.switchTiles(oldTile, newTile) installedTiles[oldTile]?.image = Cap.tileImage(tile: oldTile) installedTiles[newTile]?.image = Cap.tileImage(tile: newTile) } clearTileSelection() } private func clearTileSelection() { guard let tile = selectedTile else { return } installedTiles[tile]?.borderWidth = 0 selectedTile = nil } private func showTiles(in rect: CGRect) { for i in 0.. UIView? { return myView } func scrollViewDidScroll(_ scrollView: UIScrollView) { updateTiles() } } private extension Int { var isEven: Bool { return self % 2 == 0 } } extension GridViewController: Logger { static let logToken: String = "[Grid]" }