I am using the setView:
method on an NSMenuItem
to set a custom view. In this custom view there is an image which takes the whole of the view. The NSMenuItem
with this custom view is the first in the menu but the problem is it doesn't sit flush with the top of the menu, there is a big gap as you can see here:
Why is this happening and how can I stop it?
EDIT
I am using this code now but I am getting EXC_BAD_ACCESS
on the line InstallControlEventHandler
.
-(void)applicationDidFinishLaunching:(NSNotification *)aNotification {
HIViewRef contentView;
MenuRef menuRef = [statusMenu carbonMenuRef];
HIMenuGetContentView(menuRef, kThemeMenuTypePullDown, &contentView);
EventTypeSpec hsEventSpec[1] = {
{ kEventClassMenu, kEventMenuCreateFrameView }
};
InstallControlEventHandler(contentView,
NewEventHandlerUPP((EventHandlerProcPtr)hsMenuCreationEventHandler),
GetEventTypeCount(hsEventSpec),
hsEventSpec,
NULL,
NULL); // Get EXC_BAD_ACCESS here.
}
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 ) );
InstallControlEventHandler( content, hsMenuContentEventHandler, GetEventTypeCount( kContentEvents ),
kContentEvents, 0, NULL );
}
}
return err;
}
Also note the line metrics.top = 0
this is the line which should remove the gap at the top. However I cannot get it work that far. Does anyone know why I would be recieving an EXC_BAD_ACCESS
there. I have already created and allocated statusMenu
so surely it should work?
Your post is tagged "Objective-C" and "Cocoa", although your sample code is C and Carbon. I assume you'd prefer a Cocoa solution?
It's actually pretty simple in Cocoa. The only trick is learning how to draw outside the lines. :-)
@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 it like this:
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With