4

I wrote my own NSMenu like class to show dynamic search results below a NSSearchField in a borderless NSWindow. It's working well but doesn't draw the magic selectedMenuItemColor correctly if I add some padding to the top of the subview. I put a 5 pixel padding at the top of container view to mimic NSMenu and when I do it blue selected gradient looks off. A picture & code should make this clear:

enter image description here

Here is my drawRect code inside my item view (remember this is just a regular NSView):

-(void) drawRect:(NSRect)dirtyRect {
    CGRect b = self.bounds;
    if (selected) {

        [NSGraphicsContext saveGraphicsState];

        [[NSColor selectedMenuItemColor] set];
        NSRectFill( b );

        [NSGraphicsContext restoreGraphicsState];
        if (textField) {
            textField.textColor = [NSColor selectedMenuItemTextColor];
        }
    } else {
        [[NSColor clearColor] set];
       NSRectFillUsingOperation(b, NSCompositeSourceOver);
        if (textField) {
            textField.textColor = [NSColor blackColor];
        }
    }
}
John Wright
  • 2,418
  • 4
  • 29
  • 34
  • When I try to use `selectedMenuItemColor`, I only get the dark blue background and not the lighter gradient on top of it as is shown in your screenshot. Did you have to do anything special to get that to show up? – jtbandes Aug 12 '12 at 20:03
  • No I didn't. Want to paste a gist that I can take a look at? – John Wright Oct 25 '12 at 19:21

1 Answers1

0

You have to get the pattern phase origin to match your view frame.

That is, selectedMenuItemColor is actually a pattern, not a color, and that pattern is designed to display "properly" in "standard menu item height" increments. Because you have added the padding, now it is not being drawn at the "standard" location.

Try this:

-(void) drawRect:(NSRect)dirtyRect {
    CGRect b = self.bounds;
    if (selected) {

       NSPoint origin = [self frame].origin;
       curContext = [NSGraphicsContext currentContext];
       [curContext saveGraphicsState];
       [curContext setPatternPhase: origin];

        [[NSColor selectedMenuItemColor] set];
        NSRectFill( b );

        [curContext restoreGraphicsState];
        if (textField) {
            textField.textColor = [NSColor selectedMenuItemTextColor];
        }
    } else {
        [[NSColor clearColor] set];
       NSRectFillUsingOperation(b, NSCompositeSourceOver);
        if (textField) {
            textField.textColor = [NSColor blackColor];
        }
    }
}
Smilin Brian
  • 980
  • 8
  • 18
  • Thanks so much for helping here. That didn't work but moving the pattern phase origin up by 5 pixels did, i.e. `[curContext setPatternPhase: CGPointMake(0, 5)]`. Why is that? – John Wright Oct 25 '12 at 19:18
  • Curious, as it works for my purposes, but then my menu item view leaves a gap at the bottom, while it seems yours is leaving a gap at the top. Seems like the the `patternPhase` at `origin` should work in either case, but I guess not. Perhaps it's the flipped coordinates -- those always seem to lead to unintuitive results for me. – Smilin Brian Oct 25 '12 at 20:53