Обратное проектирование NSMenu для элемента строки состояния
Я хочу создать меню для элемента строки состояния, подобное тому, которое можно увидеть в приложении PastebotSync Tapbot:
У кого-нибудь есть идеи, как добиться пользовательской области в верхней части меню, которая находится на одном уровне с верхней частью?
Я пробовал / думал о нескольких возможных способах сделать это:
- Стандартный NSMenuItem с видом - не вровень с верхней частью меню
- Некоторый хакерский код для размещения NSWindow над областью в верхней части меню - не очень хорошо, так как он не исчезает с меню, когда оно закрывается
- Полностью отказаться от NSMenu и использовать вместо него NSView - еще не пробовал, но я не хочу делать какие-то фальшивые кнопки или что-то, что действует как NSMenuItems
У кого-нибудь есть лучшие идеи или предложения?
Спасибо!
2 ответа
На случай, если кто-нибудь придет посмотреть, я разместил решение этой проблемы в Gap выше пользовательского представления NSMenuItem.
Вот код:
@interface FullMenuItemView : NSView
@end
@implementation FullMenuItemView
- (void) drawRect:(NSRect)dirtyRect
{
NSRect fullBounds = [self bounds];
fullBounds.size.height += 4;
[[NSBezierPath bezierPathWithRect:fullBounds] setClip];
// Then do your drawing, for example...
[[NSColor blueColor] set];
NSRectFill( fullBounds );
}
@end
Используйте это так:
CGFloat menuItemHeight = 32;
NSRect viewRect = NSMakeRect(0, 0, /* width autoresizes */ 1, menuItemHeight);
NSView *menuItemView = [[[FullMenuItemView alloc] initWithFrame:viewRect] autorelease];
menuItemView.autoresizingMask = NSViewWidthSizable;
yourMenuItem.view = menuItemView;
У меня была такая же потребность в ранних версиях HoudahSpot 2. Я работал с одним ограничением: мой код оставляет меню с квадратными углами внизу.
С тех пор я отказался от этой настройки, поскольку функция BlitzSearch в HoudahSpot стала нуждаться в более сложном пользовательском интерфейсе, я столкнулся с другими ограничениями при использовании NSViews в NSMenu.
Так или иначе, вот оригинальный код, заботящийся о тех дополнительных 3 пикселях:
- (void)awakeFromNib
{
HIViewRef contentView;
MenuRef menuRef = [statusMenu carbonMenuRef];
HIMenuGetContentView (menuRef, kThemeMenuTypePullDown, &contentView);
EventTypeSpec hsEventSpec[1] = {
{ kEventClassMenu, kEventMenuCreateFrameView }
};
HIViewInstallEventHandler(contentView,
NewEventHandlerUPP((EventHandlerProcPtr)hsMenuCreationEventHandler),
GetEventTypeCount(hsEventSpec),
hsEventSpec,
NULL,
NULL);
}
#pragma mark -
#pragma mark Carbon handlers
static OSStatus hsMenuContentEventHandler( EventHandlerCallRef caller, EventRef event, void* refcon )
{
OSStatus err;
check( GetEventClass( event ) == kEventClassControl );
check( GetEventKind( event ) == kEventControlGetFrameMetrics );
err = CallNextEventHandler( caller, event );
if ( err == noErr )
{
HIViewFrameMetrics metrics;
verify_noerr( GetEventParameter( event, kEventParamControlFrameMetrics, typeControlFrameMetrics, NULL,
sizeof( metrics ), NULL, &metrics ) );
metrics.top = 0;
verify_noerr( SetEventParameter( event, kEventParamControlFrameMetrics, typeControlFrameMetrics,
sizeof( metrics ), &metrics ) );
}
return err;
}
static OSStatus hsMenuCreationEventHandler( EventHandlerCallRef caller, EventRef event, void* refcon )
{
OSStatus err = eventNotHandledErr;
if ( GetEventKind( event ) == kEventMenuCreateFrameView)
{
err = CallNextEventHandler( caller, event );
if ( err == noErr )
{
static const EventTypeSpec kContentEvents[] =
{
{ kEventClassControl, kEventControlGetFrameMetrics }
};
HIViewRef frame;
HIViewRef content;
verify_noerr( GetEventParameter( event, kEventParamMenuFrameView, typeControlRef, NULL,
sizeof( frame ), NULL, &frame ) );
verify_noerr( HIViewFindByID( frame, kHIViewWindowContentID, &content ) );
HIViewInstallEventHandler( content, hsMenuContentEventHandler, GetEventTypeCount( kContentEvents ),
kContentEvents, 0, NULL );
}
}
return err;
}
Извините, я забыл об этом:
- (MenuRef) carbonMenuRef
{
MenuRef carbonMenuRef = NULL;
if (carbonMenuRef == NULL) {
extern MenuRef _NSGetCarbonMenu(NSMenu *);
carbonMenuRef = _NSGetCarbonMenu(self);
if (carbonMenuRef == NULL) {
NSMenu *theMainMenu = [NSApp mainMenu];
NSMenuItem *theDummyMenuItem = [theMainMenu addItemWithTitle: @"sub" action: NULL keyEquivalent: @""];
if (theDummyMenuItem != nil) {
[theDummyMenuItem setSubmenu:self];
[theDummyMenuItem setSubmenu:nil];
[theMainMenu removeItem:theDummyMenuItem];
carbonMenuRef = _NSGetCarbonMenu(self);
}
}
}
if (carbonMenuRef == NULL) {
extern MenuRef _NSGetCarbonMenu2(NSMenu *);
carbonMenuRef = _NSGetCarbonMenu2(self);
}
return carbonMenuRef;
}