Skip to content
Draft
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
8 changes: 8 additions & 0 deletions MacDown 3000.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
03224E1B02E36783D5307F4A /* MPDocumentIOTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 35FB5AC5D9A67BFB58A9430F /* MPDocumentIOTests.m */; };
0A33AF1E979F50E868FEE7DC /* libPods-MacDownCore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F2375876A05ADEB6544CB4EB /* libPods-MacDownCore.a */; };
1457815B1A710E4C40F07FCA /* MPPaneToggleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E44CF1BD72E49A99DA6A4C1 /* MPPaneToggleTests.m */; };
A1B2C3D4E5F67890ABCDEF12 /* MPZoomTests.m in Sources */ = {isa = PBXBuildFile; fileRef = B2C3D4E5F67890ABCDEF1234 /* MPZoomTests.m */; };
197TESTS0B00000000197RSTB /* MPRendererStateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 197TESTS0F00000000197RSTF /* MPRendererStateTests.m */; };
1F002A23195B3DAE008B8D93 /* MPRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F002A22195B3DAE008B8D93 /* MPRenderer.m */; };
1F0D9D65194AC7CF008E1856 /* NSString+Lookup.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F0D9D5F194AC7CF008E1856 /* NSString+Lookup.m */; };
Expand Down Expand Up @@ -119,6 +120,7 @@
BA2B9EC2E95175092A97B41E /* MPResourceWatcherSet.m in Sources */ = {isa = PBXBuildFile; fileRef = E6D070A6E080254A17B3B197 /* MPResourceWatcherSet.m */; };
CCD97578A2886FFE73BD96F7 /* MPMathJaxRenderingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6811F39B13C649FC86C4CE5B /* MPMathJaxRenderingTests.m */; };
CHKBOXTGL0001BUILDFILER /* MPCheckboxToggleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CHKBOXTGL0001FILEREFID /* MPCheckboxToggleTests.m */; };
PRVZMTST0001BUILDFILER /* MPPreviewZoomTests.m in Sources */ = {isa = PBXBuildFile; fileRef = PRVZMTST0001FILEREFID /* MPPreviewZoomTests.m */; };
D29776CC6E7EB5B4AA2E0537 /* MPFileWatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = A81247E840EB5C07669FF165 /* MPFileWatcher.m */; };
D3877A6637DE48017448C8DB /* MPRendererTestHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E2FC4B9389A012264DC6214 /* MPRendererTestHelpers.m */; };
DCD310373F0CCB56C7DFD720 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FEC7D0105F2CD0464F4B6AA /* Quartz.framework */; };
Expand Down Expand Up @@ -590,6 +592,7 @@
5C2E23A49DBCCD5CFA3B8104 /* libPods-MacDownQuickLook.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-MacDownQuickLook.a"; sourceTree = BUILT_PRODUCTS_DIR; };
5CE5C37476A61D05FCC741F9 /* MPQuickLookPreferences.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = MacDownCore/MPQuickLookPreferences.h; sourceTree = SOURCE_ROOT; };
5E44CF1BD72E49A99DA6A4C1 /* MPPaneToggleTests.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = MPPaneToggleTests.m; sourceTree = "<group>"; };
B2C3D4E5F67890ABCDEF1234 /* MPZoomTests.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = MPZoomTests.m; sourceTree = "<group>"; };
5F23020AD4494E700E72C264 /* MPRendererTestHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRendererTestHelpers.h; sourceTree = "<group>"; };
615588251EB35DEE6204B94E /* MPResourceWatcherSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPResourceWatcherSet.h; sourceTree = "<group>"; };
6811F39B13C649FC86C4CE5B /* MPMathJaxRenderingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPMathJaxRenderingTests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -626,6 +629,7 @@
CHKBOXTGL0001FILEREFID /* MPCheckboxToggleTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPCheckboxToggleTests.m; sourceTree = "<group>"; };
D30FDB4BDFBD13C1577ECFB4 /* MacDownCore.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = MacDownCore/MacDownCore.h; sourceTree = SOURCE_ROOT; };
D80F0F27E815934603CB0A05 /* MacDownQuickLook.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = MacDownQuickLook.appex; sourceTree = BUILT_PRODUCTS_DIR; };
PRVZMTST0001FILEREFID /* MPPreviewZoomTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPreviewZoomTests.m; sourceTree = "<group>"; };
DDDB87873110C02114439C2C /* MPFileWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFileWatcher.h; sourceTree = "<group>"; };
E64879065D20A4124AD56945 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = MacDownQuickLook/Info.plist; sourceTree = SOURCE_ROOT; };
E6D070A6E080254A17B3B197 /* MPResourceWatcherSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPResourceWatcherSet.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1086,6 +1090,7 @@
197TESTS0F00000000197RSTF /* MPRendererStateTests.m */,
C2B84BF8A8BC4F4B871646F8 /* MPScrollSyncTests.m */,
CHKBOXTGL0001FILEREFID /* MPCheckboxToggleTests.m */,
PRVZMTST0001FILEREFID /* MPPreviewZoomTests.m */,
ISSUE285SMARTQTFILEREF /* MPSmartQuoteTests.m */,
1FFEB3261972DAB400B2254F /* MPHTMLTabularizeTests.m */,
1FFEB32F19ABCD1500B2254F /* MPMarkdownRenderingTests.m */,
Expand Down Expand Up @@ -1119,6 +1124,7 @@
QLTST00002PREF00000M /* MPQuickLookPreferencesTests.m */,
QLTST00003PVCT00000M /* MPPreviewViewControllerTests.m */,
5E44CF1BD72E49A99DA6A4C1 /* MPPaneToggleTests.m */,
B2C3D4E5F67890ABCDEF1234 /* MPZoomTests.m */,
);
path = MacDownTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -1779,6 +1785,7 @@
03224E1B02E36783D5307F4A /* MPDocumentIOTests.m in Sources */,
B9A8DE030E3748EB899BD45E /* MPScrollSyncTests.m in Sources */,
CHKBOXTGL0001BUILDFILER /* MPCheckboxToggleTests.m in Sources */,
PRVZMTST0001BUILDFILER /* MPPreviewZoomTests.m in Sources */,
ISSUE285SMARTQTBUILDFILE /* MPSmartQuoteTests.m in Sources */,
1F51C9A5194565050015A96F /* MPPreferencesTests.m in Sources */,
1FF1420419A8A24800CF8A6A /* MPUtilityTests.m in Sources */,
Expand Down Expand Up @@ -1820,6 +1827,7 @@
QLBLD00005PREFTESTSRC /* MPQuickLookPreferencesTests.m in Sources */,
QLBLD00006PVCTESTSRC0 /* MPPreviewViewControllerTests.m in Sources */,
1457815B1A710E4C40F07FCA /* MPPaneToggleTests.m in Sources */,
A1B2C3D4E5F67890ABCDEF12 /* MPZoomTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
134 changes: 126 additions & 8 deletions MacDown/Code/Application/MPToolbarController.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,24 @@
//

#import "MPToolbarController.h"
#import "MPPreferences.h"

// Because we're creating selectors for methods which aren't in this class
#pragma GCC diagnostic ignored "-Wundeclared-selector"
#pragma clang diagnostic ignored "-Wundeclared-selector"


static CGFloat itemWidth = 37;
// Document-zoom presets must match MPDocumentZoomLevels() in MPDocument.m.
static NSArray<NSNumber *> *MPToolbarDocumentZoomLevels(void)
{
static NSArray *levels = nil;
static dispatch_once_t token;
dispatch_once(&token, ^{
levels = @[@0.5, @0.75, @0.9, @1.0, @1.1, @1.25, @1.5, @2.0, @3.0];
});
return levels;
}


@implementation MPToolbarController
Expand All @@ -33,24 +44,60 @@ @implementation MPToolbarController
* created, so we can't set target = self.document at construction time.
*/
NSMutableDictionary<NSString *, NSString *> *standaloneItemActions;

/**
* Weak reference to the zoom popup so we can re-sync its selected item
* when the preference changes from elsewhere (menu, keyboard shortcut).
*/
__weak NSPopUpButton *_zoomPopUp;
}

- (id)init
{
self = [super init];

if (!self)
{
return nil;
}

self->toolbarItemIdentifierObjectDictionary = [NSMutableDictionary new];
self->standaloneItemActions = [NSMutableDictionary new];
[self setupToolbarItems];


// Observe NSUserDefaults so the popup's selection reflects external
// changes (View menu actions, ⌘+/⌘-/⌘0). Using KVO on the standard
// defaults avoids threading a sync callback through MPDocument.
[[NSUserDefaults standardUserDefaults]
addObserver:self
forKeyPath:@"documentZoomLevel"
options:NSKeyValueObservingOptionNew
context:NULL];

return self;
}

- (void)dealloc
{
@try {
[[NSUserDefaults standardUserDefaults]
removeObserver:self forKeyPath:@"documentZoomLevel"];
} @catch (NSException *exception) {
// removeObserver may throw if not registered; ignore on teardown.
}
}

- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey,id> *)change
context:(void *)context
{
if ([keyPath isEqualToString:@"documentZoomLevel"])
{
[self syncDocumentZoomDisplay];
}
}


#pragma mark - Private

Expand Down Expand Up @@ -97,10 +144,14 @@ - (void)setupToolbarItems
@[
toggleEditorMenuItem, togglePreviewMenuItem
]
]
],
[self toolbarItemDocumentZoomPopUpWithIdentifier:@"document-zoom" label:NSLocalizedString(@"Zoom", @"Preview pane zoom toolbar item")]
];

self->toolbarItemIdentifiers = [self toolbarItemIdentifiersFromItemsArray:self->toolbarItems];

// Reflect the persisted preference once everything is wired up.
[self syncDocumentZoomDisplay];
}

/**
Expand Down Expand Up @@ -400,13 +451,80 @@ - (NSToolbarItem *)toolbarItemDropDownWithIdentifier:(NSString *)itemIdentifier
[[popupButton lastItem] setTarget:self];
[[popupButton lastItem] setAction:@selector(dropdownMenuItemClicked:)];
}

toolbarItem.view = popupButton;

[self->toolbarItemIdentifierObjectDictionary setObject:toolbarItem forKey:itemIdentifier];

return toolbarItem;
}

/**
* Factory method for the document-zoom popup. Unlike the layout dropdown
* this is a regular (non-pull-down) NSPopUpButton: the currently selected
* item is shown as the button label so the user sees the active zoom
* percentage at a glance. Each menu item is wired to
* -selectDocumentZoom: on the document, with the target zoom level
* (NSNumber) attached as the item's representedObject.
*/
- (NSToolbarItem *)toolbarItemDocumentZoomPopUpWithIdentifier:(NSString *)itemIdentifier label:(NSString *)label
{
NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
toolbarItem.label = label;
toolbarItem.paletteLabel = label;
toolbarItem.toolTip = label;

NSPopUpButton *popupButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(0, 0, 70, 27) pullsDown:NO];
popupButton.bezelStyle = NSBezelStyleTexturedRounded;
popupButton.focusRingType = NSFocusRingTypeDefault;

NSArray<NSNumber *> *levels = MPToolbarDocumentZoomLevels();
for (NSNumber *level in levels)
{
NSString *title = [NSString stringWithFormat:@"%.0f%%", level.doubleValue * 100.0];
[popupButton addItemWithTitle:title];
NSMenuItem *added = [popupButton lastItem];
added.representedObject = level;
added.target = self.document;
added.action = @selector(selectDocumentZoom:);
}

toolbarItem.view = popupButton;

[self->toolbarItemIdentifierObjectDictionary setObject:toolbarItem forKey:itemIdentifier];
_zoomPopUp = popupButton;

return toolbarItem;
}

/**
* Update the popup's selection to match the current document-zoom
* preference. If the current preference matches a preset (within
* epsilon), that item is selected. Otherwise the popup falls back to
* the closest preset so the button always shows a sensible label.
*/
- (void)syncDocumentZoomDisplay
{
NSPopUpButton *popup = _zoomPopUp;
if (!popup)
return;

CGFloat current = [MPPreferences sharedInstance].documentZoomLevel;
NSArray<NSNumber *> *levels = MPToolbarDocumentZoomLevels();

NSUInteger nearestIdx = 0;
CGFloat bestDiff = CGFLOAT_MAX;
for (NSUInteger i = 0; i < levels.count; i++)
{
CGFloat diff = fabs(levels[i].doubleValue - current);
if (diff < bestDiff)
{
bestDiff = diff;
nearestIdx = i;
}
}
[popup selectItemAtIndex:(NSInteger)nearestIdx];
}


@end
10 changes: 10 additions & 0 deletions MacDown/Code/Document/MPDocument.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,14 @@
*/
+ (NSString *)toggleCheckboxAtIndex:(NSUInteger)index inMarkdown:(NSString *)markdown;

/**
* Set the shared document zoom to the level represented by the sender's
* representedObject (NSNumber). Sender may be an NSMenuItem or
* NSPopUpButton; the toolbar dropdown uses this entry point.
*/
- (IBAction)selectDocumentZoom:(id)sender;
- (IBAction)zoomIn:(id)sender;
- (IBAction)zoomOut:(id)sender;
- (IBAction)resetZoom:(id)sender;

@end
Loading