The macOS app within it does not contain the constraints you created during the webinar. this makes the example far less informative than it could be. You ended the Webinar with a significant working set of constrains on the window, but the current example only does a few of these things.
I just rewatched and there wasn’t much missing. I just coped them from the video. I had thought it had something to make labels right aligned, but it doesn’t seem to.
One thing that is a little odd, Label8 doesn’t seem to line up with the RadioButton.
OK, I’ve found a way of right aligning labels using the following two items:
MyLabel.UseIntrinsicWidth // fix the width to what is required
MyControl.AlignToLabel( MyLabel ) // align the label and control vertically by baseline
MyControl.LeftAnchor.ConstraintEqualToSystemSpacingAfterAnchor( MyLabel.RightAnchor ).Active = True // place the control just after the label
What I can’t figure out is how to make all the labels equal width to the longest, which could change by language. I suppose if I use:
MyLabel1.UseIntrinsicWidth
MyLabel2.UseIntrinsicWidth
MyLabel3.UseIntrinsicWidth
Var nMax as Integer = max( MyLabel1.Width, MyLabel2.Width, MyLabel3.Width )
// Then set each label width nMax, allowing the controls to move over to take account of the label width
Well, that doesn’t seem to work. Likely for 2 reasons:
The .Width property doesn’t seem to be updated by the UseIntrinsicWidth
Once the UseIntrinsicWidth constraint is applied it would likely override the attempt to change the widths.
Right. As soon as you start using constraints, you can basically ignore the “actual width” thing.
I’m not sure it’s worth trying to get all the labels to be the same width though. You could just add constraints so that all of the controls to the right of the labels have equal LeadingEdge constraints and let AutoLayout figure it out. You’d just need to tell the labels that they’re leadingEdge >= wherever your column should start.
I’m not near my computer at the moment but if I remember when I am, I can take a look.
I did notice that the IDE keeps making the Direction property of the UIStackView invisible so I may need to rename that property.
As long as the longest of them for the current given language
Thus avoiding the ‘German gap’ the English suffers from.
Obviously, I can offset the popup from the label (with standard gap), the segment from the popup with (standard gap). I can use intrinsic size to grow / shrink the labels, but I need ‘Sort by’ to be the same size as ‘Then sort by’.
This suggests a recipe. I’m trying to get that to work in this framework:
Another interesting thought. If I have a container control, can I set constraints on the container itself to fit its parent window. I’m thinking of being able to make the container added to an Open/Save dialog, as an accessory view, be resizable with the dialog. Currently it is fixed and floats to the centre.
if you call ConvertToAutolayout on the container, it should technically just work. That is, the container will no longer have a fixed width. That said, centering the accessory view is probably the macOS default as I don’t seem to have called anything specific to make it do that.
Perfect, thank you. I’ve just tried it using multiple languages and it works a treat.
The only issue is that the labels are set to Right aligned, which I know I asked for. When you use an RTL language the alignment should be reversed. It is trivial to fix with a little code:
If SystemIsRTL Then
Var oLabel As DesktopLabel
For Each oControl As Object In Self.Controls
If oControl IsA DesktopLabel Then
oLabel = DesktopLabel( oControl )
If oLabel.TextAlignment = TextAlignments.Right Then
oLabel.TextAlignment = TextAlignments.Left
Else
oLabel.TextAlignment = TextAlignments.Right
End If
End If
Next
End If
The code ignores the Default alignment option as it automatically adjusts to the correct orientation (Left on LTR and Right on RTL). However, Xojo is missing an option for “Contra-default”, as I think macOS is also.
I think that would a useful example for your system. It’s a relatively common layout and a good example of using your code.
Last nights exercise made me notice that the hugging and compression stuff wasn’t working on macOS so that’s been fixed n the repo and in that project. We might be able to turn off the alignment if the leading constraints for the labels were set to “greater than or equal” instead of just “equal”.
All excellent stuff. I keep getting caught on the fact that there is only a “ConstraintEqualToSystemSpacingAfterAnchor”, so when dealing with trailing edges you have to reverse the control / window arrangement. ie you have to place the window / container edge to be SystemSpacing after the control. and not the control SystemSpacing before the Window edge. Logically the same thing I know but semantically warps my mind.
One thing I’ve not quite figured yet is wether the Window .Height and .Width remain valid. I have certain dialog boxes that are resizable and that remember their last size and restore that for the next time. I’ve yet to see if that is maintained. Easy enough to test I suppose.
Just tried and it causes issues with the equal size requirement. The longer one is right aligned and the shorter one left aligned to the left of the longer one. It also causes the popups to crash down to minimum size.
I’m going to watch the video again, I’m attempting to setup a constraint that would limit the window size based on content and I’m sure you did that in the vid.
I also want it to work the other way, ie if it starts that way and the text becomes longer it expands the window to fit the contents. Again, I think you did this in the vid. I’ll watch again tomorrow. It is very likely Priorities.
So… this is one of those places where the order of the constraints matters. The fact that the pop up menu is going outside of the group probably means that you got it backwards.
Self.ConvertToAutolayout( True, True )
// set the existing constraints so they won't conflict with the ones we're creating below
Self.ConvertConstraintsForAllControls( 1 )
// 1. Remove the existing width constraints for the controls
'RemoveWidthConstraint( PopupMenu1 )
'RemoveWidthConstraint( PopupMenu2 )
RemoveWidthConstraint( Label1 )
RemoveWidthConstraint( Label2 )
RemoveWidthConstraint( GroupBox1 )
GroupBox1.LeadingAnchor.ConstraintEqualToSystemSpacingAfterAnchor( Self.LeadingAnchor ).Active = True
Self.TrailingAnchor.ConstraintEqualToSystemSpacingAfterAnchor( GroupBox1.TrailingAnchor ).Active = True
// 2. Bring the Hugging priority up for the labels so they're not allowed to expand
// and the compression resistance up to prevent the labels from being compressed
Label1.HuggingPriorityForAxis( SOSConstraintKit.Axis.Horizontal ) = 999
Label2.HuggingPriorityForAxis( SOSConstraintKit.Axis.Horizontal ) = 999
Label1.CompressionResistancePriorityForAxis( SOSConstraintKit.Axis.Horizontal ) = 1000
Label2.CompressionResistancePriorityForAxis( SOSConstraintKit.Axis.Horizontal ) = 1000
// 3. Set the widths equal to one another
Label1.WidthAnchor.ConstraintEqualToAnchor( Label2.WidthAnchor ).Active = True
// 4. The controls on the right should be aligned to the labels
PopupMenu1.AlignToLabel( Label1 )
PopupMenu2.AlignToLabel( Label2 )
// 5. constrain the trailing edge of the popup menus against the trailing edge of view
GroupBox1.TrailingAnchor.ConstraintEqualToSystemSpacingAfterAnchor( PopupMenu1.TrailingAnchor ).Active = True
GroupBox1.TrailingAnchor.ConstraintEqualToSystemSpacingAfterAnchor( PopupMenu2.TrailingAnchor ).Active = True
// 6. constrain the leading edge of the labels to the leading edge of the view
Label1.LeadingAnchor.ConstraintEqualToSystemSpacingAfterAnchor( GroupBox1.LeadingAnchor ).Active = True
Label2.LeadingAnchor.ConstraintEqualToSystemSpacingAfterAnchor( GroupBox1.LeadingAnchor ).Active = True