Skip to content

Add support for user defined units #129

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Free Ruler/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var pixelsMenuItem: NSMenuItem!
@IBOutlet weak var millimetersMenuItem: NSMenuItem!
@IBOutlet weak var inchesMenuItem: NSMenuItem!
@IBOutlet weak var userDefinedMenuItem: NSMenuItem!
@IBOutlet weak var cycleUnitsMenuItem: NSMenuItem!

@IBOutlet weak var floatRulersMenuItem: NSMenuItem!
Expand Down Expand Up @@ -73,6 +74,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
pixelsMenuItem?.state = prefs.unit == .pixels ? .on : .off
millimetersMenuItem?.state = prefs.unit == .millimeters ? .on : .off
inchesMenuItem?.state = prefs.unit == .inches ? .on : .off
userDefinedMenuItem?.state = prefs.unit == .user ? .on: .off
}

func redrawRulers() {
Expand Down Expand Up @@ -138,13 +140,18 @@ class AppDelegate: NSObject, NSApplicationDelegate {
@IBAction func setUnitInches(_ sender: Any) {
prefs.unit = .inches
}
@IBAction func setUnitUserDefined(_ sender: Any) {
prefs.unit = .user
}
@IBAction func cycleUnits(_ sender: Any) {
switch prefs.unit {
case .pixels:
prefs.unit = .millimeters
case .millimeters:
prefs.unit = .inches
case .inches:
prefs.unit = .user
case .user:
prefs.unit = .pixels
}
}
Expand Down
7 changes: 7 additions & 0 deletions Free Ruler/Base.lproj/MainMenu.xib
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<outlet property="millimetersMenuItem" destination="B6Y-Hi-AkN" id="9Cc-tZ-RRZ"/>
<outlet property="pixelsMenuItem" destination="pYR-Ba-kKi" id="Wus-JK-rs3"/>
<outlet property="rulerShadowMenuItem" destination="a8D-hN-A59" id="FZM-pS-71y"/>
<outlet property="userDefinedMenuItem" destination="irY-SC-eqL" id="LT1-bU-rbJ"/>
</connections>
</customObject>
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
Expand Down Expand Up @@ -159,6 +160,12 @@
<action selector="setUnitInches:" target="Voe-Tx-rLC" id="Apf-6P-Oz8"/>
</connections>
</menuItem>
<menuItem title="user defined" id="irY-SC-eqL">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="setUnitUserDefined:" target="Voe-Tx-rLC" id="iUa-FK-6bH"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="tK2-3l-lAd"/>
<menuItem title="Cycle Units" keyEquivalent="u" id="2nm-aL-kZd">
<modifierMask key="keyEquivalentModifierMask"/>
Expand Down
149 changes: 130 additions & 19 deletions Free Ruler/Base.lproj/PreferencesController.xib

Large diffs are not rendered by default.

44 changes: 42 additions & 2 deletions Free Ruler/HorizontalRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class HorizontalRule: RuleView {
let width = dirtyRect.width
let path = NSBezierPath()
let tickScale: CGFloat
let textScale: Int
let textScale: CGFloat
let largeTicks: Int
let mediumTicks: Int
let smallTicks: Int
Expand All @@ -51,6 +51,46 @@ class HorizontalRule: RuleView {
mediumTicks = 8
smallTicks = 4
tinyTicks = 1
case .user:
let scale:Float
switch(prefs.userUnitScreenUnit) {
case .pixels: scale = 1.0
case .millimeters: scale = Float(screen?.dpmm.width ?? NSScreen.defaultDpmm)
case .inches: scale = Float(screen?.dpi.width ?? NSScreen.defaultDpi)
default: scale = 1.0
}
var tickScale_:CGFloat = CGFloat(prefs.userUnitScreenValue * scale / prefs.userUnitValue)/10
var textScale_:CGFloat = 10.0
while (tickScale_ < 4) {
tickScale_ = tickScale_ * 10.0
textScale_ = textScale_ / 10.0
}
while (tickScale_ > 40) {
tickScale_ = tickScale_ / 10.0
textScale_ = textScale_ * 10.0
}
var largeTicks_: Int = 10
var mediumTicks_: Int = 5
if (tickScale_ > 25){
tickScale_ = tickScale_ / 5.0
textScale_ = textScale_ * 5.0
largeTicks_ = 5
mediumTicks_ = 1
}
#if (false)
if (tickScale_ > 10){
tickScale_ = tickScale_ / 2
textScale_ = textScale_ * 2
largeTicks_ = 2
mediumTicks_ = 1
}
#endif
textScale = textScale_
tickScale = tickScale_
largeTicks = largeTicks_
mediumTicks = mediumTicks_
smallTicks = 1
tinyTicks = nil
default:
tickScale = 1
textScale = 1
Expand All @@ -73,7 +113,7 @@ class HorizontalRule: RuleView {
path.move(to: CGPoint(x: pos, y: 1))
path.line(to: CGPoint(x: pos, y: 10))

let label = String(i / textScale)
let label = String(CGFloat(i) / textScale)
let labelX: CGFloat = pos - (labelWidth / 2) + 0.5 // half-pixel nudge /shrug
let labelY: CGFloat = labelOffset
let labelRect = CGRect(x: labelX, y: labelY, width: labelWidth, height: labelHeight)
Expand Down
90 changes: 90 additions & 0 deletions Free Ruler/PreferencesController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ class PreferencesController: NSWindowController, NSWindowDelegate, NotificationP
@IBOutlet weak var groupRulersCheckbox: NSButton!
@IBOutlet weak var rulerShadowCheckbox: NSButton!

@IBOutlet weak var UserUnitScreenValueTbx: NSTextField!
@IBOutlet weak var UserUnitScreenUnitPopup: NSPopUpButton!
@IBOutlet weak var UserUnitValueTbx: NSTextField!
@IBOutlet weak var UserUnitUnitTbx: NSTextField!


override var windowNibName: String {
return "PreferencesController"
}
Expand All @@ -23,6 +29,14 @@ class PreferencesController: NSWindowController, NSWindowDelegate, NotificationP

window?.isMovableByWindowBackground = true

if let app=NSApplication.shared.delegate as? AppDelegate{
UserUnitScreenUnitPopup.addItems(withTitles: [
app.pixelsMenuItem.title,
app.millimetersMenuItem.title,
app.inchesMenuItem.title
])
}

subscribeToPrefs()
updateView()
}
Expand Down Expand Up @@ -58,6 +72,18 @@ class PreferencesController: NSWindowController, NSWindowDelegate, NotificationP
prefs.observe(\Prefs.rulerShadow, options: .new) { prefs, changed in
self.updateRulerShadowCheckbox()
},
prefs.observe(\Prefs.userUnitScreenValue, options:.new){ prefs, changed in
self.updateUserUnitScreenValue()
},
prefs.observe(\Prefs.userUnitScreenUnit, options:.new){ prefs, changed in
self.updateUserUnitScreenUnit()
},
prefs.observe(\Prefs.userUnitValue, options:.new){ prefs, changed in
self.updateUserUnitValue()
},
prefs.observe(\Prefs.userUnitUnit, options:.new){ prefs, changed in
self.updateUserUnitUnit()
},
]
}

Expand All @@ -76,13 +102,57 @@ class PreferencesController: NSWindowController, NSWindowDelegate, NotificationP
@IBAction func setRulerShadow(_ sender: Any) {
prefs.rulerShadow = rulerShadowCheckbox.state == .on
}
@IBAction func setUserScreenValue(_ Sender: Any) {
prefs.userUnitScreenValue = UserUnitScreenValueTbx.floatValue
}
var screen: NSScreen? {
guard let window = window else {
return nil
}
return NSScreen.screens.first { $0.frame.intersects(window.convertToScreen(self.UserUnitScreenUnitPopup.frame)) }
}
@IBAction func setUserScreenUnit(_ Sender: Any) {
let oldScale:Float
switch(prefs.userUnitScreenUnit) {
case .pixels: oldScale = 1.0
case .millimeters: oldScale = Float(screen?.dpmm.width ?? NSScreen.defaultDpmm)
case .inches: oldScale = Float(screen?.dpi.width ?? NSScreen.defaultDpi)
default: oldScale = 1.0
}

switch(UserUnitScreenUnitPopup.indexOfSelectedItem){
case 0: prefs.userUnitScreenUnit = .pixels
case 1: prefs.userUnitScreenUnit = .millimeters
case 2: prefs.userUnitScreenUnit = .inches
default: prefs.userUnitScreenUnit = .pixels
}

let newScale:Float
switch(prefs.userUnitScreenUnit) {
case .pixels: newScale = 1.0
case .millimeters: newScale = Float(screen?.dpmm.width ?? NSScreen.defaultDpmm)
case .inches: newScale = Float(screen?.dpi.width ?? NSScreen.defaultDpi)
default: newScale = 1.0
}
prefs.userUnitScreenValue = prefs.userUnitScreenValue * oldScale / newScale;
}
@IBAction func setUserUnitValue(_ Sender: Any) {
prefs.userUnitValue = UserUnitValueTbx.floatValue
}
@IBAction func setUserUnit(_ Sender: Any) {
prefs.userUnitUnit = UserUnitUnitTbx.stringValue
}

func updateView() {
updateForegroundSlider()
updateBackgroundSlider()
updateFloatRulersCheckbox()
updateGroupRulersCheckbox()
updateRulerShadowCheckbox()
updateUserUnitScreenValue()
updateUserUnitScreenUnit()
updateUserUnitValue()
updateUserUnitUnit()
}

func updateForegroundSlider() {
Expand All @@ -107,4 +177,24 @@ class PreferencesController: NSWindowController, NSWindowDelegate, NotificationP
rulerShadowCheckbox.state = prefs.rulerShadow ? .on : .off
}

func updateUserUnitScreenValue() {
UserUnitScreenValueTbx.floatValue = prefs.userUnitScreenValue
}

func updateUserUnitScreenUnit() {
switch(prefs.userUnitScreenUnit) {
case .pixels: UserUnitScreenUnitPopup.selectItem(at: 0)
case .millimeters: UserUnitScreenUnitPopup.selectItem(at: 1)
case .inches: UserUnitScreenUnitPopup.selectItem(at: 2)
default: UserUnitScreenUnitPopup.selectItem(at: 0)
}
}
func updateUserUnitValue(){
UserUnitValueTbx.floatValue = prefs.userUnitValue
}

func updateUserUnitUnit(){
UserUnitUnitTbx.stringValue = prefs.userUnitUnit
}

}
51 changes: 38 additions & 13 deletions Free Ruler/Prefs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ let prefs = Prefs.shared
case pixels
case millimeters
case inches
case user
}

class Prefs: NSObject {
Expand All @@ -25,12 +26,16 @@ class Prefs: NSObject {
static let shared = Prefs()

// MARK: - public properties
@objc dynamic var floatRulers : Bool
@objc dynamic var groupRulers : Bool
@objc dynamic var rulerShadow : Bool
@objc dynamic var foregroundOpacity : Int
@objc dynamic var backgroundOpacity : Int
@objc dynamic var unit : Unit
@objc dynamic var floatRulers : Bool
@objc dynamic var groupRulers : Bool
@objc dynamic var rulerShadow : Bool
@objc dynamic var foregroundOpacity : Int
@objc dynamic var backgroundOpacity : Int
@objc dynamic var unit : Unit
@objc dynamic var userUnitScreenValue : Float
@objc dynamic var userUnitScreenUnit : Unit
@objc dynamic var userUnitValue : Float
@objc dynamic var userUnitUnit : String

// MARK: - public save method
func save() {
Expand All @@ -47,18 +52,26 @@ class Prefs: NSObject {
"rulerShadow": false,
"foregroundOpacity": 90,
"backgroundOpacity": 50,
"unit": Unit.pixels.rawValue
"unit": Unit.pixels.rawValue,
"userUnitScreenValue": 1,
"userUnitScreenUnit": Unit.millimeters.rawValue,
"userUnitValue": 1,
"userUnitUnit": "mm"
]

private override init() {
defaults.register(defaults: defaultValues)

floatRulers = defaults.bool(forKey: "floatRulers")
groupRulers = defaults.bool(forKey: "groupRulers")
rulerShadow = defaults.bool(forKey: "rulerShadow")
foregroundOpacity = defaults.integer(forKey: "foregroundOpacity")
backgroundOpacity = defaults.integer(forKey: "backgroundOpacity")
unit = Unit(rawValue: defaults.integer(forKey: "unit")) ?? .pixels
floatRulers = defaults.bool(forKey: "floatRulers")
groupRulers = defaults.bool(forKey: "groupRulers")
rulerShadow = defaults.bool(forKey: "rulerShadow")
foregroundOpacity = defaults.integer(forKey: "foregroundOpacity")
backgroundOpacity = defaults.integer(forKey: "backgroundOpacity")
userUnitScreenValue = defaults.float(forKey: "userUnitScreenValue")
userUnitScreenUnit = Unit(rawValue: defaults.integer(forKey: "userUnitScreenUnit")) ?? .millimeters
userUnitValue = defaults.float(forKey: "userUnitValue")
userUnitUnit = defaults.string(forKey: "userUnitUnit") ?? "mm"
unit = Unit(rawValue: defaults.integer(forKey: "unit")) ?? .pixels

super.init()

Expand Down Expand Up @@ -87,6 +100,18 @@ class Prefs: NSObject {
observe(\Prefs.unit, options: .new) { prefs, changed in
self.defaults.set(prefs.unit.rawValue, forKey: "unit")
},
observe(\Prefs.userUnitScreenValue, options:.new){ prefs, changed in
self.defaults.set(changed.newValue, forKey: "userUnitScreenValue")
},
observe(\Prefs.userUnitScreenUnit, options:.new){ prefs, changed in
self.defaults.set(prefs.userUnitScreenUnit.rawValue, forKey: "userUnitScreenUnit")
},
observe(\Prefs.userUnitValue, options:.new){ prefs, changed in
self.defaults.set(changed.newValue, forKey: "userUnitValue")
},
observe(\Prefs.userUnitUnit, options:.new){ prefs, changed in
self.defaults.set(changed.newValue, forKey: "userUnitUnit")
},
]
}

Expand Down
16 changes: 16 additions & 0 deletions Free Ruler/RuleView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ class RuleView: NSView {
return "mm"
case .inches:
return "in"
case .user:
return String(format:"user (%@)", prefs.userUnitUnit)
}
}

Expand All @@ -83,6 +85,20 @@ class RuleView: NSView {
return String(format: "%.1f", number / (screen?.dpmm.width ?? NSScreen.defaultDpmm))
case .inches:
return String(format: "%.3f", number / (screen?.dpi.width ?? NSScreen.defaultDpi))
case .user:
let scale:Float
switch(prefs.userUnitScreenUnit) {
case .millimeters:
scale = Float(screen?.dpmm.width ?? NSScreen.defaultDpmm)
break
case .inches:
scale = Float(screen?.dpi.width ?? NSScreen.defaultDpi)
break
default:
scale = 1.0;
break
}
return String(format: "%.1f", Float(number) / prefs.userUnitScreenValue / scale * prefs.userUnitValue)
}
}

Expand Down
12 changes: 12 additions & 0 deletions Free Ruler/RulerController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,18 @@ class RulerController: NSWindowController, NSWindowDelegate, NotificationObserve
prefs.observe(\Prefs.rulerShadow, options: .new) { prefs, changed in
self.rulerWindow.hasShadow = prefs.rulerShadow
},
prefs.observe(\Prefs.userUnitScreenValue, options: .new) { prefs, changed in
self.rulerWindow.rule.needsDisplay = true
},
prefs.observe(\Prefs.userUnitScreenUnit, options: .new) { prefs, changed in
self.rulerWindow.rule.needsDisplay = true
},
prefs.observe(\Prefs.userUnitValue, options: .new) { prefs, changed in
self.rulerWindow.rule.needsDisplay = true
},
prefs.observe(\Prefs.userUnitUnit, options: .new) { prefs, changed in
self.rulerWindow.rule.needsDisplay = true
},
]
}

Expand Down
Loading