| @@ -261,59 +261,115 @@ struct SettingsView: View { |
| 261 | 261 | @AppStorage("reminders") private var reminders = true |
| 262 | 262 | @AppStorage("reminderLead") private var reminderLead = 12 |
| 263 | 263 | @AppStorage("globalCapture") private var globalCapture = true |
| 264 | @AppStorage("settingsTab") private var tab = "general" |
| 264 | 265 | |
| 265 | 266 | var body: some View { |
| 267 | TabView(selection: $tab) { |
| 268 | Tab("General", systemImage: "gearshape", value: "general") { general } |
| 269 | Tab("Editing", systemImage: "text.alignleft", value: "editing") { editing } |
| 270 | Tab("Agenda", systemImage: "calendar", value: "agenda") { agenda } |
| 271 | Tab("Capture", systemImage: "tray.and.arrow.down", value: "capture") { capture } |
| 272 | } |
| 273 | .frame(width: 600) |
| 274 | } |
| 275 | |
| 276 | private var general: some View { |
| 266 | 277 | Form { |
| 267 | | Picker("Save files:", selection: $saveMode) { |
| 268 | | Text("Automatically, when typing stops").tag(SaveMode.automatic) |
| 269 | | Text("Only with File ▸ Save (⌘S)").tag(SaveMode.explicit) |
| 278 | Section { |
| 279 | Picker("Save files", selection: $saveMode) { |
| 280 | Text("Automatically, when typing stops").tag(SaveMode.automatic) |
| 281 | Text("Only with File ▸ Save (⌘S)").tag(SaveMode.explicit) |
| 282 | } |
| 283 | .pickerStyle(.radioGroup) |
| 284 | } |
| 285 | Section { |
| 286 | Picker("Keys", selection: $preset) { |
| 287 | ForEach(KeymapPreset.allCases, id: \.self) { Text($0.title).tag($0) } |
| 288 | } |
| 289 | Picker("Option as Meta", selection: $optionAsMeta) { |
| 290 | Text("Left Option").tag(OptionAsMeta.left.rawValue) |
| 291 | Text("Right Option").tag(OptionAsMeta.right.rawValue) |
| 292 | Text("Both").tag(OptionAsMeta([.left, .right]).rawValue) |
| 293 | Text("Neither").tag(0) |
| 294 | } |
| 295 | } footer: { |
| 296 | Text("Your own bindings go in \(KeymapLoader.userFile.path), on top of the preset.") |
| 297 | .settingsFooter() |
| 298 | } |
| 299 | } |
| 300 | .formStyle(.grouped) |
| 301 | .frame(height: 250) |
| 302 | } |
| 303 | |
| 304 | private var editing: some View { |
| 305 | Form { |
| 306 | Section { |
| 307 | Picker("Tags", selection: $tagsColumn) { |
| 308 | Text("Aligned to end at column 77").tag(-77) |
| 309 | Text("One space after the title").tag(0) |
| 310 | } |
| 311 | Toggle("M-RET adds the new heading after the subtree", isOn: $headingAfterSubtree) |
| 312 | Toggle("M-RET splits the line at the caret", isOn: $splitLine) |
| 313 | Toggle("Lists can use letters (a. b. c.)", isOn: $alphabeticalLists) |
| 314 | Stepper("M-q fills to column \(fillColumn)", value: $fillColumn, in: 40...200) |
| 270 | 315 | } |
| 271 | | .pickerStyle(.radioGroup) |
| 272 | | Picker("Keys:", selection: $preset) { |
| 273 | | ForEach(KeymapPreset.allCases, id: \.self) { Text($0.title).tag($0) } |
| 316 | Section { |
| 317 | Toggle("Emacs hides emphasis markers (org-hide-emphasis-markers)", isOn: $hiddenMarkers) |
| 318 | Toggle("Emacs shows entities as characters (org-pretty-entities)", isOn: $prettyEntities) |
| 319 | } footer: { |
| 320 | Text("Tags, tables and M-q measure text as your Emacs displays it, so both write the same file.") |
| 321 | .settingsFooter() |
| 274 | 322 | } |
| 275 | | Picker("Option as Meta:", selection: $optionAsMeta) { |
| 276 | | Text("Left Option").tag(OptionAsMeta.left.rawValue) |
| 277 | | Text("Right Option").tag(OptionAsMeta.right.rawValue) |
| 278 | | Text("Both").tag(OptionAsMeta([.left, .right]).rawValue) |
| 279 | | Text("Neither").tag(0) |
| 323 | Section { |
| 324 | TextField("Default TODO keywords", text: $todoKeywords) |
| 325 | } footer: { |
| 326 | Text("For files without #+TODO, in #+TODO syntax. Takes effect when Orgstar restarts.") |
| 327 | .settingsFooter() |
| 280 | 328 | } |
| 281 | | Text("Your own bindings go in \(KeymapLoader.userFile.path), on top of the preset.") |
| 282 | | .font(.caption) |
| 283 | | .foregroundStyle(.secondary) |
| 284 | | .textSelection(.enabled) |
| 285 | | Divider() |
| 286 | | Picker("Tags:", selection: $tagsColumn) { |
| 287 | | Text("Aligned to end at column 77").tag(-77) |
| 288 | | Text("One space after the title").tag(0) |
| 329 | } |
| 330 | .formStyle(.grouped) |
| 331 | .frame(height: 450) |
| 332 | } |
| 333 | |
| 334 | private var agenda: some View { |
| 335 | Form { |
| 336 | Section { |
| 337 | Stepper("Agenda shows \(agendaSpan) days", value: $agendaSpan, in: 1...31) |
| 338 | Stepper(agendaStartOffset == 0 ? "Agenda starts today" : "Agenda starts \(-agendaStartOffset) days before today", value: $agendaStartOffset, in: -14...0) |
| 339 | Toggle("Include files in subfolders", isOn: $agendaSubfolders) |
| 340 | } |
| 341 | Section { |
| 342 | Toggle("Notify before timed agenda entries", isOn: $reminders) |
| 343 | Stepper("\(reminderLead) minutes before", value: $reminderLead, in: 0...120) |
| 344 | .disabled(!reminders) |
| 345 | } footer: { |
| 346 | Text("An entry's APPT_WARNTIME property overrides the lead time.") |
| 347 | .settingsFooter() |
| 289 | 348 | } |
| 290 | | Toggle("M-RET adds the new heading after the subtree", isOn: $headingAfterSubtree) |
| 291 | | Toggle("M-RET splits the line at the caret", isOn: $splitLine) |
| 292 | | Toggle("Lists can use letters (a. b. c.)", isOn: $alphabeticalLists) |
| 293 | | Stepper("M-q fills to column \(fillColumn)", value: $fillColumn, in: 40...200) |
| 294 | | Toggle("Emacs hides emphasis markers (org-hide-emphasis-markers)", isOn: $hiddenMarkers) |
| 295 | | Toggle("Emacs shows entities as characters (org-pretty-entities)", isOn: $prettyEntities) |
| 296 | | Text("Tags, tables and M-q measure text as your Emacs displays it, so both write the same file.") |
| 297 | | .font(.caption) |
| 298 | | .foregroundStyle(.secondary) |
| 299 | | TextField("Default TODO keywords:", text: $todoKeywords) |
| 300 | | Text("For files without #+TODO, in #+TODO syntax. Takes effect when Orgstar restarts.") |
| 301 | | .font(.caption) |
| 302 | | .foregroundStyle(.secondary) |
| 303 | | Divider() |
| 304 | | Stepper("Agenda shows \(agendaSpan) days", value: $agendaSpan, in: 1...31) |
| 305 | | Stepper(agendaStartOffset == 0 ? "Agenda starts today" : "Agenda starts \(-agendaStartOffset) days before today", value: $agendaStartOffset, in: -14...0) |
| 306 | | Toggle("Agenda includes files in subfolders", isOn: $agendaSubfolders) |
| 307 | | Toggle("Notify before timed agenda entries", isOn: $reminders) |
| 308 | | Stepper("\(reminderLead) minutes before (APPT_WARNTIME overrides)", value: $reminderLead, in: 0...120) |
| 309 | | .disabled(!reminders) |
| 310 | | Toggle("⌃⌥Space opens Capture from any app", isOn: $globalCapture) |
| 311 | | Text("Templates go in \(CaptureTemplates.userFile.path).") |
| 312 | | .font(.caption) |
| 313 | | .foregroundStyle(.secondary) |
| 314 | | .textSelection(.enabled) |
| 315 | 349 | } |
| 316 | | .padding(20) |
| 317 | | .frame(width: 480) |
| 350 | .formStyle(.grouped) |
| 351 | .frame(height: 290) |
| 352 | } |
| 353 | |
| 354 | private var capture: some View { |
| 355 | Form { |
| 356 | Section { |
| 357 | Toggle("⌃⌥Space opens Capture from any app", isOn: $globalCapture) |
| 358 | } footer: { |
| 359 | Text("Templates go in \(CaptureTemplates.userFile.path).") |
| 360 | .settingsFooter() |
| 361 | } |
| 362 | } |
| 363 | .formStyle(.grouped) |
| 364 | .frame(height: 160) |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | private extension Text { |
| 369 | func settingsFooter() -> some View { |
| 370 | font(.caption) |
| 371 | .foregroundStyle(.secondary) |
| 372 | .textSelection(.enabled) |
| 373 | .frame(maxWidth: .infinity, alignment: .leading) |
| 318 | 374 | } |
| 319 | 375 | } |