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
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 theyre even better but the layer interferes with the EffectView.
The thing thats 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.
Wasnt complicated after all. Im using Christians 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 dont need a VisualEffectView but just rounded corners, its even better to install a layer on the contentView with wantsLayer= true and set its cornerRadius and autoResizingMask appropriately. But a backing layer doesnt work with a VisualEffect, or only half of the time and the other half produces artifacts and non-transparencies.
EDIT: Didnt check if NSImageMBS supports Insets. If, you could probably create the mask only once in the open event as a resizable image and dont 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?
Hope you dont 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