Vibrancy to a Canvas

I have a transparent window. It has a custom background that’s a Canvas. I’d like to add a vibrant effect to that Canvas. How can I do it?

Using the graphics.mask? Do you mean hue, saturation, lighting effect?

Sorry, I should have been more specific. I’m talking about the translucency effect that Yosemite introduced.

Have you had a look here : https://forum.xojo.com/16453-window-transparency-vibrancy

There is a vivid discussion about methods and several examples posted.

Sam Rowland wrote a very good article about translucency and other Yosemite Effects in xDev Magazine - I guess was the End of 2014…

@Michel Bujardet: Yes, I’ve looked at them. Those examples seem to be only for Window backgrounds.

Sometimes it is better to start somewhere that works. As far as I know, it was quite a lot of doing for Sam Rowlands to get that working fine.

I what you want to do is vibrancy as Apple intends it, it involves a vibrant window anyway. Or do you want to do vibrancy for the canvas over an opaque window ?

I believe instead of adding the NSVisualEffectView to the contentView you just add it to the Canvas.

I thought about it too. But then the window remains opaque. Would that not look odd ?

Would it not be more conformant to Yosemite aesthetics to have a canvas with some measure of transparency resting on a vibrant window ?

Yeah, but it sounds like what Thomas wants.

@Will Shank: With the example you provided in the other thread, I managed to add the effect to a Canvas. But I also discovered now that the effect layer is defined by NSRect, so it’s always a rectangle. So, what I need (I think) is a way to make a custom shaped effect layer.

I don’t think that’s necessary, Thomas. A VisualEffectview (UI or NS) is a sublass of a view, and therefore has a CALayer property. Have you tried creating a layer for the effectview (WantsLayer = true) and then modifiy the layer’s CornerRadius property?

Is the CALayer added to the EffectView or the Canvas? I tried both and it makes the effect disappear. When added to the effect the Canvas’ Paint code is just rendered normally, when added to the Canvas it’s as if the Canvas isn’t there, nothing drawn.

I got a non-rect shape vibrant by setting the effect views maskImage.

[code] dim p As new Picture(Canvas1.Width, Canvas1.Height)
p.Graphics.ForeColor = &c000000
p.Graphics.FillOval(0, 0, Canvas1.Width, Canvas1.Height)

dim img As new NSImage§ //MacOSLib

declare sub setMaskImage lib CocoaLib selector “setMaskImage:” (id as ptr, img As Ptr)

setMaskImage(effectView, img)[/code]

Looks good in an opaque window, however the edges are jaggy in a transparent window :frowning:

That’s how we’ve done it for apps where we just want a section of the window to use the effect. Check out ‘Magic’ where we even split the window, one with light and one with dark.

Yup, join the club. I’ve tried for a while to recreate the volume notification windows on Yosemite and not been successful yet. I figured that one day the solution would present it’s self.

To take up a really old thread: After a lot of experimenting, I think I managed to mask a an EffetView well enough to look ok on a Retina display too.

There are small edges on the beginning of the curve, but depending on the cornerRadius they are only visible if you look very, very close. With a path on a layer they’re even better but the layer interferes with the EffectView.
The thing that’s bothering me now is Vibrancy: Would it be enough to return a True value in a allowsVibrancy custom view subclass? This should be doable. Or is there more logic necessary behind?

Looks good.

Wasn’t complicated after all. I’m using Christian’s classes with a computed window property NSWin that returns the NSWindowMBS object for the window and attach an EffectView to it in its open event, while buffering it in a window property for easy access:

Sub Open() #if targetmacos nswin.styleMask = 4106 nswin.isMovableByWindowBackground = true nswin.backgroundColor = NSColorMBS.clearColor EffectView= new NSVisualEffectViewMBS(0, 0, width, height) EffectView.autoresizesSubviews = true EffectView.blendingMode = NSVisualEffectViewMBS.NSVisualEffectBlendingModeBehindWindow EffectView.autoresizingMask = 18 EffectView.material = EffectView.NSVisualEffectMaterialDark EffectView.state = EffectView.NSVisualEffectStateFollowsWindowActiveState nswin.contentView.addSubview(EffectView, -1, nil) #endif End Sub

Then in the paint event, I create a Mask image and attach it to the effectView:

Sub Paint(g As Graphics, areas() As REALbasic.Rect) if EffectView <> nil then dim mask as new picture(width*NSWin.backingScaleFactor, Height*NSWin.backingScaleFactor) dim maskgraphics as Graphics = mask.Graphics dim mcc as CGContextMBS = CGContextMBS.contextWithCGContext(g.Handle(g.HandleTypeCGContextRef)) mcc.InterpolationQuality = 3 g.AntiAlias = true maskgraphics.AntiAlias = true maskgraphics.ForeColor= &c00000000 maskgraphics.FillRoundRect(0,0,maskgraphics.Width, maskgraphics.Height, 40*NSWin.backingScaleFactor, 40*NSWin.backingScaleFactor) EffectView.maskImage = new NSImageMBS(mask) mcc.Flush end if End Sub

(Could probably be done a bit more elegantly).

If you don’t need a VisualEffectView but just rounded corners, it’s even better to install a layer on the contentView with wantsLayer= true and set its cornerRadius and autoResizingMask appropriately. But a backing layer doesn‘t work with a VisualEffect, or only half of the time and the other half produces artifacts and non-transparencies.

EDIT: Didn’t check if NSImageMBS supports Insets. If, you could probably create the mask only once in the open event as a resizable image and don’t have to worry about recreating it anymore.

I tried to get to work but it fails. Do you have a small example project as a download? :slight_smile:

Hope you don’t mind if I take the easy way and send you the current state of my complete project window:
https://dl.dropboxusercontent.com/u/21200221/Xojo/Uphonia%20collection.zip