Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c26eb28536 | ||
|
|
9330644f9e | ||
|
|
e672053594 | ||
|
|
ef3ddda8e6 | ||
|
|
b734282b0d | ||
|
|
a343b50916 | ||
|
|
40866ce9f8 | ||
|
|
ffeedffda9 | ||
|
|
46159dd5d4 |
@@ -80,7 +80,7 @@
|
||||
B3B4C2C71E25894B009F8E4E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
BA22232620AFEC1B0001069C /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = System/Library/Frameworks/ApplicationServices.framework; sourceTree = SDKROOT; };
|
||||
BA22232820B04D660001069C /* AppDelegate+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Menu.swift"; sourceTree = "<group>"; };
|
||||
BA22232A20B0E3B50001069C /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = "/Users/cosmotherly/dev/pixel-picker/README.md"; sourceTree = "<absolute>"; };
|
||||
BA22232A20B0E3B50001069C /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; };
|
||||
BA71817120AE2DB400619700 /* PPMenuShortcutView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PPMenuShortcutView.m; sourceTree = "<group>"; };
|
||||
BA71817320AE2DCC00619700 /* PPMenuShortcutView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PPMenuShortcutView.h; sourceTree = "<group>"; };
|
||||
BA74C0F620A692D100306B27 /* PPOverlayController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PPOverlayController.swift; sourceTree = "<group>"; };
|
||||
@@ -332,18 +332,18 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
BA74C14220AA409D00306B27 /* NSColor.swift in Sources */,
|
||||
BA71817220AE2DB400619700 /* PPMenuShortcutView.m in Sources */,
|
||||
15492103207B53AE00E45BBC /* Util.swift in Sources */,
|
||||
BA74C0F820A692D100306B27 /* PPOverlayController.swift in Sources */,
|
||||
BA74C14E20ADA33E00306B27 /* PPColor.swift in Sources */,
|
||||
BA22232920B04D660001069C /* AppDelegate+Menu.swift in Sources */,
|
||||
BA74C13120A6E95900306B27 /* PPOverlayPanel.swift in Sources */,
|
||||
B3B4C2C11E25894B009F8E4E /* AppDelegate.swift in Sources */,
|
||||
BA74C14420AA609500306B27 /* PPOverlayWrapper.swift in Sources */,
|
||||
BA74C13320A6F16C00306B27 /* ShowAndHideCursor.m in Sources */,
|
||||
BA74C14020AA390400306B27 /* PPOverlayPreview.swift in Sources */,
|
||||
BA71817220AE2DB400619700 /* PPMenuShortcutView.m in Sources */,
|
||||
B3B4C2C11E25894B009F8E4E /* AppDelegate.swift in Sources */,
|
||||
BA22232920B04D660001069C /* AppDelegate+Menu.swift in Sources */,
|
||||
BA74C14E20ADA33E00306B27 /* PPColor.swift in Sources */,
|
||||
15FC8CC8204E2E2C000B5E1E /* PPState.swift in Sources */,
|
||||
BA74C13120A6E95900306B27 /* PPOverlayPanel.swift in Sources */,
|
||||
BA74C14020AA390400306B27 /* PPOverlayPreview.swift in Sources */,
|
||||
BA74C14420AA609500306B27 /* PPOverlayWrapper.swift in Sources */,
|
||||
BA74C0F820A692D100306B27 /* PPOverlayController.swift in Sources */,
|
||||
BA74C14220AA409D00306B27 /* NSColor.swift in Sources */,
|
||||
15492103207B53AE00E45BBC /* Util.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -20,59 +20,116 @@ let concentrationModifiers: [(String, NSEvent.ModifierFlags)] = [
|
||||
]
|
||||
|
||||
extension AppDelegate: NSMenuDelegate {
|
||||
// Unregister/register the activating shortcut when the menu is opened/closed
|
||||
// so it can't be called when setting a new shortcut.
|
||||
func menuWillOpen(_ menu: NSMenu) { unregisterActivatingShortcut() }
|
||||
func menuDidClose(_ menu: NSMenu) { registerActivatingShortcut() }
|
||||
// Unregister the activating shortcut when the menu is opened/closed so it can't be called when
|
||||
// setting a new shortcut. Also start a run loop observer so we know when the modifierFlags have
|
||||
// changed (used to dynamically update the menu).
|
||||
func menuWillOpen(_ menu: NSMenu) {
|
||||
unregisterActivatingShortcut()
|
||||
if runLoopObserver == nil {
|
||||
let activites = CFRunLoopActivity.beforeWaiting.rawValue
|
||||
runLoopObserver = CFRunLoopObserverCreateWithHandler(nil, activites, true, 0, { [unowned self] (_, _) in
|
||||
self.updateMenuItems()
|
||||
})
|
||||
CFRunLoopAddObserver(CFRunLoopGetCurrent(), runLoopObserver, CFRunLoopMode.commonModes)
|
||||
}
|
||||
}
|
||||
|
||||
// Re-register the activating shortcut, and remove the run loop observer.
|
||||
func menuDidClose(_ menu: NSMenu) {
|
||||
registerActivatingShortcut()
|
||||
if (runLoopObserver != nil) {
|
||||
CFRunLoopObserverInvalidate(runLoopObserver)
|
||||
runLoopObserver = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the titles of the recently picked colors - if the `option` key is pressed, then
|
||||
// the colors will be in the format they were *when* they were picked, otherwise they'll be
|
||||
// in the currently chosen format.
|
||||
private func updateMenuItems() {
|
||||
// Update recent picks list with correct titles.
|
||||
let alternate = NSEvent.modifierFlags.contains(.option)
|
||||
for item in contextMenu.items {
|
||||
if let pickedColor = item.representedObject as? PPPickedColor {
|
||||
item.title = alternate
|
||||
? pickedColor.asString
|
||||
: PPState.shared.chosenFormat.asString(withColor: pickedColor.color)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: look into only updating the menu rather than rebuilding it each time.
|
||||
// Might not be worth it - it doesn't seem expensive to build it every time it's opened...
|
||||
func rebuildContextMenu() {
|
||||
contextMenu.removeAllItems()
|
||||
|
||||
|
||||
let pickItem = contextMenu.addItem(withTitle: "Pick a pixel!", action: #selector(showPicker), keyEquivalent: "")
|
||||
pickItem.image = ICON
|
||||
|
||||
|
||||
buildRecentPicks()
|
||||
|
||||
|
||||
contextMenu.addItem(.separator())
|
||||
buildColorFormatsMenu()
|
||||
buildMagnificationItem()
|
||||
buildConcentrationMenu()
|
||||
buildFloatPrecisionSlider()
|
||||
buildShortcutMenuItem()
|
||||
|
||||
let launchAtLoginItem = contextMenu.addItem(withTitle: "Launch \(APP_NAME) at Login", action: #selector(launchAtLogin(_:)), keyEquivalent: "")
|
||||
launchAtLoginItem.state = LaunchAtLogin.isEnabled ? .on : .off
|
||||
buildLaunchAtLoginItem()
|
||||
|
||||
contextMenu.addItem(.separator())
|
||||
contextMenu.addItem(withTitle: "About", action: #selector(showAboutPanel), keyEquivalent: "")
|
||||
contextMenu.addItem(withTitle: "Quit \(APP_NAME)", action: #selector(quitApplication), keyEquivalent: "")
|
||||
}
|
||||
|
||||
private func buildMagnificationItem() {
|
||||
let submenu = NSMenu()
|
||||
for i in stride(from: 4, through: 24, by: 2) {
|
||||
let item = submenu.addItem(withTitle: "\(i)x", action: #selector(selectMagnification(_:)), keyEquivalent: "")
|
||||
item.representedObject = i
|
||||
item.state = PPState.shared.magnificationLevel == i ? .on : .off
|
||||
}
|
||||
let item = contextMenu.addItem(withTitle: "Magnification", action: nil, keyEquivalent: "")
|
||||
item.submenu = submenu
|
||||
}
|
||||
|
||||
@objc private func selectMagnification(_ sender: NSMenuItem) {
|
||||
if let level = sender.representedObject as? Int {
|
||||
PPState.shared.magnificationLevel = level
|
||||
}
|
||||
}
|
||||
|
||||
private func buildLaunchAtLoginItem() {
|
||||
let item = contextMenu.addItem(withTitle: "Launch \(APP_NAME) at Login", action: #selector(launchAtLogin(_:)), keyEquivalent: "")
|
||||
item.state = LaunchAtLogin.isEnabled ? .on : .off
|
||||
}
|
||||
|
||||
@objc private func launchAtLogin(_ sender: NSMenuItem) {
|
||||
LaunchAtLogin.isEnabled = !LaunchAtLogin.isEnabled
|
||||
}
|
||||
|
||||
// Show the user's recent picks in the menu.
|
||||
private func buildRecentPicks() {
|
||||
// Recent picks.
|
||||
// TODO: it would be nice to hold the `option` key and have the recent picks show in the
|
||||
// currently chosen format, and when clicked copy in that format.
|
||||
// https://stackoverflow.com/q/11208632/5552584
|
||||
if PPState.shared.recentPicks.count > 0 {
|
||||
contextMenu.addItem(.separator())
|
||||
contextMenu.addItem(withTitle: "Recently Picked", action: nil, keyEquivalent: "")
|
||||
let format = PPState.shared.chosenFormat
|
||||
for pickedColor in PPState.shared.recentPicks {
|
||||
// TODO: copy to clipboard when clicked, if alt then in current format
|
||||
let item = contextMenu.addItem(withTitle: pickedColor.asString, action: #selector(copyRecentPick(_:)), keyEquivalent: "")
|
||||
let item = contextMenu.addItem(withTitle: format.asString(withColor: pickedColor.color), action: #selector(copyRecentPick(_:)), keyEquivalent: "")
|
||||
item.representedObject = pickedColor
|
||||
item.image = circleImage(withSize: 12, color: pickedColor.color)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Copies the recently picked color (associated with the menu item) to the clipboard.
|
||||
// If the `option` key is pressed, then it copies the color in the same format it was
|
||||
// when it was picked (otherwise, it copies it in the currently chosen format).
|
||||
@objc private func copyRecentPick(_ sender: NSMenuItem) {
|
||||
if let pickedColor = sender.representedObject as? PPPickedColor {
|
||||
copyToPasteboard(stringValue: pickedColor.asString)
|
||||
let value = NSEvent.modifierFlags.contains(.option)
|
||||
? pickedColor.asString
|
||||
: PPState.shared.chosenFormat.asString(withColor: pickedColor.color)
|
||||
copyToPasteboard(stringValue: value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,13 +173,9 @@ extension AppDelegate: NSMenuDelegate {
|
||||
|
||||
// Update state.
|
||||
PPState.shared.floatPrecision = newValue
|
||||
|
||||
|
||||
// Update recent picks list with new precision.
|
||||
for item in contextMenu.items {
|
||||
if let pickedColor = item.representedObject as? PPPickedColor {
|
||||
item.title = pickedColor.asString
|
||||
}
|
||||
}
|
||||
updateMenuItems()
|
||||
}
|
||||
|
||||
// Build a submenu with each case in the PPColor enum.
|
||||
|
||||
@@ -13,10 +13,14 @@ let ICON = setupMenuBarIcon(NSImage(named: NSImage.Name(rawValue: "icon")))
|
||||
|
||||
// This controller manages the pixel picker itself.
|
||||
@IBOutlet weak var overlayController: PPOverlayController!
|
||||
|
||||
var contextMenu: NSMenu = NSMenu()
|
||||
|
||||
// The actual menu bar item.
|
||||
var menuBarItem: NSStatusItem! = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
|
||||
|
||||
// The menu that drops down from the menu bar item.
|
||||
var contextMenu: NSMenu = NSMenu()
|
||||
// When the menu bar is opened, we observe the run loop for changes in modifierFlags.
|
||||
var runLoopObserver: CFRunLoopObserver? = nil
|
||||
|
||||
// Setup logging and load state.
|
||||
func applicationWillFinishLaunching(_ notification: Notification) {
|
||||
let minimumSeverity: LogSeverity = PPState.shared.defaults.bool(forKey: "debugMode") ? .debug : .info
|
||||
@@ -37,22 +41,28 @@ let ICON = setupMenuBarIcon(NSImage(named: NSImage.Name(rawValue: "icon")))
|
||||
menuBarItem.image = ICON
|
||||
menuBarItem.action = #selector(onMenuClick)
|
||||
menuBarItem.sendAction(on: [.leftMouseUp, .rightMouseUp])
|
||||
|
||||
|
||||
registerActivatingShortcut()
|
||||
|
||||
// Set the CGEventSource.localEventsSuppressionInterval to a small interval (default: 250ms)
|
||||
// otherwise there'll be a delay when we re-associate the mouse input with the mouse cursor
|
||||
// (in the picker) that makes it feel laggy (the suppression interval controls how long
|
||||
// hardware events are suppressed after functions like CGWarpMouseCursorPosition are used.
|
||||
CGEventSource(stateID: CGEventSourceStateID.combinedSessionState)?.localEventsSuppressionInterval = 0.05
|
||||
|
||||
Log.info?.message("Sucessfully launched.")
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ aNotification: Notification) {
|
||||
PPState.shared.saveToDisk()
|
||||
}
|
||||
|
||||
|
||||
func registerActivatingShortcut() {
|
||||
if let shortcut = PPState.shared.activatingShortcut {
|
||||
MASShortcutMonitor.shared().register(shortcut, withAction: showPicker)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func unregisterActivatingShortcut() {
|
||||
MASShortcutMonitor.shared().unregisterShortcut(PPState.shared.activatingShortcut)
|
||||
}
|
||||
@@ -61,7 +71,7 @@ let ICON = setupMenuBarIcon(NSImage(named: NSImage.Name(rawValue: "icon")))
|
||||
let leftClickToggles = PPState.shared.defaults.bool(forKey: "leftClickActivates")
|
||||
let pickerEvent: NSEvent.EventType = leftClickToggles ? .leftMouseUp : .rightMouseUp
|
||||
let dropdownEvent: NSEvent.EventType = leftClickToggles ? .rightMouseUp : .leftMouseUp
|
||||
|
||||
|
||||
let event = NSApp.currentEvent!
|
||||
if event.type == dropdownEvent {
|
||||
rebuildContextMenu()
|
||||
@@ -70,7 +80,7 @@ let ICON = setupMenuBarIcon(NSImage(named: NSImage.Name(rawValue: "icon")))
|
||||
showPicker()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@objc func showPicker() {
|
||||
overlayController.showPicker()
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
}
|
||||
{\colortbl;\red255\green255\blue255;\red0\green0\blue0;\red230\green230\blue230;}
|
||||
{\*\expandedcolortbl;;\cssrgb\c0\c0\c0;\csgray\c92143;}
|
||||
\paperw12240\paperh15840\margl1440\margr1440\vieww12800\viewh10340\viewkind0
|
||||
\margl1440\margr1440\vieww12800\viewh10340\viewkind0
|
||||
\deftab720
|
||||
\pard\pardeftab720\qc\partightenfactor0
|
||||
|
||||
@@ -27,8 +27,9 @@
|
||||
\pard\pardeftab720\qc\partightenfactor0
|
||||
{\field{\*\fldinst{HYPERLINK "https://github.com/SwiftyJSON/SwiftyJSON"}}{\fldrslt \cf2 SwiftyJSON}}\
|
||||
\
|
||||
\pard\pardeftab720\qc\partightenfactor0
|
||||
|
||||
\b\fs36 Experimental Overrides
|
||||
\b\fs36 \cf2 Experimental Overrides
|
||||
\b0 \
|
||||
\pard\pardeftab720\qc\partightenfactor0
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<string>1.0.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<string>2</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
@@ -19,18 +19,16 @@ class PPOverlayController: NSWindowController {
|
||||
@IBOutlet weak var infoFormatField: NSTextField!
|
||||
@IBOutlet weak var infoDetailField: NSTextField!
|
||||
|
||||
// The current magnification level of the preview.
|
||||
// TODO: make this somewhat configurable?
|
||||
var magnification: CGFloat = 8.0
|
||||
|
||||
// This mode increases the picker's size, increases the magnification and also
|
||||
// slows down mouseMove events to make it easier to pick the right pixel.
|
||||
// This mode increases the picker's size, increases the magnification and also slows down move
|
||||
// events to make it easier to pick the right pixel. We dissociate the mouse (input) from the
|
||||
// mouse cursor while the concentrationMode is active. This is so we can slow it down.
|
||||
var concentrationMode: Bool = false {
|
||||
didSet {
|
||||
if isEnabled {
|
||||
panelSize = concentrationMode ? 300 : 150
|
||||
overlayPanel.activate(withSize: panelSize, infoPanel: infoPanel)
|
||||
wrapper.layer?.cornerRadius = PPState.shared.paschaModeEnabled ? 0 : panelSize / 2
|
||||
CGAssociateMouseAndMouseCursorPosition(boolean_t(truncating: concentrationMode ? 0 : 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,18 +48,14 @@ class PPOverlayController: NSWindowController {
|
||||
private var lastHighlightedColor: NSColor = NSColor.black
|
||||
|
||||
// Whether or not the picker should be actively updating its preview.
|
||||
// We dissociate the mouse (input) from the mouse cursor while the picker is active.
|
||||
// This is so we can slow down the mouse movement during concentration mode.
|
||||
private var isEnabled: Bool = false {
|
||||
didSet {
|
||||
if isEnabled {
|
||||
lastMouseLocation = NSEvent.mouseLocation
|
||||
startMonitoringEvents()
|
||||
CGAssociateMouseAndMouseCursorPosition(boolean_t(truncating: 0))
|
||||
} else {
|
||||
stopMonitoringEvents()
|
||||
concentrationMode = false
|
||||
CGAssociateMouseAndMouseCursorPosition(boolean_t(truncating: 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,24 +112,30 @@ class PPOverlayController: NSWindowController {
|
||||
// slow it down to make it easier to pick the correct pixel.
|
||||
override func mouseMoved(with event: NSEvent) {
|
||||
if isEnabled {
|
||||
let speed: CGFloat = concentrationMode ? 0.1 : 0.5
|
||||
let currentMouseLocation = NSEvent.mouseLocation
|
||||
var nextMouseLocation = currentMouseLocation
|
||||
|
||||
let x = lastMouseLocation.x + (event.deltaX * speed)
|
||||
let y = lastMouseLocation.y - (event.deltaY * speed)
|
||||
// Slow down tracking speed when concentration mode is active.
|
||||
if concentrationMode {
|
||||
let speed: CGFloat = concentrationMode ? 0.1 : 0.5
|
||||
let x = lastMouseLocation.x + (event.deltaX * speed)
|
||||
let y = lastMouseLocation.y - (event.deltaY * speed)
|
||||
|
||||
// Ensure the picker doesn't travel off screen.
|
||||
var nextMouseLocation = NSPoint(x: x, y: y)
|
||||
for screen in NSScreen.screens {
|
||||
let outsideCoordinate = coordinateOutsideRect(nextMouseLocation, screen.frame)
|
||||
if NSMouseInRect(currentMouseLocation, screen.frame, false) && outsideCoordinate != .none {
|
||||
if outsideCoordinate == .x { nextMouseLocation.x = currentMouseLocation.x }
|
||||
if outsideCoordinate == .y { nextMouseLocation.y = currentMouseLocation.y }
|
||||
if outsideCoordinate == .both { nextMouseLocation = currentMouseLocation }
|
||||
// Ensure the picker doesn't travel off screen.
|
||||
nextMouseLocation = NSPoint(x: x, y: y)
|
||||
for screen in NSScreen.screens {
|
||||
let outlier = Coordinate.isOutsideRect(nextMouseLocation, screen.frame)
|
||||
if NSMouseInRect(currentMouseLocation, screen.frame, false) && outlier != .none {
|
||||
if outlier == .x { nextMouseLocation.x = currentMouseLocation.x }
|
||||
if outlier == .y { nextMouseLocation.y = currentMouseLocation.y }
|
||||
if outlier == .both { nextMouseLocation = currentMouseLocation }
|
||||
}
|
||||
}
|
||||
|
||||
// Since we've disassociated the mouse input with the cursor, we manually move it.
|
||||
CGWarpMouseCursorPosition(convertToCGCoordinateSystem(nextMouseLocation))
|
||||
}
|
||||
|
||||
CGWarpMouseCursorPosition(convertToCGCoordinateSystem(nextMouseLocation))
|
||||
updatePreview(aroundPoint: nextMouseLocation)
|
||||
lastMouseLocation = nextMouseLocation
|
||||
}
|
||||
@@ -235,6 +235,7 @@ class PPOverlayController: NSWindowController {
|
||||
let normalisedPoint = NSPoint(x: round(point.x * 2) / 2, y: round(point.y * 2) / 2)
|
||||
if let screenShot = getScreenShot(aroundPoint: normalisedPoint) {
|
||||
// Calculate a zoomed rect which will crop the screenshot we took.
|
||||
let magnification = CGFloat(PPState.shared.magnificationLevel)
|
||||
let zoomReciprocal: CGFloat = 1.0 / (concentrationMode ? magnification * 2.5 : magnification)
|
||||
let currentSize = CGFloat(screenShot.width) + 1
|
||||
let origin = floor(currentSize * ((1 - zoomReciprocal) / 2))
|
||||
|
||||
@@ -13,20 +13,20 @@ class PPOverlayPreview: NSView, CALayerDelegate {
|
||||
override var wantsUpdateLayer: Bool {
|
||||
get { return true }
|
||||
}
|
||||
|
||||
|
||||
override func awakeFromNib() {
|
||||
// Make layers contents resize to fill, and disable antialiasing.
|
||||
wantsLayer = true
|
||||
layer?.magnificationFilter = kCAFilterNearest
|
||||
layer?.contentsGravity = kCAGravityResizeAspectFill
|
||||
layer?.delegate = self
|
||||
|
||||
|
||||
// Prepare crosshair shape layers.
|
||||
crosshair.strokeColor = NSColor.black.cgColor
|
||||
crosshair.fillColor = nil
|
||||
layer?.addSublayer(crosshair)
|
||||
}
|
||||
|
||||
|
||||
// Update the crosshair with the correct color, position and size.
|
||||
func updateCrosshair(_ pixelSize: CGFloat, _ middle: CGFloat, _ color: CGColor) {
|
||||
let pos: CGFloat = (pixelSize * middle) - (pixelSize / 2)
|
||||
|
||||
@@ -29,6 +29,9 @@ import CleanroomLogger
|
||||
|
||||
// The shortcut that activates the pixel picker.
|
||||
var activatingShortcut: MASShortcut?
|
||||
|
||||
// Magnification level of the picker.
|
||||
var magnificationLevel: Int = 8
|
||||
|
||||
// Hold this down to enter concentration mode.
|
||||
var concentrationModeModifier: NSEvent.ModifierFlags = .control
|
||||
@@ -100,6 +103,8 @@ import CleanroomLogger
|
||||
}
|
||||
case "chosenFormat":
|
||||
chosenFormat = PPColor(rawValue: value.stringValue) ?? .genericHex
|
||||
case "magnificationLevel":
|
||||
magnificationLevel = value.int ?? 8
|
||||
case "floatPrecision":
|
||||
let n = value.uInt ?? 3
|
||||
floatPrecision = (n > 0 && n < PPState.maxFloatPrecision) ? n : 3
|
||||
@@ -137,6 +142,7 @@ import CleanroomLogger
|
||||
"paschaModeEnabled": paschaModeEnabled,
|
||||
"concentrationModeModifier": concentrationModeModifier.rawValue,
|
||||
"activatingShortcut": shortcutData,
|
||||
"magnificationLevel": magnificationLevel,
|
||||
"chosenFormat": chosenFormat.rawValue,
|
||||
"floatPrecision": floatPrecision,
|
||||
"recentPicks": recentPicks.map({ $0.asJSON })
|
||||
|
||||
@@ -42,14 +42,14 @@ func getScreenFromPoint(_ point: NSPoint) -> NSScreen? {
|
||||
// Returns which coordinates are outside, if any.
|
||||
enum Coordinate {
|
||||
case x, y, both, none
|
||||
}
|
||||
func coordinateOutsideRect(_ point: NSPoint, _ rect: NSRect) -> Coordinate {
|
||||
let x = point.x <= rect.origin.x || point.x >= (rect.origin.x + rect.width)
|
||||
let y = point.y <= rect.origin.y || point.y >= (rect.origin.y + rect.height)
|
||||
if x && y { return .both }
|
||||
if x { return .x }
|
||||
if y { return .y }
|
||||
return .none
|
||||
static func isOutsideRect(_ point: NSPoint, _ rect: NSRect) -> Coordinate {
|
||||
let x = point.x < rect.origin.x || point.x > (rect.origin.x + rect.width)
|
||||
let y = point.y < rect.origin.y || point.y > (rect.origin.y + rect.height)
|
||||
if x && y { return .both }
|
||||
if x { return .x }
|
||||
if y { return .y }
|
||||
return .none
|
||||
}
|
||||
}
|
||||
|
||||
// A simple helper to run animations with the same context configration.
|
||||
|
||||
@@ -15,11 +15,7 @@ PixelPicker is like Digital Color Meter, but lives in your menu bar and lets you
|
||||
|
||||
## Installation
|
||||
|
||||
Coming soon.
|
||||
|
||||
<!--
|
||||
Simply download the dmg from the [releases](https://github.com/acheronfail/pixel-picker/releases) tab and drag "Pixel Picker.app" into your `/Applications` folder.
|
||||
-->
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Versions/Current/Headers
|
||||
@@ -1 +0,0 @@
|
||||
Versions/Current/Modules
|
||||
@@ -1 +0,0 @@
|
||||
Versions/Current/Resources
|
||||
@@ -1 +0,0 @@
|
||||
Versions/Current/SwiftyJSON
|
||||
@@ -1,189 +0,0 @@
|
||||
// Generated by Apple Swift version 4.1 effective-3.3 (swiftlang-902.0.48 clang-902.0.37.1)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgcc-compat"
|
||||
|
||||
#if !defined(__has_include)
|
||||
# define __has_include(x) 0
|
||||
#endif
|
||||
#if !defined(__has_attribute)
|
||||
# define __has_attribute(x) 0
|
||||
#endif
|
||||
#if !defined(__has_feature)
|
||||
# define __has_feature(x) 0
|
||||
#endif
|
||||
#if !defined(__has_warning)
|
||||
# define __has_warning(x) 0
|
||||
#endif
|
||||
|
||||
#if __has_include(<swift/objc-prologue.h>)
|
||||
# include <swift/objc-prologue.h>
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic ignored "-Wauto-import"
|
||||
#include <objc/NSObject.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if !defined(SWIFT_TYPEDEFS)
|
||||
# define SWIFT_TYPEDEFS 1
|
||||
# if __has_include(<uchar.h>)
|
||||
# include <uchar.h>
|
||||
# elif !defined(__cplusplus)
|
||||
typedef uint_least16_t char16_t;
|
||||
typedef uint_least32_t char32_t;
|
||||
# endif
|
||||
typedef float swift_float2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef float swift_float3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef float swift_float4 __attribute__((__ext_vector_type__(4)));
|
||||
typedef double swift_double2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef double swift_double3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef double swift_double4 __attribute__((__ext_vector_type__(4)));
|
||||
typedef int swift_int2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef int swift_int3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef int swift_int4 __attribute__((__ext_vector_type__(4)));
|
||||
typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4)));
|
||||
#endif
|
||||
|
||||
#if !defined(SWIFT_PASTE)
|
||||
# define SWIFT_PASTE_HELPER(x, y) x##y
|
||||
# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y)
|
||||
#endif
|
||||
#if !defined(SWIFT_METATYPE)
|
||||
# define SWIFT_METATYPE(X) Class
|
||||
#endif
|
||||
#if !defined(SWIFT_CLASS_PROPERTY)
|
||||
# if __has_feature(objc_class_property)
|
||||
# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__
|
||||
# else
|
||||
# define SWIFT_CLASS_PROPERTY(...)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if __has_attribute(objc_runtime_name)
|
||||
# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X)))
|
||||
#else
|
||||
# define SWIFT_RUNTIME_NAME(X)
|
||||
#endif
|
||||
#if __has_attribute(swift_name)
|
||||
# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
|
||||
#else
|
||||
# define SWIFT_COMPILE_NAME(X)
|
||||
#endif
|
||||
#if __has_attribute(objc_method_family)
|
||||
# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X)))
|
||||
#else
|
||||
# define SWIFT_METHOD_FAMILY(X)
|
||||
#endif
|
||||
#if __has_attribute(noescape)
|
||||
# define SWIFT_NOESCAPE __attribute__((noescape))
|
||||
#else
|
||||
# define SWIFT_NOESCAPE
|
||||
#endif
|
||||
#if __has_attribute(warn_unused_result)
|
||||
# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
#else
|
||||
# define SWIFT_WARN_UNUSED_RESULT
|
||||
#endif
|
||||
#if __has_attribute(noreturn)
|
||||
# define SWIFT_NORETURN __attribute__((noreturn))
|
||||
#else
|
||||
# define SWIFT_NORETURN
|
||||
#endif
|
||||
#if !defined(SWIFT_CLASS_EXTRA)
|
||||
# define SWIFT_CLASS_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_PROTOCOL_EXTRA)
|
||||
# define SWIFT_PROTOCOL_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_ENUM_EXTRA)
|
||||
# define SWIFT_ENUM_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_CLASS)
|
||||
# if __has_attribute(objc_subclassing_restricted)
|
||||
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA
|
||||
# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||
# else
|
||||
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||
# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(SWIFT_PROTOCOL)
|
||||
# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
|
||||
# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
|
||||
#endif
|
||||
|
||||
#if !defined(SWIFT_EXTENSION)
|
||||
# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__)
|
||||
#endif
|
||||
|
||||
#if !defined(OBJC_DESIGNATED_INITIALIZER)
|
||||
# if __has_attribute(objc_designated_initializer)
|
||||
# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
|
||||
# else
|
||||
# define OBJC_DESIGNATED_INITIALIZER
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_ENUM_ATTR)
|
||||
# if defined(__has_attribute) && __has_attribute(enum_extensibility)
|
||||
# define SWIFT_ENUM_ATTR __attribute__((enum_extensibility(open)))
|
||||
# else
|
||||
# define SWIFT_ENUM_ATTR
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_ENUM)
|
||||
# define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type
|
||||
# if __has_feature(generalized_swift_name)
|
||||
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type
|
||||
# else
|
||||
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) SWIFT_ENUM(_type, _name)
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_UNAVAILABLE)
|
||||
# define SWIFT_UNAVAILABLE __attribute__((unavailable))
|
||||
#endif
|
||||
#if !defined(SWIFT_UNAVAILABLE_MSG)
|
||||
# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg)))
|
||||
#endif
|
||||
#if !defined(SWIFT_AVAILABILITY)
|
||||
# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__)))
|
||||
#endif
|
||||
#if !defined(SWIFT_DEPRECATED)
|
||||
# define SWIFT_DEPRECATED __attribute__((deprecated))
|
||||
#endif
|
||||
#if !defined(SWIFT_DEPRECATED_MSG)
|
||||
# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__)))
|
||||
#endif
|
||||
#if __has_feature(attribute_diagnose_if_objc)
|
||||
# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning")))
|
||||
#else
|
||||
# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg)
|
||||
#endif
|
||||
#if __has_feature(modules)
|
||||
@import Foundation;
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch"
|
||||
#pragma clang diagnostic ignored "-Wduplicate-method-arg"
|
||||
#if __has_warning("-Wpragma-clang-attribute")
|
||||
# pragma clang diagnostic ignored "-Wpragma-clang-attribute"
|
||||
#endif
|
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas"
|
||||
#pragma clang diagnostic ignored "-Wnullability"
|
||||
|
||||
#if __has_attribute(external_source_symbol)
|
||||
# pragma push_macro("any")
|
||||
# undef any
|
||||
# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="SwiftyJSON",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol))
|
||||
# pragma pop_macro("any")
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if __has_attribute(external_source_symbol)
|
||||
# pragma clang attribute pop
|
||||
#endif
|
||||
#pragma clang diagnostic pop
|
||||
@@ -1,31 +0,0 @@
|
||||
// SwiftyJSON.h
|
||||
//
|
||||
// Copyright (c) 2014 - 2017 Ruoyu Fu, Pinglin Tang
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
@import Foundation;
|
||||
|
||||
//! Project version number for SwiftyJSON.
|
||||
FOUNDATION_EXPORT double SwiftyJSONVersionNumber;
|
||||
|
||||
//! Project version string for SwiftyJSON.
|
||||
FOUNDATION_EXPORT const unsigned char SwiftyJSONVersionString[];
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,11 +0,0 @@
|
||||
framework module SwiftyJSON {
|
||||
umbrella header "SwiftyJSON.h"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
||||
|
||||
module SwiftyJSON.Swift {
|
||||
header "SwiftyJSON-Swift.h"
|
||||
requires objc
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BuildMachineOSBuild</key>
|
||||
<string>17E202</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>SwiftyJSON</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.swiftyjson.SwiftyJSON</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>SwiftyJSON</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>MacOSX</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>DTCompiler</key>
|
||||
<string>com.apple.compilers.llvm.clang.1_0</string>
|
||||
<key>DTPlatformBuild</key>
|
||||
<string>9E501</string>
|
||||
<key>DTPlatformVersion</key>
|
||||
<string>GM</string>
|
||||
<key>DTSDKBuild</key>
|
||||
<string>17E189</string>
|
||||
<key>DTSDKName</key>
|
||||
<string>macosx10.13</string>
|
||||
<key>DTXcode</key>
|
||||
<string>0931</string>
|
||||
<key>DTXcodeBuild</key>
|
||||
<string>9E501</string>
|
||||
<key>UIDeviceFamily</key>
|
||||
<array>
|
||||
<integer>1</integer>
|
||||
<integer>2</integer>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
A
|
||||
Reference in New Issue
Block a user