Skip to content
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
2 changes: 1 addition & 1 deletion Sources/TinyHand/ArmView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ final class ArmView: NSView {

let ink = Ink()
var held = false
var inkWidth: CGFloat { max(3, bounds.height * 0.0055) }
var inkWidth: CGFloat { max(2, max(3, bounds.height * 0.0055) * Preferences.penSize.scale) }

private var pressAmount: CGFloat = 0
private var gripX: CGFloat?
Expand Down
71 changes: 69 additions & 2 deletions Sources/TinyHand/Preferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,12 @@ enum InkChoice: String, CaseIterable {
}
}

/// The colour with the Ink tone setting applied.
var color: CGColor? {
baseColor.map(Preferences.inkTone.apply)
}

private var baseColor: CGColor? {
switch self {
case .match: return nil
case .red: return Ink.red
Expand All @@ -74,7 +79,59 @@ enum InkChoice: String, CaseIterable {
}

func resolved(for style: PointerStyle) -> CGColor {
color ?? style.inkColor
color ?? Preferences.inkTone.apply(style.inkColor)
}
}

/// Shifts every ink colour together: softer, greyer or darker.
enum InkTone: String, CaseIterable {
case vivid, pastel, muted, deep

var title: String {
switch self {
case .vivid: return "Vivid"
case .pastel: return "Pastel"
case .muted: return "Muted"
case .deep: return "Deep"
}
}

func apply(_ color: CGColor) -> CGColor {
guard self != .vivid, let ns = NSColor(cgColor: color)?.usingColorSpace(.sRGB) else {
return color
}
var h: CGFloat = 0, s: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
ns.getHue(&h, saturation: &s, brightness: &b, alpha: &a)
if s < 0.08 {
return color // leave white and black alone
}
switch self {
case .vivid: break
case .pastel: s *= 0.45; b = min(1, b * 0.25 + 0.78)
case .muted: s *= 0.55; b *= 0.82
case .deep: s = min(1, s * 1.05); b *= 0.62
}
return NSColor(hue: h, saturation: s, brightness: b, alpha: a).cgColor
}
}

enum PenSize: String, CaseIterable {
case thin, medium, thick

var title: String {
switch self {
case .thin: return "Thin"
case .medium: return "Medium"
case .thick: return "Thick"
}
}

var scale: CGFloat {
switch self {
case .thin: return 0.55
case .medium: return 1
case .thick: return 1.9
}
}
}

Expand Down Expand Up @@ -109,6 +166,16 @@ enum Preferences {
set { set(newValue, "fadeSeconds") }
}

static var inkTone: InkTone {
get { defaults.string(forKey: "inkTone").flatMap(InkTone.init(rawValue:)) ?? .vivid }
set { set(newValue.rawValue, "inkTone") }
}

static var penSize: PenSize {
get { defaults.string(forKey: "penSize").flatMap(PenSize.init(rawValue:)) ?? .medium }
set { set(newValue.rawValue, "penSize") }
}

static var handSound: Bool {
get { defaults.object(forKey: "sound.hands") as? Bool ?? true }
set { set(newValue, "sound.hands") }
Expand Down Expand Up @@ -187,7 +254,7 @@ enum Preferences {
static func resetAll() {
for key in ["shortcut.toggle", "shortcut.clear", "pointerSize", "showShadow", "fadeSeconds",
"sound.hands", "sound.laser", "interactKey", "interactKeepsHand", "doubleShiftClickThrough", "pinnedStyles", "pointerStyle",
"inkChoice", "showInkButton", "showToolbar", "tapSound"] {
"inkChoice", "showInkButton", "showToolbar", "tapSound", "inkTone", "penSize"] {
defaults.removeObject(forKey: key)
}
NotificationCenter.default.post(name: changed, object: nil)
Expand Down
23 changes: 23 additions & 0 deletions Sources/TinyHand/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,7 @@ private struct AppearancePage: View {
private struct DrawingPage: View {
@ObservedObject var model: SettingsModel
private static let choices: [(String, Double)] = [
("After 1 second", 1),
("After 3 seconds", 3),
("After 6 seconds", 6),
("After 10 seconds", 10),
Expand All @@ -991,6 +992,28 @@ private struct DrawingPage: View {
}
}
}
Row("Ink tone", detail: "Shifts every colour together: Pastel is softer, Muted is greyer, Deep is darker.") {
Picker("", selection: model.binding({ Preferences.inkTone }, { Preferences.inkTone = $0 })) {
ForEach(InkTone.allCases, id: \.self) { tone in
Text(tone.title).tag(tone)
}
}
.labelsHidden()
.pickerStyle(.segmented)
.fixedSize()
.focusable(false)
}
Row("Pen size") {
Picker("", selection: model.binding({ Preferences.penSize }, { Preferences.penSize = $0 })) {
ForEach(PenSize.allCases, id: \.self) { size in
Text(size.title).tag(size)
}
}
.labelsHidden()
.pickerStyle(.segmented)
.fixedSize()
.focusable(false)
}
Row("Lines fade", detail: "Clear them any time with \(Preferences.clearShortcut.display).") {
Picker("", selection: model.binding({ Preferences.fadeSeconds }, { Preferences.fadeSeconds = $0 })) {
ForEach(DrawingPage.choices, id: \.1) { choice in
Expand Down