diff --git a/Beat iOS/Localizable.strings b/Beat iOS/Localizable.strings
index b1ada51f..6c93f9ac 100644
--- a/Beat iOS/Localizable.strings
+++ b/Beat iOS/Localizable.strings
@@ -129,3 +129,16 @@
"cards.addScene" = "Add New Scene Here";
"cards.addScenePrompt" = "Heading For New Scene";
+
+/* Fonts (Settings) */
+"settings.customFonts" = "Fonts";
+"settings.screenplayFonts" = "Screenplay Fonts";
+"settings.customScreenplayFont" = "Choose Screenplay Font…";
+"settings.useDefaultScreenplayFont" = "Use Built-In Screenplay Font";
+"settings.novelFonts" = "Novel Fonts";
+"settings.customNovelFont" = "Choose Novel Font…";
+"settings.useDefaultNovelFont" = "Use Default Novel Font";
+"settings.useDefaultFonts" = "Use Default Fonts";
+"settings.notMonospaced.title" = "Not Monospaced";
+"settings.notMonospaced.message" = "This font isn't monospaced, so page counts may differ from the standard ~1 page per minute.";
+"general.OK" = "OK";
diff --git a/Beat iOS/User Interface Views/Settings/BeatSettingsControllers.swift b/Beat iOS/User Interface Views/Settings/BeatSettingsControllers.swift
index 221c1537..2215ed80 100644
--- a/Beat iOS/User Interface Views/Settings/BeatSettingsControllers.swift
+++ b/Beat iOS/User Interface Views/Settings/BeatSettingsControllers.swift
@@ -84,9 +84,12 @@ class BeatSettingsViewController:UITableViewController {
@IBOutlet weak var synopsisFontType:UIButton?
@IBOutlet weak var fontStyleButton:UIButton?
-
+
/// Font size switch is only available on iPhone
@IBOutlet var fontSizeSwitch:UISegmentedControl?
+
+ private var activeFontSettingKey:String?
+ private var activeFontRequiresMonospaced = false
override func viewDidLoad() {
super.viewDidLoad()
@@ -113,6 +116,9 @@ class BeatSettingsViewController:UITableViewController {
if let fontStyleMenu = fontStyleButton?.menu, style < fontStyleMenu.children.count {
(fontStyleMenu.children[style] as? UICommand)?.state = .on
}
+
+ self.migrateLegacyCustomFonts()
+ self.setupCustomFontMenu()
if let stylesheet = self.delegate?.styles.name,
let availableStyles = stylesheetSwitch?.stylesheets.split(separator: ",") {
@@ -311,13 +317,146 @@ class BeatSettingsViewController:UITableViewController {
// This is a little hacky. 0 = serif, 1 = sans serif, 2 = courier new
BeatUserDefaults.shared().save(style, forKey: BeatSettingFontStyle)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomScreenplayFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomScreenplayEditorFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomScreenplayExportFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomEditorFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomExportFont)
print("New font style:", style)
+ self.applyFontChange()
+ }
+
+ // MARK: Custom fonts
+
+ private func setupCustomFontMenu() {
+ guard let button = fontStyleButton else { return }
+ let existing = button.menu?.children ?? []
+
+ let screenplayCustomAction = UIAction(title: NSLocalizedString("settings.customScreenplayFont", comment: "")) { [weak self] _ in
+ self?.presentFontPicker(for: BeatSettingCustomScreenplayFont, requiresMonospaced: true)
+ }
+ let screenplayDefaultAction = UIAction(title: NSLocalizedString("settings.useDefaultScreenplayFont", comment: "")) { [weak self] _ in
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomScreenplayFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomScreenplayEditorFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomScreenplayExportFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomEditorFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomExportFont)
+ self?.applyFontChange()
+ }
+ let novelCustomAction = UIAction(title: NSLocalizedString("settings.customNovelFont", comment: "")) { [weak self] _ in
+ self?.presentFontPicker(for: BeatSettingCustomNovelFont, requiresMonospaced: false)
+ }
+ let novelDefaultAction = UIAction(title: NSLocalizedString("settings.useDefaultNovelFont", comment: "")) { [weak self] _ in
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomNovelFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomNovelEditorFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomNovelExportFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomEditorFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomExportFont)
+ self?.applyFontChange()
+ }
+ let resetAction = UIAction(title: NSLocalizedString("settings.useDefaultFonts", comment: "")) { [weak self] _ in
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomEditorFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomExportFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomScreenplayFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomNovelFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomScreenplayEditorFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomScreenplayExportFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomNovelEditorFont)
+ BeatUserDefaults.shared().save("", forKey: BeatSettingCustomNovelExportFont)
+ self?.applyFontChange()
+ }
+
+ let screenplayMenu = UIMenu(title: NSLocalizedString("settings.screenplayFonts", comment: ""),
+ options: .displayInline,
+ children: [screenplayCustomAction, screenplayDefaultAction])
+ let novelMenu = UIMenu(title: NSLocalizedString("settings.novelFonts", comment: ""),
+ options: .displayInline,
+ children: [novelCustomAction, novelDefaultAction])
+ let resetMenu = UIMenu(title: "", options: .displayInline, children: [resetAction])
+ button.menu = UIMenu(children: existing + [screenplayMenu, novelMenu, resetMenu])
+ }
+
+ private func migrateLegacyCustomFonts() {
+ let defaults = BeatUserDefaults.shared()
+ var screenplayFont = defaults.get(BeatSettingCustomScreenplayFont) as? String ?? ""
+ var novelFont = defaults.get(BeatSettingCustomNovelFont) as? String ?? ""
+
+ if let editorFont = defaults.get(BeatSettingCustomEditorFont) as? String,
+ !editorFont.isEmpty,
+ screenplayFont.isEmpty,
+ novelFont.isEmpty {
+ defaults.save(editorFont, forKey: BeatSettingCustomScreenplayFont)
+ defaults.save(editorFont, forKey: BeatSettingCustomNovelFont)
+ screenplayFont = editorFont
+ novelFont = editorFont
+ }
+
+ if let exportFont = defaults.get(BeatSettingCustomExportFont) as? String,
+ !exportFont.isEmpty,
+ screenplayFont.isEmpty,
+ novelFont.isEmpty {
+ defaults.save(exportFont, forKey: BeatSettingCustomScreenplayFont)
+ defaults.save(exportFont, forKey: BeatSettingCustomNovelFont)
+ }
+
+ if screenplayFont.isEmpty,
+ let legacyScreenplayFont = defaults.get(BeatSettingCustomScreenplayEditorFont) as? String,
+ !legacyScreenplayFont.isEmpty {
+ defaults.save(legacyScreenplayFont, forKey: BeatSettingCustomScreenplayFont)
+ }
+ if novelFont.isEmpty,
+ let legacyNovelFont = defaults.get(BeatSettingCustomNovelEditorFont) as? String,
+ !legacyNovelFont.isEmpty {
+ defaults.save(legacyNovelFont, forKey: BeatSettingCustomNovelFont)
+ }
+ }
+
+ private func presentFontPicker(for settingKey:String, requiresMonospaced:Bool) {
+ self.activeFontSettingKey = settingKey
+ self.activeFontRequiresMonospaced = requiresMonospaced
+
+ let config = UIFontPickerViewController.Configuration()
+ config.includeFaces = true
+ let picker = UIFontPickerViewController(configuration: config)
+ picker.delegate = self
+ self.present(picker, animated: true)
+ }
+
+ fileprivate func applyFontChange() {
+ self.delegate?.reloadFonts()
self.delegate?.reloadStyles()
self.delegate?.formatting.formatAllLines()
+ self.delegate?.invalidatePreview()
+ }
+
+}
+
+extension BeatSettingsViewController:UIFontPickerViewControllerDelegate {
+ func fontPickerViewControllerDidPickFont(_ viewController: UIFontPickerViewController) {
+ viewController.dismiss(animated: true)
+
+ guard let key = self.activeFontSettingKey,
+ let descriptor = viewController.selectedFontDescriptor
+ else { return }
+
+ let font = UIFont(descriptor: descriptor, size: 12.0)
+ BeatUserDefaults.shared().save(font.fontName, forKey: key)
+ self.applyFontChange()
+
+ if self.activeFontRequiresMonospaced && !font.fontDescriptor.symbolicTraits.contains(.traitMonoSpace) {
+ let alert = UIAlertController(title: NSLocalizedString("settings.notMonospaced.title", comment: ""),
+ message: NSLocalizedString("settings.notMonospaced.message", comment: ""),
+ preferredStyle: .alert)
+ alert.addAction(UIAlertAction(title: NSLocalizedString("general.OK", comment: ""), style: .default))
+ self.present(alert, animated: true)
+ }
+ }
+
+ func fontPickerViewControllerDidCancel(_ viewController: UIFontPickerViewController) {
+ viewController.dismiss(animated: true)
}
-
}
class BeatURLButton:UIButton {
@@ -351,4 +490,3 @@ extension UIButton {
(menu.children[index] as? UIAction)?.state = .on
}
}
-
diff --git a/Beat/Text Editor View/BeatTextView.m b/Beat/Text Editor View/BeatTextView.m
index 0d681acc..b55f692e 100755
--- a/Beat/Text Editor View/BeatTextView.m
+++ b/Beat/Text Editor View/BeatTextView.m
@@ -205,9 +205,15 @@ -(void)setup
self.layoutManager.allowsNonContiguousLayout = YES;
NSSpellChecker.sharedSpellChecker.automaticallyIdentifiesLanguages = true;
+ CGFloat lineHeight = self.editorDelegate.editorStyles.page.lineHeight;
+ if (_editorDelegate.fonts.custom) {
+ BXFont* font = _editorDelegate.fonts.regular;
+ lineHeight = MAX(lineHeight, ceil(font.ascender - font.descender + font.leading));
+ }
+
NSMutableParagraphStyle *paragraphStyle = NSMutableParagraphStyle.new;
- paragraphStyle.maximumLineHeight = self.editorDelegate.editorStyles.page.lineHeight;
- paragraphStyle.minimumLineHeight = self.editorDelegate.editorStyles.page.lineHeight;
+ paragraphStyle.maximumLineHeight = lineHeight;
+ paragraphStyle.minimumLineHeight = lineHeight;
paragraphStyle.lineSpacing = 1.0;
[self setDefaultParagraphStyle:paragraphStyle];
diff --git a/Beat/User Interface Views/Preferences/Base.lproj/BeatPreferencesPanel.xib b/Beat/User Interface Views/Preferences/Base.lproj/BeatPreferencesPanel.xib
index 9a99186f..aaa3d61f 100644
--- a/Beat/User Interface Views/Preferences/Base.lproj/BeatPreferencesPanel.xib
+++ b/Beat/User Interface Views/Preferences/Base.lproj/BeatPreferencesPanel.xib
@@ -19,6 +19,10 @@
+
+
+
+
@@ -46,24 +50,24 @@
-
+
-
+
-
+
-
+
-
+
@@ -83,7 +87,7 @@
-
+
-
+
-
+
@@ -124,15 +128,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
@@ -141,7 +190,7 @@
-
+
@@ -153,7 +202,7 @@
-
+
@@ -173,7 +222,7 @@
-
+
@@ -215,19 +264,19 @@
-
+
-
+
-
+
-
+
@@ -257,7 +306,7 @@
-
+
@@ -266,7 +315,7 @@