Steve's Pad

Bindings and NSPopUpButton hack

March 3, 2007

Cocoa bindings are great, but it still has a few rough edges and missing features. One of those is the ability to add images to menu items in an NSPopUpButton. Bindings adds the titles just fine, but there are no options for adding images. So, I came up with a hack which works great. This also adds the ability to have separator items!

This is why Cocoa is great! poseAsClass is very cool!

In the object you bind, return a description in the format: [NSString stringWithFormat:@”::$$%@$$%d”, path, kSmallMenuIconSize];

The files path and image size are encoded in the title. When bindings builds the menu item, this code converts this string to a real title and adds an image. In this code, I’m using some private classes I created, but they are easy to replace with your own code.

wala.jpg





@interface NSMenuItemHack : NSMenuItem { }
+ (void)install;
@end

@implementation NSMenuItemHack

+ (void)install;
{
   [NSMenuItemHack poseAsClass:[NSMenuItem class]];
}

// this hack allows us to add icons to popupbuttons using bindings
//  return [NSString stringWithFormat:@"::$$%@$$%d", path, kSmallMenuIconSize];

- (id)initWithTitle:(NSString *)title action:(SEL)aSelector keyEquivalent:(NSString *)charCode;
{
   NSImage* image = nil;

   if ([title hasPrefix:@"::"])
   {
      NSArray *components = [title componentsSeparatedByString:@"$$"];

      if ([components count] == 3)
      {
         NSString* path = [components objectAtIndex:1];
         int imageSize = [[components objectAtIndex:2] intValue];

         if ([path isEqualToString:@"-"])
         {
            // ? release self since we are replacing it [self release] bombed?
            return [[NSMenuItem separatorItem] retain];
         }
         else
         {
            NTFileDesc* desc = [NTFileDesc descNoResolve:path];

            if ([desc isValid])
            {
               title = [desc displayName];

               // set the icon
                image = [NSImage iconRef:[[desc icon] iconRef] toImage:imageSize];
            }
         }
      }
   }

   self = [super initWithTitle:title action:aSelector keyEquivalent:charCode];

   if (image)
      [self setImage:image];

     return self;
}

@end

Posted by sgehrman at March 3, 2007 3:53 PM