NSBrowser image is not displaying in cell

336 Views Asked by At

I'm using NSBrowser view to show list of files and folder in finder type app.I'm using new Item Base Api for NSBrowser.

The problem is that when I try set image in willDisplayCell method. Nothing is displayed in view.

Code:

// This is a utility method to find the parent item for a given column. The item based API eliminates the need for this method.
- (FileSystemNode *)parentNodeForColumn:(NSInteger)column {
    if (_rootNode == nil) {
        _rootNode = [[FileSystemNode alloc] initWithURL:[NSURL fileURLWithPath:@"/Users/kiritvaghela"]];
    }

    FileSystemNode *result = _rootNode;
    // Walk up to this column, finding the selected row in the column before it and using that in the children array
    for (NSInteger i = 0; i < column; i++) {
        NSInteger selectedRowInColumn = [_browser selectedRowInColumn:i];
        FileSystemNode *selectedChildNode = [result.children objectAtIndex:selectedRowInColumn];
        result = selectedChildNode;
    }

    return result;
}

- (void)browser:(NSBrowser *)browser willDisplayCell:(NSBrowserCell *)cell atRow:(NSInteger)row column:(NSInteger)column {
    FileSystemNode *parentNode = [self parentNodeForColumn:column];
    FileSystemNode *childNode = [parentNode.children objectAtIndex:row];

    [cell setTitle:childNode.displayName];

    cell.image = node.icon;

}

Apple SimpleCocoaBrowser Example

2

There are 2 best solutions below

0
On

While the default value for cellPrototype is NSBrowserCell, it seems to use a NSTextFieldCell. (macOS 10.14)

To fix this, you need to subclass NSBrowserCell and set the subclass as cellClass: [_browser setCellClass:[BrowserCell class]];

@interface BrowserCell : NSBrowserCell
@end

@implementation BrowserCell
@end

Another issue is the leaf indicator. It will be shown twice, once from the cell and once from the browser.

- (void)browser:(NSBrowser *)browser willDisplayCell:(NSBrowserCell *)cell atRow:(NSInteger)row column:(NSInteger)column {
    FileSystemNode *parentNode = [self parentNodeForColumn:column];
    FileSystemNode *childNode = [parentNode.children objectAtIndex:row];

    NSImage *image = node.icon;
    [image setSize:NSMakeSize(16, 16)];

    cell.image = cell.image;
    cell.leaf = YES;
}

radar://47175910

0
On

Using NSBrowserCell described in catlan's answer works, but NSTextField behaves differently when drawing a selected cell's background than NSBrowserCell does. While the mouse is clicking/dragged in another column, NSBrowserCell will draw the selected cell's background which was blue as grey instead (the Finder does this too). However NSTextFieldCell remains blue while the mouse is clicked, and goes grey when released. Because leaf indicator isn't being drawn by the NSBrowserCell, that region of the cell will still have a blue selection highlight, so the cell has blue and grey as the background color at the same time. It's brief since it's only while clicking, but it does look wrong.

Getting NSBrowserCell to behave like NSTextFieldCell took some reverse engineering and private APIs, so I decided that the right thing to do was just subclass NSTextFieldCell and draw an icon in it. The code is something like this,

@implementation BrowserTextFieldCell
- (void)drawInteriorWithFrame:(NSRect)cellFrame controlView:(NSView *)controlView
{
    __auto_type textFrame = cellFrame;
    __auto_type inset = kIconHorizontalPadding * 2 + kIconSize;

    textFrame.origin.x += inset;
    textFrame.size.width -= inset;
    [super drawInteriorWithFrame:textFrame inView:controlView];

    [self drawIconWithFrame:cellFrame];
}

- (void)drawIconWithWithFrame:(NSRect)cellFrame
{
    NSRect iconFrame = cellFrame;
    iconFrame.origin.x += kIconPadding;
    iconFrame.size = NSMakeSize(kIconSize, kIconSize);
    [self.iconImage drawInRect:iconFrame];
}
@end