diff --git a/Cluster.xcodeproj/project.pbxproj b/Cluster.xcodeproj/project.pbxproj index 3dc8802..b95077f 100644 --- a/Cluster.xcodeproj/project.pbxproj +++ b/Cluster.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ 8BFA2B801E9F7184001A80FB /* Cluster.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFA2B5F1E9F7149001A80FB /* Cluster.framework */; }; 8BFA2B811E9F7184001A80FB /* Cluster.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8BFA2B5F1E9F7149001A80FB /* Cluster.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 8BFA2B861E9F71BD001A80FB /* Cluster.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BFA2B851E9F71BD001A80FB /* Cluster.swift */; }; + BFD7F1C72983CD71005A30E7 /* NSTextField+TextProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF18053D2983881100BBDC9D /* NSTextField+TextProperty.swift */; }; F45EDCB2234F9DF700A6270D /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = F45EDCB1234F9DF700A6270D /* Atomic.swift */; }; F4619D1B216C95FC00018B20 /* AnnotationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4619D1A216C95FC00018B20 /* AnnotationView.swift */; }; F4AF970720F5EF1C008DB4E5 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4AF970620F5EF1C008DB4E5 /* Tests.swift */; }; @@ -86,6 +87,7 @@ 8BFA2B7A1E9F715B001A80FB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 8BFA2B7C1E9F715B001A80FB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8BFA2B851E9F71BD001A80FB /* Cluster.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cluster.swift; sourceTree = ""; }; + BF18053D2983881100BBDC9D /* NSTextField+TextProperty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTextField+TextProperty.swift"; sourceTree = ""; }; F45EDCB1234F9DF700A6270D /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = ""; }; F4619D1A216C95FC00018B20 /* AnnotationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnnotationView.swift; sourceTree = ""; }; F4AF970420F5EF1C008DB4E5 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -153,6 +155,7 @@ 8B65CB031EA30BAB00753706 /* Extensions.swift */, 8BFA2B631E9F7149001A80FB /* Info.plist */, 8B03BCAF1EBE8A1500CC9EED /* QuadTree.swift */, + BF18053D2983881100BBDC9D /* NSTextField+TextProperty.swift */, ); name = Cluster; path = Sources; @@ -336,6 +339,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + BFD7F1C72983CD71005A30E7 /* NSTextField+TextProperty.swift in Sources */, 8BFA2B861E9F71BD001A80FB /* Cluster.swift in Sources */, 8B5335101EA2C723005C0A31 /* Annotation.swift in Sources */, 8B03BCB01EBE8A1500CC9EED /* QuadTree.swift in Sources */, @@ -547,7 +551,11 @@ PRODUCT_BUNDLE_IDENTIFIER = com.efremidze.Cluster; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTS_MACCATALYST = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; @@ -571,6 +579,10 @@ PRODUCT_BUNDLE_IDENTIFIER = com.efremidze.Cluster; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTS_MACCATALYST = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; }; diff --git a/Package.swift b/Package.swift index 1c96b66..c611e81 100644 --- a/Package.swift +++ b/Package.swift @@ -6,7 +6,8 @@ import PackageDescription let package = Package( name: "Cluster", platforms: [ - .iOS(.v8) + .iOS(.v8), + .macOS(.v10_13) ], products: [ // Products define the executables and libraries produced by a package, and make them visible to other packages. diff --git a/Sources/Annotation.swift b/Sources/Annotation.swift index 141883f..a3bf979 100755 --- a/Sources/Annotation.swift +++ b/Sources/Annotation.swift @@ -7,6 +7,14 @@ // import MapKit +#if os(macOS) +import Cocoa +public typealias CommonColor = NSColor +public typealias CommonImage = NSImage +#elseif os(iOS) +public typealias CommonColor = UIColor +public typealias CommonImage = UIImage +#endif open class Annotation: MKPointAnnotation { // @available(swift, obsoleted: 6.0, message: "Please migrate to StyledClusterAnnotationView.") @@ -44,6 +52,7 @@ open class ClusterAnnotation: Annotation { The view associated with your cluster annotations. */ open class ClusterAnnotationView: MKAnnotationView { + #if os(iOS) open lazy var countLabel: UILabel = { let label = UILabel() label.autoresizingMask = [.flexibleWidth, .flexibleHeight] @@ -57,6 +66,27 @@ open class ClusterAnnotationView: MKAnnotationView { self.addSubview(label) return label }() + #endif + + #if os(macOS) + open lazy var countLabel: NSTextField = { + let label = NSTextField() + label.font = .boldSystemFont(ofSize: 13) + label.textColor = .white + label.drawsBackground = false + label.isSelectable = false + label.isEditable = false + label.isBezeled = false + label.alignment = .center + label.maximumNumberOfLines = 1 + label.preferredMaxLayoutWidth = self.frame.width + label.translatesAutoresizingMaskIntoConstraints = false + self.addSubview(label) + NSLayoutConstraint(item: label, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0).isActive = true + NSLayoutConstraint(item: label, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: -1).isActive = true + return label + }() + #endif open override var annotation: MKAnnotation? { didSet { @@ -81,12 +111,12 @@ public enum ClusterAnnotationStyle { - `color`: The color of the annotation circle - `radius`: The radius of the annotation circle */ - case color(UIColor, radius: CGFloat) + case color(CommonColor, radius: CGFloat) /** Displays the annotation as an image. */ - case image(UIImage?) + case image(CommonImage?) } /** @@ -142,14 +172,45 @@ open class StyledClusterAnnotationView: ClusterAnnotationView { } } - override open func layoutSubviews() { - super.layoutSubviews() - + // macOS's layer is optional, unlike iOS. + private func getLayer() -> CALayer? { + return layer + } + + private func layoutView() { if case .color = style { - layer.masksToBounds = true - layer.cornerRadius = image == nil ? bounds.width / 2 : 0 + getLayer()?.masksToBounds = true + getLayer()?.cornerRadius = image == nil ? bounds.width / 2 : 0 + #if os(iOS) countLabel.frame = bounds + #endif } } + #if os(iOS) + override open func layoutSubviews() { + super.layoutSubviews() + + self.layoutView() + } + #endif + + #if os(macOS) + open override func layout() { + super.layout() + + self.layoutView() + } + + var _backgroundColor = NSColor.clear + var backgroundColor: NSColor { + get { + return _backgroundColor + } + set { + getLayer()?.backgroundColor = newValue.cgColor + _backgroundColor = newValue + } + } + #endif } diff --git a/Sources/Cluster.h b/Sources/Cluster.h index e5585c2..ea6f4b7 100644 --- a/Sources/Cluster.h +++ b/Sources/Cluster.h @@ -6,7 +6,7 @@ // Copyright © 2017 efremidze. All rights reserved. // -#import +#import //! Project version number for Cluster. FOUNDATION_EXPORT double ClusterVersionNumber; diff --git a/Sources/NSTextField+TextProperty.swift b/Sources/NSTextField+TextProperty.swift new file mode 100644 index 0000000..5c369ae --- /dev/null +++ b/Sources/NSTextField+TextProperty.swift @@ -0,0 +1,22 @@ +// +// NSTextField+TextProperty.swift +// Cluster-Mac +// +// Created by Vincent Neo on 27/1/23. +// Copyright © 2023 efremidze. All rights reserved. +// + +#if os(macOS) +import Cocoa + +extension NSTextField { + public var text: String { + get { + return self.stringValue + } + set { + self.stringValue = newValue + } + } +} +#endif