-
Notifications
You must be signed in to change notification settings - Fork 254
Example apps — expose all 8 fonts + font-size slider #211
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ca8b125
9878053
3ba000c
090db84
cb98a7d
31546fb
b578164
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,7 @@ | |
|
|
||
| #import "AppDelegate.h" | ||
| #import "MTMathUILabel.h" | ||
| #import "MTFontManager.h" | ||
| #import "../MathExamples.h" | ||
|
|
||
| // Flipped NSView so Auto Layout stacks subviews top-to-bottom. | ||
|
|
@@ -24,6 +25,14 @@ @interface AppDelegate () | |
| @property (weak) IBOutlet NSWindow *window; | ||
| @property (nonatomic, strong) NSMutableArray<MTMathUILabel*>* demoLabels; | ||
| @property (nonatomic, strong) NSMutableArray<MTMathUILabel*>* labels; | ||
| // Height constraints + their startup constants, so the size slider can rescale | ||
| // each label (and the document view) instead of clipping at larger font sizes. | ||
| // Demo labels render at fontSize 15; test labels at the default 20. | ||
| @property (nonatomic, strong) NSMutableArray<NSLayoutConstraint*>* demoHeightConstraints; | ||
| @property (nonatomic, strong) NSMutableArray<NSLayoutConstraint*>* testHeightConstraints; | ||
| @property (nonatomic, strong) NSMutableArray<NSNumber*>* demoBaseHeights; | ||
| @property (nonatomic, strong) NSMutableArray<NSNumber*>* testBaseHeights; | ||
| @property (nonatomic, weak) NSView* documentContentView; | ||
| @end | ||
|
|
||
| @implementation AppDelegate | ||
|
|
@@ -33,15 +42,55 @@ static CGFloat HeightAtIndex(const CGFloat *heights, NSUInteger count, NSUIntege | |
| return (index < count) ? heights[index] : fallback; | ||
| } | ||
|
|
||
| static NSString *const kMacFontNames[] = { | ||
| @"Latin Modern Math", @"TeX Gyre Termes", @"XITS Math", | ||
| @"New Computer Modern", @"TeX Gyre Pagella", @"STIX Two", | ||
| @"Fira Math", @"Noto Sans Math", | ||
| }; | ||
| static const NSUInteger kMacFontCount = 8; | ||
|
|
||
| - (void)applicationDidFinishLaunching:(NSNotification *)aNotification | ||
| { | ||
| self.demoLabels = [[NSMutableArray alloc] init]; | ||
| self.labels = [[NSMutableArray alloc] init]; | ||
| self.demoHeightConstraints = [[NSMutableArray alloc] init]; | ||
| self.testHeightConstraints = [[NSMutableArray alloc] init]; | ||
| self.demoBaseHeights = [[NSMutableArray alloc] init]; | ||
| self.testBaseHeights = [[NSMutableArray alloc] init]; | ||
|
|
||
| NSView* mainView = self.window.contentView; | ||
|
|
||
| // Scroll view fills the window. | ||
| NSScrollView* scrollView = [[NSScrollView alloc] initWithFrame:mainView.bounds]; | ||
| // Header strip: font popup + size slider, pinned to the top of mainView. | ||
| CGFloat headerHeight = 36; | ||
| NSRect headerFrame = NSMakeRect(0, mainView.bounds.size.height - headerHeight, | ||
| mainView.bounds.size.width, headerHeight); | ||
| NSView* headerView = [[NSView alloc] initWithFrame:headerFrame]; | ||
| headerView.autoresizingMask = NSViewWidthSizable | NSViewMinYMargin; | ||
|
|
||
| NSPopUpButton* fontPopup = [[NSPopUpButton alloc] initWithFrame:NSMakeRect(8, 4, 220, 28) pullsDown:NO]; | ||
| for (NSUInteger i = 0; i < kMacFontCount; i++) { | ||
| [fontPopup addItemWithTitle:kMacFontNames[i]]; | ||
| } | ||
| [fontPopup setTarget:self]; | ||
| [fontPopup setAction:@selector(changeFont:)]; | ||
| fontPopup.autoresizingMask = NSViewMaxXMargin; | ||
| [headerView addSubview:fontPopup]; | ||
|
|
||
| NSSlider* sizeSlider = [[NSSlider alloc] initWithFrame:NSMakeRect(236, 8, 200, 20)]; | ||
| sizeSlider.minValue = 10; | ||
| sizeSlider.maxValue = 40; | ||
| sizeSlider.doubleValue = 15; | ||
| sizeSlider.target = self; | ||
| sizeSlider.action = @selector(changeSize:); | ||
| sizeSlider.autoresizingMask = NSViewWidthSizable; | ||
| [headerView addSubview:sizeSlider]; | ||
|
|
||
| [mainView addSubview:headerView]; | ||
|
|
||
| // Scroll view fills the window below the header. | ||
| NSRect scrollFrame = NSMakeRect(0, 0, mainView.bounds.size.width, | ||
| mainView.bounds.size.height - headerHeight); | ||
| NSScrollView* scrollView = [[NSScrollView alloc] initWithFrame:scrollFrame]; | ||
| scrollView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; | ||
| scrollView.hasVerticalScroller = YES; | ||
| scrollView.hasHorizontalScroller = NO; | ||
|
|
@@ -55,6 +104,7 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification | |
| contentView.autoresizingMask = NSViewWidthSizable; | ||
| contentView.backgroundColor = NSColor.whiteColor; | ||
| scrollView.documentView = contentView; | ||
| self.documentContentView = contentView; | ||
|
|
||
| // --- Demo formulae — LaTeX strings from MathExamples.h --- | ||
| static const CGFloat demoHeights[] = { | ||
|
|
@@ -63,9 +113,12 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification | |
| NSArray<NSString*>* demoFormulas = MathDemoFormulas(); | ||
| for (NSUInteger i = 0; i < demoFormulas.count; i++) { | ||
| CGFloat height = HeightAtIndex(demoHeights, sizeof(demoHeights)/sizeof(CGFloat), i, 60); | ||
| MTMathUILabel* label = [self createMathLabel:demoFormulas[i] withHeight:height]; | ||
| MTMathUILabel* label = [[MTMathUILabel alloc] init]; | ||
| label.latex = demoFormulas[i]; | ||
| label.fontSize = 15; | ||
| [self.demoLabels addObject:label]; | ||
| [self.demoHeightConstraints addObject:[self setHeight:height forView:label]]; | ||
| [self.demoBaseHeights addObject:@(height)]; | ||
| } | ||
|
|
||
| [self addLabelAsSubview:self.demoLabels[0] to:contentView]; | ||
|
|
@@ -95,7 +148,11 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification | |
| NSArray<NSString*>* testFormulas = MathTestFormulas(); | ||
| for (NSUInteger i = 0; i < testFormulas.count; i++) { | ||
| CGFloat height = HeightAtIndex(testHeights, sizeof(testHeights)/sizeof(CGFloat), i, 40); | ||
| [self.labels addObject:[self createMathLabel:testFormulas[i] withHeight:height]]; | ||
| MTMathUILabel* label = [[MTMathUILabel alloc] init]; | ||
| label.latex = testFormulas[i]; | ||
| [self.labels addObject:label]; | ||
| [self.testHeightConstraints addObject:[self setHeight:height forView:label]]; | ||
| [self.testBaseHeights addObject:@(height)]; | ||
| } | ||
|
|
||
| CGFloat documentHeight = 10; | ||
|
|
@@ -123,9 +180,7 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification | |
| self.labels[6].contentInsets = NSEdgeInsetsMake(0, 20, 0, 0); | ||
| self.labels[7].backgroundColor = highlight; | ||
| self.labels[7].labelMode = kMTMathUILabelModeText; | ||
| self.labels[8].fontSize = 30; | ||
| self.labels[8].textAlignment = kMTTextAlignmentCenter; | ||
| self.labels[9].fontSize = 10; | ||
| self.labels[9].textAlignment = kMTTextAlignmentCenter; | ||
| self.labels[17].labelMode = kMTMathUILabelModeText; | ||
| self.labels[18].labelMode = kMTMathUILabelModeText; | ||
|
|
@@ -143,16 +198,56 @@ - (void)applicationWillTerminate:(NSNotification *)aNotification | |
| { | ||
| } | ||
|
|
||
| #pragma mark - Label creation helpers | ||
| #pragma mark - Font and size actions | ||
|
|
||
| - (MTMathUILabel*)createMathLabel:(NSString*)latex withHeight:(CGFloat)height | ||
| - (void)changeFont:(NSPopUpButton *)sender | ||
| { | ||
| MTMathUILabel* label = [[MTMathUILabel alloc] init]; | ||
| [self setHeight:height forView:label]; | ||
| label.latex = latex; | ||
| return label; | ||
| NSInteger i = sender.indexOfSelectedItem; | ||
| if (i < 0 || (NSUInteger)i >= kMacFontCount) return; | ||
| // Local (non-static) array: the public MTFontName* constants are runtime | ||
| // `extern NSString *const` values, not compile-time constants, so they can't | ||
| // initialize a file-scope static array. | ||
| NSString *const kMacFontKeys[] = { | ||
| MTFontNameLatinModern, MTFontNameTermes, MTFontNameXITS, | ||
| MTFontNameNewComputerModern, MTFontNamePagella, MTFontNameSTIXTwo, | ||
| MTFontNameFiraMath, MTFontNameNotoSansMath, | ||
| }; | ||
| NSString* key = kMacFontKeys[i]; | ||
| for (MTMathUILabel* label in self.demoLabels) { | ||
| label.font = [[MTFontManager fontManager] fontWithName:key size:label.font.fontSize]; | ||
| } | ||
| for (MTMathUILabel* label in self.labels) { | ||
| label.font = [[MTFontManager fontManager] fontWithName:key size:label.font.fontSize]; | ||
| } | ||
| } | ||
|
Comment on lines
+203
to
+222
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Define the - (void)changeFont:(NSPopUpButton *)sender
{
NSInteger i = sender.indexOfSelectedItem;
if (i < 0 || (NSUInteger)i >= kMacFontCount) return;
NSString *const kMacFontKeys[] = {
MTFontNameLatinModern, MTFontNameTermes, MTFontNameXITS,
MTFontNameNewComputerModern, MTFontNamePagella, MTFontNameSTIXTwo,
MTFontNameFiraMath, MTFontNameNotoSansMath,
};
NSString* key = kMacFontKeys[i];
for (MTMathUILabel* label in self.demoLabels) {
label.font = [[MTFontManager fontManager] fontWithName:key size:label.font.fontSize];
}
for (MTMathUILabel* label in self.labels) {
label.font = [[MTFontManager fontManager] fontWithName:key size:label.font.fontSize];
}
}
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in cb98a7d — kMacFontKeys is now a local array in changeFont: built from MTFontNameLatinModern, MTFontNameTermes, etc. |
||
|
|
||
| - (void)changeSize:(NSSlider *)sender | ||
| { | ||
| CGFloat size = (CGFloat)sender.doubleValue; | ||
| // Scale each label's height from its startup baseline (demo 15, test 20) and | ||
| // grow the document view to match so formulas aren't clipped at larger sizes. | ||
| CGFloat documentHeight = 10; // top inset | ||
| for (NSUInteger i = 0; i < self.demoLabels.count; i++) { | ||
| self.demoLabels[i].fontSize = size; | ||
| CGFloat h = self.demoBaseHeights[i].doubleValue * (size / 15.0); | ||
| self.demoHeightConstraints[i].constant = h; | ||
| documentHeight += h + 10; | ||
| } | ||
| documentHeight += 30; // gap between sections | ||
| for (NSUInteger i = 0; i < self.labels.count; i++) { | ||
| self.labels[i].fontSize = size; | ||
| CGFloat h = self.testBaseHeights[i].doubleValue * (size / 20.0); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The test formulas at indices 8 and 9 have baseline font sizes of 30 and 10 respectively, rather than the default 20. Scaling their heights using a hardcoded baseline of 20.0 will cause incorrect layout heights (potentially clipping at smaller sizes or leaving excessive empty space). Consider scaling them using their correct baseline font sizes, similar to the logic implemented in the Swift example. CGFloat baseline = 20.0;
if (i == 8) baseline = 30.0;
else if (i == 9) baseline = 10.0;
CGFloat h = self.testBaseHeights[i].doubleValue * (size / baseline);
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't apply to the macOS example as it currently stands. The per-label |
||
| self.testHeightConstraints[i].constant = h; | ||
| documentHeight += h + 10; | ||
| } | ||
| NSView* contentView = self.documentContentView; | ||
| NSRect frame = contentView.frame; | ||
| frame.size.height = documentHeight; | ||
| contentView.frame = frame; | ||
| } | ||
|
Comment on lines
+224
to
+247
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When the font size is changed dynamically via the slider, the labels' font sizes are updated, but their height constraints (which are fixed at startup) and the content view's frame height are not updated. This causes the math formulas to be vertically clipped when the font size is increased, and the scrollable area will not adjust correctly. Consider dynamically scaling the height constraints of the labels and the content view's frame height proportionally to the font size ratio (
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 090db84. changeSize: now rescales each label height constraint from its baseline (demo 15, test 20) and grows the document view frame height to match. |
||
|
|
||
| #pragma mark - Label creation helpers | ||
|
|
||
| - (void)addLabelWithIndex:(NSUInteger)idx inArray:(NSArray<MTMathUILabel*>*)array toView:(NSView*)contentView | ||
| { | ||
| NSAssert(idx > 0, @"Index should be greater than 0. For the first label add manually."); | ||
|
|
@@ -172,15 +267,17 @@ - (void)addLabelAsSubview:(NSView*)label to:(NSView*)parent | |
| options:0 metrics:nil views:views]]; | ||
| } | ||
|
|
||
| - (void)setHeight:(CGFloat)height forView:(NSView*)view | ||
| - (NSLayoutConstraint*)setHeight:(CGFloat)height forView:(NSView*)view | ||
| { | ||
| view.translatesAutoresizingMaskIntoConstraints = NO; | ||
| [NSLayoutConstraint constraintWithItem:view | ||
| NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem:view | ||
| attribute:NSLayoutAttributeHeight | ||
| relatedBy:NSLayoutRelationEqual | ||
| toItem:nil | ||
| attribute:NSLayoutAttributeNotAnAttribute | ||
| multiplier:1 constant:height].active = YES; | ||
| multiplier:1 constant:height]; | ||
| constraint.active = YES; | ||
| return constraint; | ||
| } | ||
|
|
||
| - (void)setVerticalGap:(CGFloat)gap between:(NSView*)view1 and:(NSView*)view2 | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of duplicating the raw string literals for the font keys in a global static array, we can define
kMacFontKeyslocally inside thechangeFont:method using the newly exposed public constants (MTFontNameLatinModern, etc.) fromMTFontManager.h. This improves maintainability and keeps the implementation consistent withViewController.m.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in cb98a7d, using the public MTFontName* constants to match the iOS example. The array had to move local to changeFont: rather than stay a file-scope static — the constants are runtime
extern NSString *constvalues, not compile-time constants, so they can't initialize a static array.