/core/externals/google-toolbox-for-mac/AppKit/GTMUILocalizerAndLayoutTweaker.m
http://macfuse.googlecode.com/ · Objective C · 655 lines · 450 code · 80 blank · 125 comment · 70 complexity · 1a94270b2e1fee7b840d0033ef5e88d7 MD5 · raw file
- //
- // GTMUILocalizerAndLayoutTweaker.m
- //
- // Copyright 2009 Google Inc.
- //
- // Licensed under the Apache License, Version 2.0 (the "License"); you may not
- // use this file except in compliance with the License. You may obtain a copy
- // of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- // License for the specific language governing permissions and limitations under
- // the License.
- //
- #import "GTMUILocalizerAndLayoutTweaker.h"
- #import "GTMUILocalizer.h"
- // Controls if +wrapString:width:font: uses a subclassed TypeSetter to do
- // its work in one pass.
- #define GTM_USE_TYPESETTER 1
- // Helper that will try to do a SizeToFit on any UI items and do the special
- // case handling we also need to end up with a usable UI item. It also takes
- // an offset so we can slide the item if we need to.
- // Returns the change in the view's size.
- static NSSize SizeToFit(NSView *view, NSPoint offset);
- // Compare function for -[NSArray sortedArrayUsingFunction:context:]
- static NSInteger CompareFrameX(id view1, id view2, void *context);
- // Check if the view is anchored on the right (fixed right, flexible left).
- static BOOL IsRightAnchored(NSView *view);
- // Constant for a forced string wrap in button cells (Opt-Return in IB inserts
- // this into the string).
- NSString * const kForcedWrapString = @"\xA";
- // Radio and Checkboxes (NSButtonCell) appears to use two different layout
- // algorithms for sizeToFit calls and drawing calls when there is a forced word
- // wrap in the title. The result is a sizeToFit can tell you it all fits N
- // lines in the given rect, but at draw time, it draws as >N lines and never
- // gets as wide, resulting in a clipped control. This fudge factor is what is
- // added to try and avoid these by giving the size calls just enough slop to
- // handle the differences.
- // radar://7831901 different wrapping between sizeToFit and drawing
- static const CGFloat kWrapperStringSlop = 0.9;
- #if GTM_USE_TYPESETTER
- @interface GTMBreakRecordingTypeSetter : NSATSTypesetter {
- @private
- NSMutableArray *array_;
- }
- @end
- @implementation GTMBreakRecordingTypeSetter
- - (id)init {
- if ((self = [super init])) {
- array_ = [[NSMutableArray alloc] init];
- }
- return self;
- }
- - (void)dealloc {
- [array_ release];
- [super dealloc];
- }
- - (BOOL)shouldBreakLineByWordBeforeCharacterAtIndex:(NSUInteger)charIndex {
- [array_ addObject:[NSNumber numberWithUnsignedInteger:charIndex]];
- return YES;
- }
- - (NSArray*)breakArray {
- return array_;
- }
- @end
- #endif // GTM_USE_TYPESETTER
- @interface GTMUILocalizerAndLayoutTweaker (PrivateMethods)
- // Recursively walk the UI triggering Tweakers.
- - (void)tweakView:(NSView *)view;
- // Insert newlines so the string wraps to the given width using the requested
- // font.
- + (NSString*)wrapString:(NSString *)string
- width:(CGFloat)width
- font:(NSFont *)font;
- @end
- @interface GTMWidthBasedTweaker (InternalMethods)
- // Does the actual work to size and adjust the views within this Tweaker. The
- // offset is the amount this view should shift as part of it's resize.
- // Returns change in this view's width.
- - (CGFloat)tweakLayoutWithOffset:(NSPoint)offset;
- @end
- @implementation GTMUILocalizerAndLayoutTweaker
- - (void)awakeFromNib {
- if (uiObject_) {
- GTMUILocalizer *localizer = localizer_;
- if (!localizer) {
- NSBundle *bundle = [GTMUILocalizer bundleForOwner:localizerOwner_];
- localizer = [[[GTMUILocalizer alloc] initWithBundle:bundle] autorelease];
- }
- [self applyLocalizer:localizer tweakingUI:uiObject_];
- }
- }
- - (void)applyLocalizer:(GTMUILocalizer *)localizer
- tweakingUI:(id)uiObject {
- // Localize first
- [localizer localizeObject:uiObject recursively:YES];
- // Then tweak!
- [self tweakUI:uiObject];
- }
- - (void)tweakUI:(id)uiObject {
- // Figure out where we start
- NSView *startView;
- if ([uiObject isKindOfClass:[NSWindow class]]) {
- startView = [(NSWindow *)uiObject contentView];
- } else {
- _GTMDevAssert([uiObject isKindOfClass:[NSView class]],
- @"should have been a subclass of NSView");
- startView = (NSView *)uiObject;
- }
- // Tweak away!
- [self tweakView:startView];
- }
- - (void)tweakView:(NSView *)view {
- // If it's a alignment box, let it do its thing...
- if ([view isKindOfClass:[GTMWidthBasedTweaker class]]) {
- [(GTMWidthBasedTweaker *)view tweakLayoutWithOffset:NSZeroPoint];
- // Do our best to support TabViews. If the tabs need to resize, you are
- // probably better off manually running them through a tweaker and then fixing
- // up the parent view (and other tabs) to look right.
- } else if ([view isKindOfClass:[NSTabView class]]) {
- NSArray *tabViewItems = [(NSTabView *)view tabViewItems];
- NSTabViewItem *item = nil;
- GTM_FOREACH_OBJECT(item, tabViewItems) {
- [self tweakView:[item view]];
- }
- // Generically look for subviews...
- } else {
- NSArray *subviews = [view subviews];
- NSView *subview = nil;
- GTM_FOREACH_OBJECT(subview, subviews) {
- [self tweakView:subview];
- }
- }
- }
- + (NSString*)wrapString:(NSString *)string
- width:(CGFloat)width
- font:(NSFont *)font {
- // Set up the objects needed for the layout work.
- NSRect targetRect = NSMakeRect(0, 0, width, CGFLOAT_MAX);
- NSTextContainer* textContainer =
- [[[NSTextContainer alloc] initWithContainerSize:targetRect.size]
- autorelease];
- NSLayoutManager* layoutManager = [[[NSLayoutManager alloc] init] autorelease];
- NSTextStorage* textStorage =
- [[[NSTextStorage alloc] initWithString:string] autorelease];
- [textStorage addLayoutManager:layoutManager];
- [layoutManager addTextContainer:textContainer];
- // From playing in interface builder, the padding seems to be 2 on the line
- // fragments to get the same wrapping as what the NSCell will do in the end.
- [textContainer setLineFragmentPadding:2.0f];
- // Apply the font.
- [textStorage setFont:font];
- // Get the mutable string for the layout, remove any forced wraps in it.
- NSMutableString* workerStr = [textStorage mutableString];
- [workerStr replaceOccurrencesOfString:kForcedWrapString
- withString:@""
- options:NSLiteralSearch
- range:NSMakeRange(0, [workerStr length])];
- #if GTM_USE_TYPESETTER
- // Put in the recording type setter.
- GTMBreakRecordingTypeSetter *typeSetter =
- [[[GTMBreakRecordingTypeSetter alloc] init] autorelease];
- [layoutManager setTypesetter:typeSetter];
- // Make sure things are layed out (10.5 has a clean API for this, 10.4
- // doesn't).
- #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
- [layoutManager ensureLayoutForCharacterRange:NSMakeRange(0,
- [textStorage length])];
- #else
- [layoutManager lineFragmentRectForGlyphAtIndex:[layoutManager numberOfGlyphs]-1
- effectiveRange:NULL];
- #endif
- // Insert the breaks everywere the type setter got asked about breaks.
- NSEnumerator *reverseEnumerator =
- [[typeSetter breakArray] reverseObjectEnumerator];
- NSNumber *number;
- while ((number = [reverseEnumerator nextObject]) != nil) {
- [workerStr insertString:kForcedWrapString
- atIndex:[number unsignedIntegerValue]];
- }
- #else
- // Find out how tall lines would be for the layout loop.
- CGFloat lineHeight = [layoutManager defaultLineHeightForFont:font];
- targetRect.size.height = lineHeight;
- // Loop until all glyphs are layout out.
- NSUInteger numGlyphsUsed = 0;
- while (numGlyphsUsed < [layoutManager numberOfGlyphs]) {
- // See what fits in the current rect
- NSRange range = [layoutManager glyphRangeForBoundingRect:targetRect
- inTextContainer:textContainer];
- numGlyphsUsed = NSMaxRange(range);
- if (numGlyphsUsed < [layoutManager numberOfGlyphs]) {
- // Didn't all fit, add a break, and grow the rect to try again.
- NSRange charRange = [layoutManager glyphRangeForCharacterRange:range
- actualCharacterRange:nil];
- [workerStr insertString:kForcedWrapString atIndex:NSMaxRange(charRange)];
- targetRect.size.height += lineHeight;
- }
- }
- #endif // GTM_USE_TYPESETTER
- // Return the string with forced wraps
- return [[workerStr copy] autorelease];
- }
- + (NSSize)sizeToFitView:(NSView *)view {
- return SizeToFit(view, NSZeroPoint);
- }
- + (CGFloat)sizeToFitFixedWidthTextField:(NSTextField *)textField {
- NSRect initialFrame = [textField frame];
- NSRect sizeRect = NSMakeRect(0, 0, NSWidth(initialFrame), CGFLOAT_MAX);
- NSSize newSize = [[textField cell] cellSizeForBounds:sizeRect];
- newSize.width = NSWidth(initialFrame);
- [textField setFrameSize:newSize];
- return newSize.height - NSHeight(initialFrame);
- }
- #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
- + (CGFloat)sizeToFitFixedHeightTextField:(NSTextField *)textField {
- return [self sizeToFitFixedHeightTextField:textField minWidth:(CGFloat)0];
- }
- + (CGFloat)sizeToFitFixedHeightTextField:(NSTextField *)textField
- minWidth:(NSUInteger)minWidth {
- NSRect initialRect = [textField frame];
- NSCell *cell = [textField cell];
- NSSize titleSize = [cell titleRectForBounds:initialRect].size;
- // Find linebreak point, and keep trying them until we're under the height
- // requested.
- NSString *str = [textField stringValue];
- CFStringTokenizerRef tokenizer =
- CFStringTokenizerCreate(NULL,
- (CFStringRef)str,
- CFRangeMake(0, [str length]),
- kCFStringTokenizerUnitLineBreak,
- NULL);
- if (!tokenizer) {
- _GTMDevAssert(tokenizer, @"failed to get a tokenizer");
- return 0.0;
- }
- NSCell *workerCell = [[cell copy] autorelease];
- // Loop trying line break points until the height fits.
- while (1) {
- CFStringTokenizerTokenType tokenType =
- CFStringTokenizerAdvanceToNextToken(tokenizer);
- if (tokenType == kCFStringTokenizerTokenNone) {
- // Reached the end without ever find a good width, how?
- _GTMDevAssert(0, @"Failed to find a good size?!");
- [textField sizeToFit];
- break;
- }
- CFRange tokenRange = CFStringTokenizerGetCurrentTokenRange(tokenizer);
- NSRange subStringRange =
- NSMakeRange(0, tokenRange.location + tokenRange.length);
- NSString *subString = [str substringWithRange:subStringRange];
- // Find how wide the cell would be for this sub string.
- [workerCell setStringValue:subString];
- CGFloat testWidth = [workerCell cellSize].width;
- // Find the overall size if wrapped to this width.
- NSRect sizeRect = NSMakeRect(0, 0, testWidth, CGFLOAT_MAX);
- NSSize newSize = [cell cellSizeForBounds:sizeRect];
- if (newSize.height <= titleSize.height) {
- [textField setFrameSize:newSize];
- break;
- }
- }
- CFRelease(tokenizer);
- NSSize fixedSize = [textField frame].size;
- NSSize finalSize = NSMakeSize(fixedSize.width, NSHeight(initialRect));
- // Enforce the minWidth
- if (minWidth > fixedSize.width) {
- finalSize.width = minWidth;
- }
- // Make integral.
- finalSize.width = ceil(fixedSize.width);
- finalSize.height = ceil(fixedSize.height);
- if (!NSEqualSizes(fixedSize, finalSize)) {
- [textField setFrameSize:finalSize];
- }
- // Return how much things changed
- return finalSize.width - NSWidth(initialRect);
- }
- #endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
- + (void)wrapButtonTitleForWidth:(NSButton *)button {
- NSCell *cell = [button cell];
- NSRect frame = [button frame];
- NSRect titleFrame = [cell titleRectForBounds:frame];
- NSString* newTitle = [self wrapString:[button title]
- width:NSWidth(titleFrame)
- font:[button font]];
- [button setTitle:newTitle];
- }
- + (void)wrapRadioGroupForWidth:(NSMatrix *)radioGroup {
- NSSize cellSize = [radioGroup cellSize];
- NSRect tmpRect = NSMakeRect(0, 0, cellSize.width, cellSize.height);
- NSFont *font = [radioGroup font];
- NSCell *cell;
- GTM_FOREACH_OBJECT(cell, [radioGroup cells]) {
- NSRect titleFrame = [cell titleRectForBounds:tmpRect];
- NSString* newTitle = [self wrapString:[cell title]
- width:NSWidth(titleFrame)
- font:font];
- [cell setTitle:newTitle];
- }
- }
- + (void)resizeWindowWithoutAutoResizingSubViews:(NSWindow*)window
- delta:(NSSize)delta {
- NSView *contentView = [window contentView];
- // Clear autosizesSubviews (saving the state).
- BOOL autoresizesSubviews = [contentView autoresizesSubviews];
- if (autoresizesSubviews) {
- [contentView setAutoresizesSubviews:NO];
- }
- NSRect rect = [contentView convertRect:[window frame] fromView:nil];
- rect.size.width += delta.width;
- rect.size.height += delta.height;
- rect = [contentView convertRect:rect toView:nil];
- [window setFrame:rect display:NO];
- // For some reason the content view is resizing, but some times not adjusting
- // its origin, so correct it manually.
- [contentView setFrameOrigin:NSMakePoint(0, 0)];
- // Restore autosizesSubviews.
- if (autoresizesSubviews) {
- [contentView setAutoresizesSubviews:YES];
- }
- }
- + (void)resizeViewWithoutAutoResizingSubViews:(NSView*)view
- delta:(NSSize)delta {
- // Clear autosizesSubviews (saving the state).
- BOOL autoresizesSubviews = [view autoresizesSubviews];
- if (autoresizesSubviews) {
- [view setAutoresizesSubviews:NO];
- }
- NSRect rect = [view frame];
- rect.size.width += delta.width;
- rect.size.height += delta.height;
- [view setFrame:rect];
- // Restore autosizesSubviews.
- if (autoresizesSubviews) {
- [view setAutoresizesSubviews:YES];
- }
- }
- @end
- @implementation GTMWidthBasedTweaker
- - (CGFloat)changedWidth {
- return widthChange_;
- }
- - (CGFloat)tweakLayoutWithOffset:(NSPoint)offset {
- NSArray *subviews = [self subviews];
- if (![subviews count]) {
- widthChange_ = 0.0;
- return widthChange_;
- }
- BOOL sumMode = NO;
- NSMutableArray *rightAlignedSubViews = nil;
- NSMutableArray *rightAlignedSubViewDeltas = nil;
- if ([subviews count] > 1) {
- // Check if the frames are in a row by seeing if when they are left aligned
- // they overlap. If they don't overlap in this case, it means they are
- // probably stacked instead.
- NSRect rect1 = [[subviews objectAtIndex:0] frame];
- NSRect rect2 = [[subviews objectAtIndex:1] frame];
- rect1.origin.x = rect2.origin.x = 0;
- if (NSIntersectsRect(rect1, rect2)) {
- // No, so walk them x order moving them along so they don't overlap.
- sumMode = YES;
- subviews = [subviews sortedArrayUsingFunction:CompareFrameX context:NULL];
- } else {
- // Since they are vertical, any views pinned to the right will have to be
- // shifted after we finish figuring out the final size.
- rightAlignedSubViews = [NSMutableArray array];
- rightAlignedSubViewDeltas = [NSMutableArray array];
- }
- }
- // Size our subviews
- NSView *subView;
- CGFloat finalDelta = sumMode ? 0 : -CGFLOAT_MAX;
- NSPoint subViewOffset = NSZeroPoint;
- GTM_FOREACH_OBJECT(subView, subviews) {
- if (sumMode) {
- subViewOffset.x = finalDelta;
- }
- CGFloat delta = SizeToFit(subView, subViewOffset).width;
- if (sumMode) {
- finalDelta += delta;
- } else {
- if (delta > finalDelta) {
- finalDelta = delta;
- }
- }
- // Track the right anchored subviews size changes so we can update them
- // once we know this view's size.
- if (IsRightAnchored(subView)) {
- [rightAlignedSubViews addObject:subView];
- #if CGFLOAT_IS_DOUBLE
- NSNumber *nsDelta = [NSNumber numberWithDouble:delta];
- #else
- NSNumber *nsDelta = [NSNumber numberWithFloat:delta];
- #endif
- [rightAlignedSubViewDeltas addObject:nsDelta];
- }
- }
- // Are we pinned to the right of our parent?
- BOOL rightAnchored = IsRightAnchored(self);
- // Adjust our size (turn off auto resize, because we just fixed up all the
- // objects within us).
- BOOL autoresizesSubviews = [self autoresizesSubviews];
- if (autoresizesSubviews) {
- [self setAutoresizesSubviews:NO];
- }
- NSRect selfFrame = [self frame];
- selfFrame.size.width += finalDelta;
- if (rightAnchored) {
- // Right side is anchored, so we need to slide back to the left.
- selfFrame.origin.x -= finalDelta;
- }
- selfFrame.origin.x += offset.x;
- selfFrame.origin.y += offset.y;
- [self setFrame:selfFrame];
- if (autoresizesSubviews) {
- [self setAutoresizesSubviews:autoresizesSubviews];
- }
- // Now spin over the list of right aligned view and their size changes
- // fixing up their positions so they are still right aligned in our final
- // view.
- for (NSUInteger lp = 0; lp < [rightAlignedSubViews count]; ++lp) {
- subView = [rightAlignedSubViews objectAtIndex:lp];
- CGFloat delta = [[rightAlignedSubViewDeltas objectAtIndex:lp] doubleValue];
- NSRect viewFrame = [subView frame];
- viewFrame.origin.x += -delta + finalDelta;
- [subView setFrame:viewFrame];
- }
- if (viewToSlideAndResize_) {
- NSRect viewFrame = [viewToSlideAndResize_ frame];
- if (!rightAnchored) {
- // If our right wasn't anchored, this view slides (we push it right).
- // (If our right was anchored, the assumption is the view is in front of
- // us so its x shouldn't move.)
- viewFrame.origin.x += finalDelta;
- }
- viewFrame.size.width -= finalDelta;
- [viewToSlideAndResize_ setFrame:viewFrame];
- }
- if (viewToSlide_) {
- NSRect viewFrame = [viewToSlide_ frame];
- // Move the view the same direction we moved.
- if (rightAnchored) {
- viewFrame.origin.x -= finalDelta;
- } else {
- viewFrame.origin.x += finalDelta;
- }
- [viewToSlide_ setFrame:viewFrame];
- }
- if (viewToResize_) {
- if ([viewToResize_ isKindOfClass:[NSWindow class]]) {
- NSWindow *window = (NSWindow *)viewToResize_;
- NSView *contentView = [window contentView];
- NSRect windowFrame = [contentView convertRect:[window frame]
- fromView:nil];
- windowFrame.size.width += finalDelta;
- windowFrame = [contentView convertRect:windowFrame toView:nil];
- [window setFrame:windowFrame display:YES];
- // For some reason the content view is resizing, but not adjusting its
- // origin, so correct it manually.
- [contentView setFrameOrigin:NSMakePoint(0, 0)];
- // TODO: should we update min size?
- } else {
- NSRect viewFrame = [viewToResize_ frame];
- viewFrame.size.width += finalDelta;
- [viewToResize_ setFrame:viewFrame];
- // TODO: should we check if this view is right anchored, and adjust its
- // x position also?
- }
- }
- widthChange_ = finalDelta;
- return widthChange_;
- }
- @end
- #pragma mark -
- static NSSize SizeToFit(NSView *view, NSPoint offset) {
- // If we've got one of us within us, recurse (for grids)
- if ([view isKindOfClass:[GTMWidthBasedTweaker class]]) {
- GTMWidthBasedTweaker *widthAlignmentBox = (GTMWidthBasedTweaker *)view;
- return NSMakeSize([widthAlignmentBox tweakLayoutWithOffset:offset], 0);
- }
- NSRect oldFrame = [view frame];
- NSRect fitFrame = oldFrame;
- NSRect newFrame = oldFrame;
- if ([view isKindOfClass:[NSTextField class]] &&
- [(NSTextField *)view isEditable]) {
- // Don't try to sizeToFit because edit fields really don't want to be sized
- // to what is in them as they are for users to enter things so honor their
- // current size.
- #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
- } else if ([view isKindOfClass:[NSPathControl class]]) {
- // Don't try to sizeToFit because NSPathControls usually need to be able
- // to display any path, so they shouldn't tight down to whatever they
- // happen to be listing at the moment.
- #endif // MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
- } else {
- // Genericaly fire a sizeToFit if it has one.
- if ([view respondsToSelector:@selector(sizeToFit)]) {
- [view performSelector:@selector(sizeToFit)];
- fitFrame = [view frame];
- newFrame = fitFrame;
- if ([view isKindOfClass:[NSMatrix class]]) {
- NSMatrix *matrix = (NSMatrix *)view;
- // See note on kWrapperStringSlop for why this is done.
- NSCell *cell;
- GTM_FOREACH_OBJECT(cell, [matrix cells]) {
- if ([[cell title] rangeOfString:kForcedWrapString].location !=
- NSNotFound) {
- newFrame.size.width += kWrapperStringSlop;
- break;
- }
- }
- }
- }
- if ([view isKindOfClass:[NSButton class]]) {
- NSButton *button = (NSButton *)view;
- // -[NSButton sizeToFit] gives much worse results than IB's Size to Fit
- // option for standard push buttons.
- if (([button bezelStyle] == NSRoundedBezelStyle) &&
- ([[button cell] controlSize] == NSRegularControlSize)) {
- // This is the amount of padding IB adds over a sizeToFit, empirically
- // determined.
- const CGFloat kExtraPaddingAmount = 12.0;
- // Width is tricky, new buttons in IB are 96 wide, Carbon seems to have
- // defaulted to 70, Cocoa seems to like 82. But we go with 96 since
- // that's what IB is doing these days.
- const CGFloat kMinButtonWidth = (CGFloat)96.0;
- newFrame.size.width = NSWidth(newFrame) + kExtraPaddingAmount;
- if (NSWidth(newFrame) < kMinButtonWidth) {
- newFrame.size.width = kMinButtonWidth;
- }
- } else if ([button bezelStyle] == NSTexturedRoundedBezelStyle &&
- [[button cell] controlSize] == NSRegularControlSize) {
- // The round textured style needs to have a little extra padding,
- // otherwise the baseline of the text sinks by a few pixels.
- const CGFloat kExtraPaddingAmount = 4.0;
- newFrame.size.width += kExtraPaddingAmount;
- } else {
- // See note on kWrapperStringSlop for why this is done.
- NSString *title = [button title];
- if ([title rangeOfString:kForcedWrapString].location != NSNotFound) {
- newFrame.size.width += kWrapperStringSlop;
- }
- }
- }
- }
- // Apply the offset, and see if we need to change the frame (again).
- newFrame.origin.x += offset.x;
- newFrame.origin.y += offset.y;
- if (!NSEqualRects(fitFrame, newFrame)) {
- [view setFrame:newFrame];
- }
- // Return how much we changed size.
- return NSMakeSize(NSWidth(newFrame) - NSWidth(oldFrame),
- NSHeight(newFrame) - NSHeight(oldFrame));
- }
- static NSInteger CompareFrameX(id view1, id view2, void *context) {
- CGFloat x1 = [view1 frame].origin.x;
- CGFloat x2 = [view2 frame].origin.x;
- if (x1 < x2)
- return NSOrderedAscending;
- else if (x1 > x2)
- return NSOrderedDescending;
- else
- return NSOrderedSame;
- }
- static BOOL IsRightAnchored(NSView *view) {
- NSUInteger autoresizing = [view autoresizingMask];
- BOOL viewRightAnchored =
- ((autoresizing & (NSViewMinXMargin | NSViewMaxXMargin)) == NSViewMinXMargin);
- return viewRightAnchored;
- }