simple CALayer - example ?

Hi,

is it possible to use a CALayer for a Xojo canvas ? I am not familiar with CALayer so I just
tried a simple thing but Xojo crashes.

const CocoaLib = “cocoa”
declare sub setLayer lib CocoaLib selector “setLayer:” (ob_id As Ptr, p as ptr)
declare sub setNeedsDisplay lib CocoaLib selector “setNeedsDisplay” (ob_id As Ptr)
declare function layer lib CocoaLib selector “layer” (ob_id As Ptr) As Ptr
declare function NSClassFromString lib CocoaLib (cls as CFStringRef) as ptr
declare sub setWantsLayer lib CocoaLib selector “setWantsLayer:” (ob_id As Ptr, b as Boolean)
declare sub setBackgroundColor lib CocoaLib selector “setBackgroundColor:” (obj_id as Ptr, aColor as Ptr)

dim c as Color = Color.black
dim col() as double = Array(c.Red/255,c.Green/255,c.Blue/255,(255-c.Alpha)/255)
dim cgcm As new xojo.Core.MutableMemoryBlock((col.Ubound+1)4)
for i as integer=0 to col.Ubound
cgcm.SingleValue(i
4) = col(i)
next

dim viewRef as ptr = ptr(me.Handle)
dim layerRef as ptr =layer(NSClassFromString(“CALayer”))
self.theLayer = layerRef
setLayer(viewRef ,layerRef)
setWantsLayer(viewRef, true)
setBackgroundColor(layerRef, cgcm.Data)
setNeedsDisplay(layerRef)

There are numerous discussions that mention CALayer in this forum :
https://forum.xojo.com/conversations/all?search=calayer

haven’t found any useful CALayer example or code for OSX.

Did you check MBS Plugins?
Includes a couple of CALayer classes and examples.

[quote=240857:@Christian Schmitz]Did you check MBS Plugins?
Includes a couple of CALayer classes and examples.[/quote]

A plugin wasn’t the question. Thanks for placing your ad.

But maybe you can see how to use CALayer properly in it’s example.

Where and how?

I tried your code and I get a crash. The log mentions “CA::Render::convert_cgcolor” so I commented out this line

setBackgroundColor(layerRef, cgcm.Data)

and no more crash, so it’s the background color not CALayer that’s the problem I think.

edit: yeah, backgroundColor takes a CGColor not an array of singles.

Thanks Will. I haven’t seen the conversion from NSColor to CGColor. It works now!. :slight_smile:

const CocoaLib = “cocoa”
declare sub setLayer lib CocoaLib selector “setLayer:” (ob_id As Ptr, p as ptr)
declare sub setNeedsDisplay lib CocoaLib selector “setNeedsDisplay” (ob_id As Ptr)
declare function layer lib CocoaLib selector “layer” (ob_id As Ptr) As Ptr
declare function NSClassFromString lib CocoaLib (cls as CFStringRef) as ptr
declare function blueColor lib CocoaLib selector “blueColor” (obj as ptr) as ptr
declare function CGColor lib CocoaLib selector “CGColor” (obj as ptr) as ptr

declare sub setWantsLayer lib CocoaLib selector “setWantsLayer:” (ob_id As Ptr, b as Boolean)
declare sub setBackgroundColor lib CocoaLib selector “setBackgroundColor:” (obj_id as Ptr, aColor as Ptr)

dim c as ptr = CGColor( blueColor( NSClassFromString(“NSColor”)))
dim viewRef as ptr = ptr(me.Handle)
dim layerRef as ptr =layer(NSClassFromString(“CALayer”))
self.theLayer = layerRef
setLayer(viewRef ,layerRef)
setWantsLayer(viewRef, true)
setBackgroundColor(layerRef, c)
setNeedsDisplay(layerRef)

After spending some time, I could figure how CALayers work. The are possibilities are huge.
However, I am wondering how to reset layers and have the original canvas paint() event work again.
code project enclosed.

https://www.dropbox.com/s/td1xbeo5gs23dxu/CALayer1.xojo_binary_project?dl=0

You need to tell it it doesn’t want layers

setWantsLayer(Ptr(Canvas1.Handle), false)

[quote=241036:@Will Shank]You need to tell it it doesn’t want layers

setWantsLayer(Ptr(Canvas1.Handle), false)

Hmm doesn’t seem to work. Canvas1 does nothing. Well, I’ll check again…

I have cleaned up the code and made a CALayer and CATextLayer class to get an idea. That’s a lot of
fun :slight_smile: The classes work but may still have bugs though.
https://www.dropbox.com/s/izfawy0fszhqqie/CALayer2.zip?dl=0

[quote=241029:@Rob Egal]However, I am wondering how to reset layers and have the original canvas paint() event work again.
[/quote]
A hint without knowing its value: Add the debugdescription API method to your NSView/Canvas and investigate its values when you change layer-related properties. Maybe wantsUpdateLayer needs to be overridden with false when you try to reset the view to CGContext based drawing again. As it’s not calling the paint event, it looks like the drawRect: still forwards to layer based drawing.

Just a shot in the dark, but did you try setting the layer to nil after setting wantsLayer to false?

setLayer(viewRef ,nil)

From a SWIFT point of view… I have found that you need to remove the layers from the SuperView… or REPLACE the layer based on its index (which can change as you add/delete layers). I found this when adding a Gradient layer, and trying to change the Gradient later on in the program. The solution was to NAME the Gradient layer, and when attempting to change it, I had to determine if a layer existing with that name, remove it, and insert the new Gradient.

I too thought about “DebugDescription”, but unless XOJO sets that value for you, you might find it to be NIL

You should be able to read the values Apple puts into this string. A different thing is description which I found to be empty usually.

I was looking at “Description” which is NIL
but DebugDescription is not a simple string…it seems to be a “description” of all the attributes of the layer, so I’d say that is NOT a good thing to track layer identification with

here is an example :

Using project CALayer1, change the code in PushButton2 to this

declare sub setWantsLayer lib "Cocoa" selector "setWantsLayer:" (ob_id As Ptr, b as Boolean) setWantsLayer(Ptr(Canvas1.Handle), false)
For me Canvas1 turns solid black, the Paint event is drawing.

[quote=241122:@Will Shank]Using project CALayer1, change the code in PushButton2 to this

declare sub setWantsLayer lib "Cocoa" selector "setWantsLayer:" (ob_id As Ptr, b as Boolean) setWantsLayer(Ptr(Canvas1.Handle), false)
For me Canvas1 turns solid black, the Paint event is drawing.[/quote]

Yepp it works. I’ve found the trouble maker…
// action - in the Button
dim viewRef as ptr = ptr(me.Handle)
setWantsLayer(viewRef, false)

I should subclass the canvas and put the stuff in there.