Skip to content
Merged
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
127 changes: 112 additions & 15 deletions MacOSMathExample/AppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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;
Comment on lines +45 to +50
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Instead of duplicating the raw string literals for the font keys in a global static array, we can define kMacFontKeys locally inside the changeFont: method using the newly exposed public constants (MTFontNameLatinModern, etc.) from MTFontManager.h. This improves maintainability and keeps the implementation consistent with ViewController.m.

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;

Copy link
Copy Markdown
Owner Author

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 *const values, not compile-time constants, so they can't initialize a static array.


- (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;
Expand All @@ -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[] = {
Expand All @@ -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];
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Define the kMacFontKeys array locally using the public constants from MTFontManager.h to avoid hardcoded string literals.

- (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];
    }
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The 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);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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);

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The 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 labels[8].fontSize = 30 / labels[9].fontSize = 10 overrides were removed in this PR (see the PR description) — current code sets only textAlignment for those indices. Every test label now renders at the default MTMathUILabel.fontSize of 20 (MTMathUILabel.m:44), so size / 20.0 is correct for all of them. Special-casing 30/10 here would scale indices 8/9 against a baseline they no longer use and clip/over-size them. The per-entry baselines still legitimately exist in the Swift gallery because those formula structs carry their own fontSize; iOS/macOS no longer do.

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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

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 (size / 15.0), or transition to a fully dynamic Auto Layout system without fixed height constraints.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The 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.");
Expand All @@ -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
Expand Down
25 changes: 0 additions & 25 deletions MacOSMathExample/Base.lproj/MainMenu.xib
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate">
<connections>
<outlet property="inputTextField" destination="3eF-aq-wq7" id="ZaO-Km-dmc"/>
<outlet property="screen" destination="JGc-8F-Tcp" id="k46-7h-xbX"/>
<outlet property="window" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
</connections>
</customObject>
Expand Down Expand Up @@ -690,29 +688,6 @@
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rQu-NO-fcw">
<rect key="frame" x="200" y="13" width="81" height="32"/>
<buttonCell key="cell" type="push" title="Update!" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="q3o-Jo-ri0">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="clickUpdateButton:" target="Voe-Tx-rLC" id="pNr-c5-o7t"/>
</connections>
</button>
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3eF-aq-wq7">
<rect key="frame" x="20" y="49" width="440" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="Enter LaTeX here..." drawsBackground="YES" id="w3t-RT-Vy0">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JGc-8F-Tcp" customClass="MTMathUILabel">
<rect key="frame" x="20" y="79" width="440" height="261"/>
</customView>
</subviews>
</view>
</window>
</objects>
Expand Down
Loading
Loading