Engenharia reversa Um nsmenu para um item de barra de status
-
27-09-2019 - |
Pergunta
Quero criar um menu para um item de barra de status como o visto no aplicativo PastebotSync da Tapbot:
Alguém tem alguma idéia de como alcançar a área personalizada na parte superior do menu que está nivelada com a parte superior?
Eu tentei/pensei em algumas maneiras em potencial de fazê -lo:
- Nsmenuitem padrão com vista - não está nivelado com a parte superior do menu
- Algum código de hack -ish para colocar uma NSWIDOW sobre a área no topo do menu - não é ótimo, pois não desaparece bem com o menu quando fecha
- Abandonando um nsmenu completamente e usando uma NSView - ainda não tentei isso, mas eu realmente não quero ter que fazer alguns botões falsos ou algo que age como nsmenuitems
Alguém tem idéias ou sugestões melhores?
Obrigado!
Solução
Caso alguém venha procurar, eu postei uma solução para isso em Visualização personalizada acima do nsmenuitem
Aqui está o código:
@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
Use assim:
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;
Outras dicas
Eu tinha a mesma necessidade nas versões iniciais do Houdahspot 2. Eu o fiz trabalhando com uma limitação: meu código deixa o menu com cantos quadrados na parte inferior.
Desde então, abandonei essa configuração, à medida que o recurso BlitzSearch no Houdahspot cresceu para precisar de uma interface do usuário mais complexa, encontrei outras limitações com o uso de NSViews em um NSMENU.
De qualquer forma, aqui está o código original cuidando desses 3 pixels extras:
- (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;
}
Desculpe, eu esqueci isso:
- (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;
}