166 lines
7.2 KiB
Swift
166 lines
7.2 KiB
Swift
// PreferencesView.swift
|
|
// GreenshotMac
|
|
//
|
|
// Port of Greenshot's SettingsForm.
|
|
|
|
import SwiftUI
|
|
import AppKit
|
|
|
|
struct PreferencesView: View {
|
|
var body: some View {
|
|
TabView {
|
|
GeneralPreferences()
|
|
.tabItem { Label("General", systemImage: "gearshape") }
|
|
OutputPreferences()
|
|
.tabItem { Label("Output", systemImage: "square.and.arrow.down") }
|
|
HotkeyPreferences()
|
|
.tabItem { Label("Hotkeys", systemImage: "keyboard") }
|
|
EditorPreferences()
|
|
.tabItem { Label("Editor", systemImage: "pencil.tip.crop.circle") }
|
|
}
|
|
.padding(16)
|
|
.frame(width: 520, height: 380)
|
|
}
|
|
}
|
|
|
|
private struct GeneralPreferences: View {
|
|
@AppStorage(Configuration.Keys.defaultDestination) private var destination = DestinationID.editor.rawValue
|
|
@AppStorage(Configuration.Keys.captureMousepointer) private var captureMousePointer = false
|
|
@AppStorage(Configuration.Keys.captureDelayMillis) private var captureDelay = 0
|
|
@AppStorage(Configuration.Keys.playCameraSound) private var cameraSound = true
|
|
@AppStorage(Configuration.Keys.showFlashAnimation) private var flash = true
|
|
@AppStorage(Configuration.Keys.showMagnifier) private var magnifier = true
|
|
@AppStorage(Configuration.Keys.showSelectionSize) private var selectionSize = true
|
|
@AppStorage(Configuration.Keys.windowCaptureMode) private var windowMode = WindowCaptureMode.window.rawValue
|
|
@State private var launchAtLogin = LaunchAtLogin.isEnabled
|
|
|
|
var body: some View {
|
|
Form {
|
|
Picker("After capture:", selection: $destination) {
|
|
ForEach(DestinationID.allCases.filter { $0 != .openWith }, id: \.rawValue) { item in
|
|
Text(item.title).tag(item.rawValue)
|
|
}
|
|
}
|
|
Picker("Window capture:", selection: $windowMode) {
|
|
Text("Window only").tag(WindowCaptureMode.window.rawValue)
|
|
Text("Window with shadow").tag(WindowCaptureMode.windowWithShadow.rawValue)
|
|
Text("Crop from screen").tag(WindowCaptureMode.screen.rawValue)
|
|
}
|
|
Toggle("Capture the mouse pointer", isOn: $captureMousePointer)
|
|
Toggle("Play a shutter sound", isOn: $cameraSound)
|
|
Toggle("Flash the captured area", isOn: $flash)
|
|
Toggle("Show magnifier while selecting", isOn: $magnifier)
|
|
Toggle("Show selection size while selecting", isOn: $selectionSize)
|
|
Toggle("Launch at login", isOn: $launchAtLogin)
|
|
.onChange(of: launchAtLogin) { _, newValue in
|
|
LaunchAtLogin.isEnabled = newValue
|
|
}
|
|
HStack {
|
|
Text("Capture delay:")
|
|
Slider(value: Binding(get: { Double(captureDelay) },
|
|
set: { captureDelay = Int($0) }),
|
|
in: 0...5000, step: 250)
|
|
Text("\(captureDelay) ms").frame(width: 70, alignment: .trailing)
|
|
}
|
|
}
|
|
.formStyle(.grouped)
|
|
}
|
|
}
|
|
|
|
private struct OutputPreferences: View {
|
|
@AppStorage(Configuration.Keys.outputFilePath) private var outputPath = ""
|
|
@AppStorage(Configuration.Keys.outputFileFilenamePattern) private var pattern = ""
|
|
@AppStorage(Configuration.Keys.outputFileFormat) private var format = OutputFormat.png.rawValue
|
|
@AppStorage(Configuration.Keys.outputFileJpegQuality) private var jpegQuality = 80
|
|
@AppStorage(Configuration.Keys.copyPathToClipboard) private var copyPath = false
|
|
|
|
var body: some View {
|
|
Form {
|
|
HStack {
|
|
Text("Save to:")
|
|
Text(outputPath).lineLimit(1).truncationMode(.middle)
|
|
.foregroundStyle(.secondary)
|
|
Spacer()
|
|
Button("Choose…", action: chooseFolder)
|
|
}
|
|
TextField("Filename pattern:", text: $pattern)
|
|
Text("Variables: ${capturetime}, ${title}, ${appname}, ${user}, ${hostname}, ${mode}, ${NUM}. "
|
|
+ "Example: ${capturetime:d\"yyyy-MM-dd HH_mm_ss\"}-${title}")
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
Picker("Format:", selection: $format) {
|
|
ForEach(OutputFormat.allCases, id: \.rawValue) { item in
|
|
Text(item.displayName).tag(item.rawValue)
|
|
}
|
|
}
|
|
if format == OutputFormat.jpg.rawValue {
|
|
HStack {
|
|
Text("JPEG quality:")
|
|
Slider(value: Binding(get: { Double(jpegQuality) },
|
|
set: { jpegQuality = Int($0) }),
|
|
in: 10...100, step: 5)
|
|
Text("\(jpegQuality)%").frame(width: 50, alignment: .trailing)
|
|
}
|
|
}
|
|
Toggle("Copy the file path to the clipboard after saving", isOn: $copyPath)
|
|
}
|
|
.formStyle(.grouped)
|
|
}
|
|
|
|
private func chooseFolder() {
|
|
let panel = NSOpenPanel()
|
|
panel.canChooseDirectories = true
|
|
panel.canChooseFiles = false
|
|
panel.allowsMultipleSelection = false
|
|
panel.directoryURL = URL(fileURLWithPath: outputPath, isDirectory: true)
|
|
if panel.runModal() == .OK, let url = panel.url {
|
|
outputPath = url.path
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct HotkeyPreferences: View {
|
|
var body: some View {
|
|
Form {
|
|
ForEach(HotkeyAction.allCases, id: \.rawValue) { action in
|
|
HStack {
|
|
Text(action.title)
|
|
Spacer()
|
|
HotkeyRecorder(action: action)
|
|
.frame(width: 150, height: 24)
|
|
}
|
|
}
|
|
Text("Click a shortcut, then press the new combination. Backspace clears it, Esc cancels. "
|
|
+ "A modifier key is required.")
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
.formStyle(.grouped)
|
|
}
|
|
}
|
|
|
|
private struct EditorPreferences: View {
|
|
@AppStorage(Configuration.Keys.editorLineThickness) private var lineThickness = 2
|
|
@AppStorage(Configuration.Keys.editorFontFamily) private var fontFamily = "Helvetica"
|
|
@AppStorage(Configuration.Keys.editorFontSize) private var fontSize = 14
|
|
@AppStorage(Configuration.Keys.editorPixelSize) private var pixelSize = 8
|
|
@AppStorage(Configuration.Keys.editorBlurRadius) private var blurRadius = 12
|
|
@AppStorage(Configuration.Keys.editorDropShadow) private var dropShadow = false
|
|
|
|
var body: some View {
|
|
Form {
|
|
Stepper("Default line thickness: \(lineThickness) px", value: $lineThickness, in: 0...20)
|
|
Picker("Default font:", selection: $fontFamily) {
|
|
ForEach(["Helvetica", "Helvetica Neue", "Menlo", "Times New Roman", "Arial", "Georgia"], id: \.self) {
|
|
Text($0).tag($0)
|
|
}
|
|
}
|
|
Stepper("Default font size: \(fontSize) pt", value: $fontSize, in: 6...96)
|
|
Stepper("Pixelation size: \(pixelSize) px", value: $pixelSize, in: 2...40)
|
|
Stepper("Blur radius: \(blurRadius) px", value: $blurRadius, in: 1...40)
|
|
Toggle("Drop shadow on new elements", isOn: $dropShadow)
|
|
}
|
|
.formStyle(.grouped)
|
|
}
|
|
}
|