Mac Custom NSSlider how to override tick mark drawing outside slider frame - objective-c

I'm creating a custom NSSlider where I want to draw labels underneath each of the tick marks.
I'm currently doing this in the custom NSSliderCell -(NSRect)rectOfTickMarkAtIndex however because the height of NSSlider is fixed, the label I'm drawing underneath is being cropped.
Anyone have any ideas?
Also any resources with full implementations of custom NSSliders would be appreciated.

Simply set the frame and bounds of the NSSlider (which is really a subclass of NSView) so it is higher. Then your drawing should work fine. Stick this code in awakeFromNib: (Replace slider with self if you're in its subclass.)
NSRect frameRect = [slider frame];
frameRect.size.height = 30;
[slider setFrame:frameRect];
NSRect boundsRect = [slider bounds];
boundsRect.size.height = 30;
[slider setBounds:boundsRect];

Related

NSImageView transparency

I'm beginner with programming for OS X and I have problems with setting NSImageView transparency.
In iOS it was quite simple, there's property in UIImageView called alpha and I could change it and animate it. (like imageView.alpha = 0.5)
How can I achieve the same with NSImageView?
set the property alphaValue of a NSView that has a layer!
[view setWantsLayer:YES];
[view setAlphaValue:0];

How to customize a NSSlider

I'm trying to implement a custom slider in Cocoa with 5 values. See my demo project, which can be downloaded here: http://s000.tinyupload.com/index.php?file_id=07311576247413689572.
I've subclassed the NSSliderCell and implemented methods like drawKnob:(NSRect)knobRect and drawBarInside:(NSRect)cellFrame flipped:(BOOL)flipped etc.
I'm facing some issues:
I'm not able to position the knob correctly regarding to the background image. I know that I'm able to change the knob's frame, and I've tried doing some calculation to position the knob correctly, but I'm not able to make it work for my custom slider. Could someone please help me with this?
The height of my custom slider background is 41px. In the drawBarInside:(NSRect)cellFrame flipped:(BOOL)flipped I change the height of the frame to 41px as well, but the entire background is not visible. Why?
I've noticed that the included images (the background and knob) are flipped vertically. Why? Note that the border top is darker in the background compared to the bottom, but this is reversed when I draw the background.
I found a mistake in your calculation of the x position of the knob rectangle: You used the height of the image where you should have used the width.
The cell drawing is being clipped to the frame of the control. Maybe you could expand the control frame when your cell awakes.
You need to use the NSImage method drawInRect:fromRect:operation:fraction:respectFlipped:hints:, and pass YES for the respectFlipped: parameter. Apple's controls generally do use flipped coordinates.
Added: Expanding the frame in awakeFromNib doesn't seem to work, the frame gets set back. Here's something that does work. Instead of overriding drawBarInside:flipped:, add this override:
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
NSRect controlFrame = [controlView frame];
float bgHeight = self.backgroundImage.size.height;
if (controlFrame.size.height < bgHeight)
{
controlFrame.size.height = bgHeight;
[controlView setFrame: controlFrame];
}
[self.backgroundImage
drawInRect: [controlView bounds]
fromRect: NSZeroRect
operation: NSCompositeSourceOver
fraction: 1.0
respectFlipped: YES
hints: NULL];
[self drawKnob];
}

Blank pixels left when NSWindow with opaque set to NO

I have a NSWindow where I set opaque attribute to NO. The problem is that when I put any view inside that window it's corners has blank pixels.
Everything works well when opaque attribue is left with YES value, however, window's corners are not rounded anymore. See picture:
I've created repository with simple example project at bitbucket: https://bitbucket.org/lukaszb/animationartifacts
Is there a way I can fix this (remain window's corners rounded and blank pixels not appearing)? Or should I try another solution (without setOapque:NO at NSWindow subclass)?
Try enabling the Core Animation layer for your RoundedView, i.e., open MainMenu.xib, select RoundedView and in the “View Effects” tab (rightmost one) check the view under “Core Animation Layer”.
Alternatively you can do it programmatically, e.g., in RoundedView add:
- (void)awakeFromNib {
self.wantsLayer = YES;
self.layer = [CALayer layer];
self.layer.backgroundColor = [[NSColor blackColor] CGColor];
self.layer.cornerRadius = RADIUS;
}
Also #import <QuartzCore/QuartzCore.h> and add QuartzCore.framework to the project. You can then delete the drawRect method since CALayer already does rounded corners for you. (Actually you can delete your whole RoundedView class if you just set up this layer for a regular NSView that you use in its place.)
You can create a Subclass of NSView, make a custom drawing using NSBezierPath in it's drawRect: method, and then set it as the content view of the window.

NSRect Size to Fill Screen

How do i get the current size of the screen no matter the resolution change in xcode so that i can adjust my NSRect size to be maximized or take up the screen according to the resolution ? What do I need to add? Would it be something to the NSWindow?
NSRect panelRect = [[self window] frame];
panelRect.size.height = _HEIGHT;
panelRect.size.width = _WIDTH;
panelRect.origin.x = 0;
panelRect.origin.y = 0;
[[self window] setFrame:panelRect display:NO];
Thanks!
You can use CGDisplayBounds, which returns a CGRect containing the screen's bounds (origin and size) in global coordinates.
You can use CGDisplayRegisterReconfigurationCallback to be notified when a display configuration changes, which includes when its resolution is changed.
Quartz Display Services Reference
Have you tried using [[NSScreen mainScreen] frame]? If you want to exclude the menubar, you can subtract the menubar height from the NSRect's height. (It's around 20 pixels)
Edit: If you want your window to be resized from the start, you can put the method above in your controller's awakeFromNib and use NSWindow's setFrame:display: to resize it.

Custom NSView Fill Paints Over Bottom Bar

I have a window which has a custom NSView and has a bottom bar with controls on it, one of which is an NSColorWheel.
For simplicity sake the Window is 332px high, with the custom NSView being 300px high and the bottom bar being 32px high.
The bottom bar is created as part of my awakeFromNib when the app loads the window using the following code:
[[self window] setAutorecalculatesContentBorderThickness:YES forEdge:NSMinYEdge];
[[self window] setContentBorderThickness: 32.0 forEdge: NSMinYEdge];
In my custom NSView class I fill the rectangle with color. Everything works fine when the app loads using the following in my NSView class:
- (void)drawRect:(NSRect)dirtyRect
{
dirtyRect = [self bounds];
NSColor * mNewColor = [NSColor blackColor];
[mNewColor set];
[NSBezierPath fillRect:dirtyRect];
}
However, if I subsequently call a method that changes the color of the custom NSView when a color wheel in the bottom bar is changed, the bottom bar gets overwritten with the color. The following code illustrates this method (this code is in the custom NSView class:
- (void)changeBackgroundColor:(NSNotification *)notification
{
NSLog(#"Changed background color");
NSRect mRect = [self bounds];
NSColor * mNewColor = [theColorWell color];
[mNewColor set];
[NSBezierPath fillRect:mRect];
[self setNeedsDisplay:YES];
}
Resizing the window instantly corrects the problem, but obviously I don't want the user to have to resize the window for an obvious bug!
What I don't understand is why my bounds appear to be mapping to the parent window and not the custom NSView when I call setNeedsDisplay and yet the bound correctly adjust when I resize the window using the mouse (even if just by 1 pixel).
Do I somehow need to account for the bottom bar on the redraw?
Any and all help much appreciated.
You should do all your drawing in the drawRect: method of your custom NSView. Cocoa automatically sets up the graphics context for you when it calls this method - things may not draw correctly if you perform drawing operations in other methods.
Your code in drawRect: could set the colour to the the current background colour as specified by your NSColorWell and fill the dirtyRect rectangle with this.
Then in the other method just call [self setNeedsDisplay:YES]; and then drawRect: will automatically be called to redraw the view.
See here for more information: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CocoaViewsGuide/SubclassingNSView/SubclassingNSView.html#//apple_ref/doc/uid/TP40002978-CH7-SW4 (in particular the Drawing View Content section)