Improve tab trigger rendering

This is using NSAttributedString’s NSTextTableBlocks:

* Font is determined from current menu rather than hardcoded
* Fixed: Invalid font size on bundle-item popup
* Fixed: Both tab triggers and key equivalents can co exists on single menu item
* No relayout calculations are needed after menu update (this is done automatically by NSLayoutManager when using NSTextTables)
* Uses 10.5 compatible API
This commit is contained in:
Adam Strzelecki
2012-08-14 17:59:13 +02:00
committed by Allan Odgaard
parent 15afc1398b
commit 7bd9f9817b

View File

@@ -83,6 +83,109 @@ static void set_legacy_key_equivalent (MenuRef aMenu, UInt16 anIndex, std::strin
SetMenuItemModifiers(aMenu, anIndex, modifiers);
}
@interface MenuMutableAttributedString : NSMutableAttributedString
{
NSMutableAttributedString* contents;
CGSize size;
}
- (void)appendTableCellWithString:(NSString*)string table:(NSTextTable*)table textAlignment:(NSTextAlignment)textAlignment verticalAlignment:(NSTextBlockVerticalAlignment)verticalAlignment font:(NSFont*)font row:(int)row column:(int)column;
- (CGSize)size;
@end
@implementation MenuMutableAttributedString
// Methods to override in subclass
- (id)init
{
return [self initWithAttributedString:nil];
}
- (id)initWithAttributedString:(NSAttributedString*)attributedString
{
if(self = [super init])
contents = attributedString ? [attributedString mutableCopy] : [[NSMutableAttributedString alloc] init];
return self;
}
- (NSString*)string
{
return [contents string];
}
- (NSDictionary*)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRange*)range
{
return [contents attributesAtIndex:location effectiveRange:range];
}
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString*)string
{
[contents replaceCharactersInRange:range withString:string];
}
- (void)setAttributes:(NSDictionary*)attributes range:(NSRange)range
{
[contents setAttributes:attributes range:range];
}
- (id)copyWithZone:(NSZone*)zone
{
MenuMutableAttributedString* copy = [MenuMutableAttributedString allocWithZone:zone];
copy->contents = [contents copyWithZone:zone];
copy->size = size;
return copy;
}
- (void)dealloc
{
[contents release];
[super dealloc];
}
// NOTE: AppKit additions produce invalid values here, provide our own implementation
- (NSRect)boundingRectWithSize:(NSSize)aSize options:(NSStringDrawingOptions)options
{
return NSMakeRect(0, 0, size.width, size.height);
}
// Helper method for adding table cell into the attributed string
- (void)appendTableCellWithString:(NSString*)string table:(NSTextTable*)table textAlignment:(NSTextAlignment)textAlignment verticalAlignment:(NSTextBlockVerticalAlignment)verticalAlignment font:(NSFont*)font row:(int)row column:(int)column;
{
CGSize stringSize = [string sizeWithAttributes:[NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName]];
NSTextTableBlock* block = [[[NSTextTableBlock alloc] initWithTable:table startingRow:row rowSpan:1 startingColumn:column columnSpan:1] autorelease];
if(column > 0)
[block setContentWidth:stringSize.width type:NSTextBlockAbsoluteValueType];
block.verticalAlignment = verticalAlignment;
NSMutableParagraphStyle* paragraphStyle = [[[NSMutableParagraphStyle alloc] init] autorelease];
[paragraphStyle setTextBlocks:[NSArray arrayWithObjects:block, nil]];
[paragraphStyle setAlignment:textAlignment];
string = [string stringByAppendingString:@"\n"];
NSMutableAttributedString* cellString = [[[NSMutableAttributedString alloc] initWithString:string] autorelease];
[cellString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [cellString length])];
[cellString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, [cellString length])];
size.width += stringSize.width;
if(size.height < stringSize.height)
size.height = stringSize.height;
[self appendAttributedString:cellString];
}
- (CGSize)size
{
return size;
}
@end
@implementation NSMenuItem (FileIcon)
- (void)setIconForFile:(NSString*)path;
{
@@ -144,16 +247,16 @@ static void set_legacy_key_equivalent (MenuRef aMenu, UInt16 anIndex, std::strin
if(aTabTrigger == NULL_STR)
return;
if(MenuRef menu = _NSGetCarbonMenu([self menu]))
{
MenuItemIndex itemIndex = [[self menu] indexOfItem:self] + 1;
MenuMutableAttributedString* attributedTitle = [[[MenuMutableAttributedString alloc] init] autorelease];
NSTextTable* table = [[[NSTextTable alloc] init] autorelease];
[table setNumberOfColumns:2];
ChangeMenuItemAttributes(menu, itemIndex, kMenuItemAttrCustomDraw, 0);
std::string const& tabTrigger(aTabTrigger + "⇥");
size_t len = tabTrigger.size();
SetMenuItemProperty(menu, itemIndex, 'TxMt', 'TbLn', sizeof(size_t), &len);
SetMenuItemProperty(menu, itemIndex, 'TxMt', 'TbTr', tabTrigger.size(), tabTrigger.data());
}
NSFont* font = self.menu.font ?: [NSFont menuFontOfSize:0];
[attributedTitle appendTableCellWithString:self.title table:table textAlignment:NSLeftTextAlignment verticalAlignment:NSTextBlockMiddleAlignment font:font row:0 column:0];
[attributedTitle appendTableCellWithString:[NSString stringWithCxxString:(" "+aTabTrigger+"\u21E5")] table:table textAlignment:NSRightTextAlignment
verticalAlignment:font.pointSize >= 13 ? NSTextBlockBottomAlignment : NSTextBlockMiddleAlignment
font:[NSFont menuBarFontOfSize:floor(font.pointSize * 0.85)] row:0 column:1];
self.attributedTitle = attributedTitle;
}
- (void)setModifiedState:(BOOL)flag