Skip to content
Merged
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
22 changes: 20 additions & 2 deletions Free Ruler/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var pixelsMenuItem: NSMenuItem!
@IBOutlet weak var millimetersMenuItem: NSMenuItem!
@IBOutlet weak var inchesMenuItem: NSMenuItem!

@IBOutlet weak var cycleUnitsMenuItem: NSMenuItem!

@IBOutlet weak var floatRulersMenuItem: NSMenuItem!
@IBOutlet weak var groupRulersMenuItem: NSMenuItem!
@IBOutlet weak var rulerShadowMenuItem: NSMenuItem!
Expand Down Expand Up @@ -47,6 +48,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
observers = [
prefs.observe(\Prefs.unit, options: .new) { prefs, changed in
self.updateUnitMenu()
self.redrawRulers()
},
prefs.observe(\Prefs.floatRulers, options: .new) { prefs, changed in
self.updateFloatRulersMenuItem()
Expand All @@ -73,6 +75,12 @@ class AppDelegate: NSObject, NSApplicationDelegate {
inchesMenuItem?.state = prefs.unit == .inches ? .on : .off
}

func redrawRulers() {
for ruler in rulers {
ruler.rulerWindow.rule.setNeedsDisplay(ruler.rulerWindow.rule.visibleRect)
}
}

func updateFloatRulersMenuItem() {
floatRulersMenuItem?.state = prefs.floatRulers ? .on : .off
}
Expand Down Expand Up @@ -130,7 +138,17 @@ class AppDelegate: NSObject, NSApplicationDelegate {
@IBAction func setUnitInches(_ sender: Any) {
prefs.unit = .inches
}

@IBAction func cycleUnits(_ sender: Any) {
switch prefs.unit {
case .pixels:
prefs.unit = .millimeters
case .millimeters:
prefs.unit = .inches
case .inches:
prefs.unit = .pixels
}
}

@IBAction func toggleFloatRulers(_ sender: Any) {
prefs.floatRulers = !prefs.floatRulers
}
Expand Down
14 changes: 8 additions & 6 deletions Free Ruler/Base.lproj/MainMenu.xib
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Free_Ruler" customModuleProvider="target">
<connections>
<outlet property="alignRulersMenuItem" destination="iKV-uW-hwy" id="KQ1-Wu-ShT"/>
<outlet property="cycleUnitsMenuItem" destination="2nm-aL-kZd" id="cec-5d-z3z"/>
<outlet property="floatRulersMenuItem" destination="GDK-AC-uC8" id="552-nT-5F2"/>
<outlet property="groupRulersMenuItem" destination="7Ga-Fb-LLc" id="WrL-X9-6QE"/>
<outlet property="inchesMenuItem" destination="lt1-Hj-2TR" id="yV0-oN-4bC"/>
Expand Down Expand Up @@ -158,6 +159,13 @@
<action selector="setUnitInches:" target="Voe-Tx-rLC" id="Apf-6P-Oz8"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="tK2-3l-lAd"/>
<menuItem title="Cycle Units" keyEquivalent="u" id="2nm-aL-kZd">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="cycleUnits:" target="Voe-Tx-rLC" id="jzB-to-aha"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
Expand Down Expand Up @@ -238,11 +246,5 @@
</items>
<point key="canvasLocation" x="-147" y="125"/>
</menu>
<menuItem title="Group Rulers" state="on" keyEquivalent="g" id="7SO-Lm-Ylr">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleGroupRulers:" target="Voe-Tx-rLC" id="RkN-cz-hMe"/>
</connections>
</menuItem>
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was a weird stray menuitem that somehow got added outside the menu, not visible in the app. A duplicate of the existing Group Rulers menu item.

</objects>
</document>
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ <h2>
<tr><th></th><th>G</th><td>Group/ungroup rulers</td></tr>
<tr><th></th><th>S</th><td>Show/hide ruler shadows</td></tr>
<tr><th></th><th>O</th><td>Orient rulers at mouse location</td></tr>
<tr><th></th><th>U</th><td>Cycle units: pixels, millimeters, and inches</td></tr>
<tr><th>⌘</th><th>R</th><td>Reset ruler positions to default</td></tr>
<tr><th>⌘</th><th>,</th><td>Open Preferences</td></tr>
</tbody>
Expand Down
90 changes: 59 additions & 31 deletions Free Ruler/HorizontalRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ class HorizontalRule: RuleView {
}
}

var windowWidth: CGFloat {
return self.window?.frame.width ?? 0
}

override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)

Expand All @@ -31,6 +27,7 @@ class HorizontalRule: RuleView {
.foregroundColor: color.numbers
]

let width = dirtyRect.width
let path = NSBezierPath()
let tickScale: CGFloat
let textScale: Int
Expand Down Expand Up @@ -63,18 +60,26 @@ class HorizontalRule: RuleView {
tinyTicks = nil
}

let labelWidth: CGFloat = 50
let labelHeight: CGFloat = 20
let labelOffset: CGFloat = 13 // offset of label from bottom edge of ruler
// TODO: refactor this to use label.size() logic (see func drawUnitLabel)

// substract two so ticks don't overlap with border
// subtract from this range so width var is accurate
for i in 1...Int((dirtyRect.width - 2) / tickScale) {
for i in 1...Int((width - 2) / tickScale) {
let pos = CGFloat(i) * tickScale
if i.isMultiple(of: largeTicks) {
path.move(to: CGPoint(x: pos, y: 1))
path.line(to: CGPoint(x: pos, y: 10))

let label = String(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)

label.draw(
with: CGRect(x: pos - 20, y: 3, width: 40, height: 20),
options: .usesLineFragmentOrigin,
with: labelRect,
attributes: attrs,
context: nil
)
Expand All @@ -99,11 +104,16 @@ class HorizontalRule: RuleView {
color.ticks.setStroke()
path.stroke()

if !showMouseTick || mouseTickX < 0 || mouseTickX > 26 {
drawUnitLabel()
}

// Draw the MouseTick & number
if showMouseTick && mouseTickX > 0 && mouseTickX < windowWidth {
if showMouseTick && mouseTickX > 0 && mouseTickX < self.windowWidth {
drawMouseTick(mouseTickX)
drawMouseNumber(mouseTickX)
}

}

override func drawMouseTick(at mouseLoc: NSPoint) {
Expand All @@ -126,39 +136,57 @@ class HorizontalRule: RuleView {
}

func drawMouseNumber(_ mouseTickX: CGFloat) {
let number = mouseTickX
let width = self.frame.width
let height = self.frame.height
let labelOffset: CGFloat = 5

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .left
paragraphStyle.alignment = .center

let number = mouseTickX
let labelWidth: CGFloat = 40
let attributes = [
NSAttributedString.Key.font: NSFont(name: "HelveticaNeue", size: 10)!,
NSAttributedString.Key.paragraphStyle: paragraphStyle,
NSAttributedString.Key.foregroundColor: color.mouseNumber,
]

var labelX = number + 5 // 3px padding from the line
let mouseNumber = self.getMouseNumberLabel(number)
let label = NSAttributedString(string: mouseNumber, attributes: attributes)
let labelSize = label.size()

if labelX + labelWidth > windowWidth {
// Switch to the left of the tick
labelX = number - labelWidth - 5
paragraphStyle.alignment = .right
}
let rightPosition = number + labelOffset;
let leftPosition = number - labelOffset - labelSize.width
let enoughRoomToTheRight = rightPosition + labelSize.width < width - labelOffset
let labelX = enoughRoomToTheRight ? rightPosition : leftPosition

let labelRect = CGRect(x: labelX, y: height - labelSize.height, width: labelSize.width, height: labelSize.height)

label.draw(
with: labelRect,
context: nil
)
}

func drawUnitLabel() {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .left

let attrs = [
let attributes = [
NSAttributedString.Key.font: NSFont(name: "HelveticaNeue", size: 10)!,
NSAttributedString.Key.paragraphStyle: paragraphStyle,
NSAttributedString.Key.foregroundColor: color.mouseNumber,
NSAttributedString.Key.backgroundColor: color.fill,
NSAttributedString.Key.foregroundColor: color.ticks,
]

let label: String
switch prefs.unit {
case .millimeters:
label = String(format: "%.1f", number / (screen?.dpmm.width ?? NSScreen.defaultDpmm))
case .inches:
label = String(format: "%.3f", number / (screen?.dpi.width ?? NSScreen.defaultDpi))
default:
label = String(Int(number))
}

label.draw(with: CGRect(x: labelX, y: 20, width: labelWidth, height: 20), options: .usesLineFragmentOrigin, attributes: attrs, context: nil)
let unitlabel = self.getUnitLabel()
let label = NSAttributedString(string: unitlabel, attributes: attributes)
let height = self.frame.height
let labelSize = label.size()
let labelRect = CGRect(x: 10, y: height - labelSize.height, width: labelSize.width, height: labelSize.height)

label.draw(
with: labelRect,
context: nil
)
}

}
30 changes: 30 additions & 0 deletions Free Ruler/RuleView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ class RuleView: NSView {
fatalError("RuleView subclass must override drawMouseTick method.")
}

var windowWidth: CGFloat {
return self.window?.frame.width ?? 0
}

var windowHeight: CGFloat {
return self.window?.frame.height ?? 0
}

var showMouseTick: Bool = true {
didSet {
if showMouseTick != oldValue {
Expand All @@ -56,6 +64,28 @@ class RuleView: NSView {
return NSScreen.screens.first { $0.frame.intersects(window.convertToScreen(frame)) }
}

func getUnitLabel() -> String {
switch prefs.unit {
case .pixels:
return "px"
case .millimeters:
return "mm"
case .inches:
return "in"
}
}

func getMouseNumberLabel(_ number: CGFloat) -> String {
switch prefs.unit {
case .pixels:
return String(format: "%d", Int(number))
case .millimeters:
return String(format: "%.1f", number / (screen?.dpmm.width ?? NSScreen.defaultDpmm))
case .inches:
return String(format: "%.3f", number / (screen?.dpi.width ?? NSScreen.defaultDpi))
}
}

}

fileprivate let mmPerIn: CGFloat = 25.4
Expand Down
Loading