Xojo - Control Locks

As we all know, Xojo supports “Lock” parameters for most controls, this set the behaviour of an embedded control, when its parent moves or changes size.

I am attempting to create a Swift framework, and am trying to figure out the best way to replicate a similar behaviour. I have come up with a few ideas, and don’t really like any of them

  1. Add Autolayout constraints when would be turned on/off . So far this is messy, and I can’t quite make it work properly
  2. Add an extension to the base object (NSVIEW) which would somehow determine what changes to the controls frame need to be made… Not tested, but feels just as messy
  3. forget about it entirely, and leave it as a manual exercise for the developer using this framework

Anyone have an idea what Xojo does behind the scenes? I doubt it is the AL method, as AL is new and macOS only…

The Xojo locks are roughly an autolayout constraint from the control to a permanently fixed distance from the left, right, top and bottom edges of the containing item

I think that would get you to the same thing as Xojo locks

but how are they implemented? since AL came out long after Xojo had this feature, and WIndows doesn’t have AL at all

Isn’t it ‘just’ 4 hidden integer properties holding ‘distancefromright’ ‘distancefromleft’ and so on?

When a window is resized it gets a WM_SIZE or WM_SIZING message from the API in the WIndowProc callback.
The child is resized/ moved in response

Xojo exposes a user-trappable version of this as Resized and Resizing, but will have done the control moves before it passes the message along.

The window listens for resize events and traverses controls to cause them to remain sized according to their locks as far as I can think

Thanks… so similar to #2 in my OP…

Now to figure the best way to add properties to the control… seems I will have to do it multiple times, as I cannot add them to to the superclasses :frowning:

I think I figured it out (but not tested it yet)
First I had to add properties to superclass of ALL controls… This is something that Swift doesn’t do in a straight forward manner… but I think I got it to work… this was the LOCKxxx direction flags

Then for each “container” type control… if its frame changed, it will pass the old and new frame sizes to a function that will examine the lock flags on each child control, and alter its frame based on its lockflags and how its parent frame changed…

for those interested :


extension NSView  {
	// nested structure
	private struct lockKeys {
		static var leftKey   : Bool = false
		static var topKey    : Bool = false
		static var rightKey  : Bool = false
		static var bottomKey : Bool = false
	}

	var lockLeft: Bool {
		get { return getAssociated(associatedKey: &lockKeys.leftKey) }
		set { setAssociated(value: newValue, associatedKey: &lockKeys.leftKey) }
	}

	var lockTop: Bool {
		get { return getAssociated(associatedKey: &lockKeys.topKey) }
		set { setAssociated(value: newValue, associatedKey: &lockKeys.topKey) }
	}

	var lockRight: Bool {
		get { return getAssociated(associatedKey: &lockKeys.rightKey) }
		set { setAssociated(value: newValue, associatedKey: &lockKeys.rightKey) }
	}

	var lockBottom: Bool {
		get { return getAssociated(associatedKey: &lockKeys.bottomKey) }
		set { setAssociated(value: newValue, associatedKey: &lockKeys.bottomKey) }
	}
}

// suport for "lock" properties above
extension NSObject {
	func setAssociated<Bool>(value: Bool, associatedKey: UnsafeRawPointer, policy: objc_AssociationPolicy = objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) -> Void {
		objc_setAssociatedObject(self, associatedKey, value, policy)
	}

	func getAssociated<Bool>(associatedKey: UnsafeRawPointer) -> Bool {
		let value = objc_getAssociatedObject(self, associatedKey) as? Bool
		return value ?? false as! Bool
	}
}

All controls inherit from NSView, and NSView inherits from NSObject… I could probably put the NSObject stuff into the NSView extension as well

IMHO AutoLayout constraints are quite a complex thing for what AutoResizingMask does perfectly. I built myself a method that creates a mask from the locks of a Xojo control when I embed a custom declared subclass and that works quite nicely.