diff --git a/MenubarCountdown.xcodeproj/project.pbxproj b/MenubarCountdown.xcodeproj/project.pbxproj index 852246d..f14c96b 100644 --- a/MenubarCountdown.xcodeproj/project.pbxproj +++ b/MenubarCountdown.xcodeproj/project.pbxproj @@ -8,8 +8,6 @@ /* Begin PBXBuildFile section */ 4E48658E1BEE6CE500C159BF /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E48658D1BEE6CE500C159BF /* Log.swift */; }; - 4E4865911BEE703A00C159BF /* MenubarIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 4E48658F1BEE703A00C159BF /* MenubarIcon.png */; }; - 4E4865921BEE703A00C159BF /* MenubarIconInverse.png in Resources */ = {isa = PBXBuildFile; fileRef = 4E4865901BEE703A00C159BF /* MenubarIconInverse.png */; }; 4E4865941BEE705E00C159BF /* UserDefaults.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4E4865931BEE705E00C159BF /* UserDefaults.plist */; }; 4E4865961BEE721C00C159BF /* CATransactionExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4865951BEE721C00C159BF /* CATransactionExtensions.swift */; }; 4E4865981BEE749E00C159BF /* StartTimerDialogController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4865971BEE749E00C159BF /* StartTimerDialogController.swift */; }; @@ -29,7 +27,6 @@ 4EB204401BED89F900D83EF3 /* MenubarCountdownUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB2043F1BED89F900D83EF3 /* MenubarCountdownUITests.swift */; }; 4EB2044E1BED908300D83EF3 /* Stopwatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB2044D1BED908300D83EF3 /* Stopwatch.swift */; }; 4EB204501BEE29D700D83EF3 /* AppUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB2044F1BEE29D700D83EF3 /* AppUserDefaults.swift */; }; - 4EB204521BEE2E8B00D83EF3 /* StatusItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB204511BEE2E8B00D83EF3 /* StatusItemView.swift */; }; 4EB204541BEE307900D83EF3 /* CALayerExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EB204531BEE307900D83EF3 /* CALayerExtensions.swift */; }; /* End PBXBuildFile section */ @@ -52,8 +49,6 @@ /* Begin PBXFileReference section */ 4E48658D1BEE6CE500C159BF /* Log.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = ""; }; - 4E48658F1BEE703A00C159BF /* MenubarIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = MenubarIcon.png; sourceTree = ""; }; - 4E4865901BEE703A00C159BF /* MenubarIconInverse.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = MenubarIconInverse.png; sourceTree = ""; }; 4E4865931BEE705E00C159BF /* UserDefaults.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = UserDefaults.plist; sourceTree = ""; }; 4E4865951BEE721C00C159BF /* CATransactionExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CATransactionExtensions.swift; sourceTree = ""; }; 4E4865971BEE749E00C159BF /* StartTimerDialogController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StartTimerDialogController.swift; sourceTree = ""; }; @@ -81,7 +76,6 @@ 4EB204411BED89F900D83EF3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4EB2044D1BED908300D83EF3 /* Stopwatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Stopwatch.swift; sourceTree = ""; }; 4EB2044F1BEE29D700D83EF3 /* AppUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppUserDefaults.swift; sourceTree = ""; }; - 4EB204511BEE2E8B00D83EF3 /* StatusItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusItemView.swift; sourceTree = ""; }; 4EB204531BEE307900D83EF3 /* CALayerExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CALayerExtensions.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -136,8 +130,6 @@ children = ( 4E4865A81BEFA07300C159BF /* MenuTimerIcon.icns */, 4EB204261BED89F900D83EF3 /* Assets.xcassets */, - 4E48658F1BEE703A00C159BF /* MenubarIcon.png */, - 4E4865901BEE703A00C159BF /* MenubarIconInverse.png */, ); name = "Image Resources"; sourceTree = ""; @@ -184,7 +176,6 @@ 4E48659F1BEE85D200C159BF /* MenubarCountdown-Bridging-Header.h */, 4E4865B11BEFC63700C159BF /* StartTimerDialog.xib */, 4E4865971BEE749E00C159BF /* StartTimerDialogController.swift */, - 4EB204511BEE2E8B00D83EF3 /* StatusItemView.swift */, 4EB2044D1BED908300D83EF3 /* Stopwatch.swift */, 4E4865AB1BEFA0F000C159BF /* Text Resources */, 4E4865991BEE79EA00C159BF /* TextField.swift */, @@ -317,13 +308,11 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4E4865921BEE703A00C159BF /* MenubarIconInverse.png in Resources */, 4E4865941BEE705E00C159BF /* UserDefaults.plist in Resources */, 4E4865A91BEFA07300C159BF /* MenuTimerIcon.icns in Resources */, 4E4865B51BEFC63700C159BF /* TimerExpiredAlert.xib in Resources */, 4EB204271BED89F900D83EF3 /* Assets.xcassets in Resources */, 4E4865B41BEFC63700C159BF /* StartTimerDialog.xib in Resources */, - 4E4865911BEE703A00C159BF /* MenubarIcon.png in Resources */, 4E4865B31BEFC63700C159BF /* MainMenu.xib in Resources */, 4E4865AD1BEFA12A00C159BF /* Credits.rtf in Resources */, ); @@ -350,7 +339,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4EB204521BEE2E8B00D83EF3 /* StatusItemView.swift in Sources */, 4E4865981BEE749E00C159BF /* StartTimerDialogController.swift in Sources */, 4EB204541BEE307900D83EF3 /* CALayerExtensions.swift in Sources */, 4E48659A1BEE79EA00C159BF /* TextField.swift in Sources */, diff --git a/MenubarCountdown/MenubarIcon.png b/MenubarCountdown/MenubarIcon.png deleted file mode 100644 index 57fe213..0000000 Binary files a/MenubarCountdown/MenubarIcon.png and /dev/null differ diff --git a/MenubarCountdown/MenubarIconInverse.png b/MenubarCountdown/MenubarIconInverse.png deleted file mode 100644 index a9c9c01..0000000 Binary files a/MenubarCountdown/MenubarIconInverse.png and /dev/null differ diff --git a/MenubarCountdown/StatusItemView.swift b/MenubarCountdown/StatusItemView.swift deleted file mode 100644 index c93696d..0000000 --- a/MenubarCountdown/StatusItemView.swift +++ /dev/null @@ -1,292 +0,0 @@ -// -// StatusItemView.swift -// MenubarCountdown -// -// Copyright © 2009,2015,2019 Kristopher Johnson. All rights reserved. - -import Cocoa - -/** - Custom view for menu bar status item - - StatusItemView implements the custom view for the menubar status item. - - StatusItemView uses layers to display its content. There are four layers: - - - the background/root layer, which draws the background and hosts the other layers - - the icon layer, which is a 22x22 image displayed in the menu bar - - the highlighted icon layer, which is the inverse to the icon layer, displayed - when the menu is popped up, and hidden otherwise - - the title layer, which displays a string - - The application can switch between displaying the icon and displaying the string - by calling `showIcon` and `showTitle`, respectively. - - The application can cause the title to blink by setting the `isTitleBlinking` property. - */ -class StatusItemView: NSView, NSMenuDelegate, CALayerDelegate { - static let iconPaddingWidth = CGFloat(3) - static let titlePaddingWidth = CGFloat(6) - static let titlePaddingHeight = CGFloat(3) - - var statusItem: NSStatusItem? - - var title: String = "" { - didSet { - if titleLayer != nil { updateTitleLayer() } - if statusItem != nil { updateStatusItemSize() } - } - } - - var isTitleVisible = false - - var isMenuVisible = false - - var isTitleBlinking = false { - didSet { - if titleLayer != nil { - if isTitleBlinking { - titleLayer.addBlinkAnimation() - - } - else { - titleLayer.removeBlinkAnimation() - } - - titleLayer.setNeedsDisplay() - } - } - } - - var backgroundLayer: CALayer! - var titleLayer: CALayer! - var iconLayer: CALayer! - var highlightIconLayer: CALayer! - - // MARK: Initialization - - override init(frame frameRect: NSRect) { - super.init(frame: frameRect) - initializeLayers() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func initializeLayers() { - self.wantsLayer = true - - backgroundLayer = self.layer - - iconLayer = CALayer.newLayerFromImageResource(name: "MenubarIcon.png") - iconLayer.orientBottomLeft() - iconLayer.position = CGPoint(x: StatusItemView.iconPaddingWidth, y: 0.0) - backgroundLayer.addSublayer(iconLayer) - - highlightIconLayer = CALayer.newLayerFromImageResource(name: "MenubarIconInverse.png") - highlightIconLayer.orientBottomLeft() - highlightIconLayer.position = iconLayer.position - highlightIconLayer.isHidden = true - backgroundLayer.addSublayer(highlightIconLayer) - - titleLayer = makeTitleLayer() - backgroundLayer.addSublayer(titleLayer) - } - - // MARK: Drawing - - func showIcon() { - if isTitleVisible { - isTitleVisible = false - titleLayer.isHidden = true - - iconLayer.isHidden = isMenuVisible - highlightIconLayer.isHidden = !isMenuVisible - - updateStatusItemSize() - } - } - - func showTitle() { - if (!isTitleVisible) { - isTitleVisible = true - - iconLayer.isHidden = true - highlightIconLayer.isHidden = true - - updateStatusItemSize() - - titleLayer.isHidden = false - } - } - - func updateStatusItemSize() { - if let statusItem = statusItem { - let currentWidth = statusItem.length - let newWidth = isTitleVisible - ? titleLayer.bounds.size.width - : iconLayer.bounds.size.width - if newWidth != currentWidth { - statusItem.length = newWidth - backgroundLayer.setNeedsDisplay() - } - } - } - - func makeTitleLayer() -> CALayer { - let newLayer = CALayer() - - newLayer.orientBottomLeft() - - let titleBounds = titleBoundingRect() - let desiredWidth = titleBounds.size.width + 2 * StatusItemView.titlePaddingWidth - let desiredHeight = self.bounds.size.height - newLayer.bounds = CGRect(x: 0.0, y: 0.0, width: desiredWidth, height: desiredHeight) - - // drawLayer:inContext: will set the layer's contents - newLayer.delegate = self - newLayer.setNeedsDisplay() - - return newLayer - } - - func updateTitleLayer() { - let newTitleLayer = makeTitleLayer() - - if !isTitleVisible { - newTitleLayer.isHidden = true - } - - // #KJ TODO: what do we do if titleLayer is nil? - if let oldTitleLayer = titleLayer { - titleLayer = newTitleLayer - backgroundLayer.replaceSublayer(oldTitleLayer, with: newTitleLayer) - } - } - - func titleAttributes() -> [NSAttributedString.Key : Any] { - let font = NSFont.monospacedDigitSystemFont(ofSize: 0, weight: .thin) - let foregroundColor = titleForegroundColor() - return [ - NSAttributedString.Key.font: font, - NSAttributedString.Key.foregroundColor: foregroundColor - ] - } - - func titleForegroundColor() -> NSColor { - if isMenuVisible { return NSColor.white } - if isTitleBlinking { return NSColor.red } - else { return NSColor.black } - } - - func titleBoundingRect() -> NSRect { - // TODO: boundingRectWithSize(options:attributes:) is deprecated; replace appropriately - let infiniteSize = NSMakeSize(CGFloat.infinity, CGFloat.infinity) - return (title as NSString).boundingRect(with: infiniteSize, - options: NSString.DrawingOptions(rawValue: 0), - attributes: titleAttributes()) - } - - func draw(_ layer: CALayer, in ctx: CGContext) { - // Set up graphics context so that we can use Application Kit drawing functions - let nsGraphicsContext = NSGraphicsContext(cgContext: ctx, flipped: false) - - NSGraphicsContext.saveGraphicsState() - NSGraphicsContext.current = nsGraphicsContext - - if layer == backgroundLayer { - drawBackground() - } - else if layer == titleLayer { - drawTitle() - } - - NSGraphicsContext.restoreGraphicsState() - } - - func drawBackground() { - if let statusItem = statusItem { - // #KJ TODO: Eliminate use of this deprecated method - statusItem.drawStatusBarBackground(in: self.bounds, withHighlight: isMenuVisible) - } - } - - func drawTitle() { - let position = NSMakePoint( - StatusItemView.titlePaddingWidth, - StatusItemView.titlePaddingHeight) - (title as NSString).draw(at: position, withAttributes: titleAttributes()) - } - - // MARK: Mouse and menu handling - - override func mouseDown(with event: NSEvent) { - if let menu = menu { - menu.delegate = self - if let statusItem = statusItem { - // #KJ TODO: popUpMenu is deprecated - statusItem.popUpMenu(menu) - } - else { - Log.error("statusItem property not set") - } - } - else { - Log.error("menu property not set") - } - } - - override func rightMouseDown(with event: NSEvent) { - // Treat right-click just like left-click - mouseDown(with: event) - } - - func menuWillOpen(_ menu: NSMenu) { - isMenuVisible = true - - // Disable animation for the following changes - // (menu highlighting needs to be instantaneous) - CATransaction.begin() - CATransaction.disableActions() - - // Need to highlight the background - backgroundLayer.setNeedsDisplay() - if isTitleVisible { - // The title's color will change - titleLayer.setNeedsDisplay() - } - else { - // Hide the normal icon and show the highlighted icon - iconLayer.isHidden = true - highlightIconLayer.isHidden = false - } - - CATransaction.commit() - } - - func menuDidClose(_ menu: NSMenu) { - isMenuVisible = false - menu.delegate = nil - - // Disable animation for the following changes - // (menu highlighting needs to be instantaneous) - CATransaction.begin() - CATransaction.disableActions() - - // Unhighlight the background - backgroundLayer.setNeedsDisplay() - - if isTitleVisible { - // Restore title color - titleLayer.setNeedsDisplay() - } - else { - // Show the normal icon and hide the highlighted icon - iconLayer.isHidden = false - highlightIconLayer.isHidden = true - } - - CATransaction.commit() - } -}