What sucks when you are creating custom declared controls on macOS? The drawing coordinate system is reversed; Apple defines (0,0) as the lower left bottom. So you end up creating all kinds of conversions for your controls to align them with Xojos coordinate system. Or you give up and use Apples system, but that confuses a lot when you try to port something to iOS where the coordinates are like in Xojo.
NSView has an [quote]isFlipped:[/quote] property to determine when a views coordinate system should be treated Xojo-wise, but that property is read-only. Apple recommends to override this property. I could not find any Xojo information on how to and have finally figured it out. This may not be the most elegant way. If you have a better solution: Please! In case I have not been blind and there was no solution yet, heres how I made it (and how you can change properties and add your custom properties too):
A property on an Apple class can be retrieved by Objective Cs
class_getProperty (Class as Ptr, Propertyname as Cstring) method. That gives you the ptr to the property, You can retrieve the property list by
property_copyAttributeList (Property as Ptr, Byref Count As Integer). This returns the unreleased ptr to a C array of objc_property_attribute_t structures. I tried to use that, but a structure of 2 Cstring values (objc_property_attribute_t has two of them: name and value) does not give a reliable size. The Memoryblock created by that has an undetermined size, and while you could work your way through it, casting the objc_property_attribute_t structure on its ptrvalue didnt work.
I found it much easier then to use
property_getAttributes (property as Ptr) which returns the attributes names and values as a comma-separated Cstring. I simply converted this to Text, split it by its commas and then started to build a new MutableMemoryblock Lets call it ResultBlock.
An objc_property_attribute_t, if viewed as a Memoryblock, starts with two ptr values: The first pointing to its Name as Cstring, the second to its value as Cstring. So I create the MutableMemoryblock in the size of the count of the split text * Integersize * 2 - 8 Bytes for each attribute on 32 and 16 bytes on 64 Bit. If I want to add attributes, count must be increased of course.
Then I simply append a new memoryblock containing the attribute name and set ResultBlock.ptrvalue(0) to the position of the name (I used a helper variable giving me the offset from the ResultBlocks start) and another memoryblock with the Cstring of the attribute value. In case there is non, it must be a new memoryblock with size 1 an empty byte depicting the end of a CString. ResultBlock.ptrvalue(Integersize) gets set to this position. And so on.
So when adding an attribute for a property like isFlipped which comes with 3 attributes, I end up with a memoryblock around 60 bytes on 32 Bit, where the first 8 * 4 Bytes are the ptrs to the attached Cstrings that follow after the ptrs.
The attribute names are one-character Code:
[quote]R The property is read-only (readonly).
CThe property is a copy of the value last assigned (copy).
& The property is a reference to the value last assigned (retain).
N The property is non-atomic (nonatomic).
G The property defines a custom getter selector name. The name follows the G (for example, GcustomGetter,).
S The property defines a custom setter selector name. The name follows the S (for example, ScustomSetter:,).
D The property is dynamic (@dynamic).
W The property is a weak reference (__weak).
P The property is eligible for garbage collection.
t Specifies the type using old-style encoding.[/quote]
Thus, I attached “S” as a new name and “setFlipped:” as its value, creating the setter for this property, and then installed it all via
class_replaceProperty (result, prop.OriginalName.toCString(xojo.core.TextEncoding.ASCII), resultmb.data, attcount)
and registering the class pair as usual.
A new declare:
Protected Sub setFlipped lib AppkitFramework selector "setFlipped:" (id as ptr, value as Boolean) makes the property usable.