0

I've got NSWindows implementation that is used as modal authorization dialog. The code:

using System;
using AppKit;
using Cairo;

namespace SomeNameSpace
{
  public class DialogWindow : NSWindow
  {
    public DialogWindow() : base()
    {
      var stackView = new NSStackView(){
        AutoresizingMask = NSViewResizingMask.HeightSizable | NSViewResizingMask.WidthSizable,
      };
      stackView.WantsLayer = true;
      stackView.Layer.BackgroundColor = new CoreGraphics.CGColor(255f, 0f, 0f);
      stackView.Alignment = NSLayoutAttribute.Leading;
      stackView.Orientation = NSUserInterfaceLayoutOrientation.Vertical;
      ContentView = stackView; 
      SetFrame(new CoreGraphics.CGRect(Frame.Location, new CoreGraphics.CGSize(300, 210)), true);
      StyleMask |= NSWindowStyle.Closable;
    }

    public void ShowDialog()
    {
      NSApplication.SharedApplication.RunModalForWindow(this);
    }
  }

 public class AuthDialog : DialogWindow
  {
    public AuthDialog() : base()
    {
      var usernameLabel = new NSTextField() {
        StringValue = "Username",
        Editable = false,
        DrawsBackground = false,
        Selectable = false,
        Bezeled = false,
      };
      usernameLabel.SizeToFit();
      var usernameEditor = new NSTextField();
      var passwordLabel = new NSTextField() {
        StringValue = "Password",
        Editable = false,
        DrawsBackground = false,
        Selectable = false,
        Bezeled = false,
      };
      passwordLabel.SizeToFit();
      var passwordEditor = new NSSecureTextField();
      var actionButtonsView = new NSStackView() {
        Orientation = NSUserInterfaceLayoutOrientation.Horizontal,
      };
      actionButtonsView.WantsLayer = true;
      actionButtonsView.Layer.BackgroundColor = new CoreGraphics.CGColor(0f, 255f, 0f);
      var cancelButton = new NSButton() {
        Title = "Cancel",
      };
      var loginButton = new NSButton() {
        Title = "Login",
      };
      actionButtonsView.TranslatesAutoresizingMaskIntoConstraints = false;
      actionButtonsView.AddArrangedSubview(cancelButton);
      actionButtonsView.AddArrangedSubview(loginButton);
      loginButton.SizeToFit();
      var stackView = (NSStackView)ContentView;
      stackView.AddArrangedSubview(usernameLabel);
      stackView.AddArrangedSubview(usernameEditor);
      stackView.AddArrangedSubview(passwordLabel);
      stackView.AddArrangedSubview(passwordEditor);
      stackView.AddArrangedSubview(actionButtonsView);
      ShowsResizeIndicator = false;
    }
  }
}

It simply creates NSStackView based layout. And looks like this: enter image description here

The question is how can I align last subview (containing buttons) to the right of the parent view (and window)? The programming language doesn't matter. It's easily translated to swift\obj-c and vice-versa.

Ivan Ičin
  • 9,672
  • 5
  • 36
  • 57
Keltar Helviett
  • 638
  • 1
  • 7
  • 13

2 Answers2

1

NSStackView uses the auto layout system. So things like sizetofit should probably not be used. Look at Contenthuggingpriority and contentcompressionpriority on the buttons and distribution on the stackview for sizing.

Replace

actionButtonsView.AddArrangedSubview(cancelButton);
actionButtonsView.AddArrangedSubview(loginButton);

With

actionButtonsView.AddView(cancelButton, NSStackViewGravity.Trailing);
actionButtonsView.AddView(loginButton, NSStackViewGravity.Trailing);

Cannot test it now myself, maybe other modifications are also needed.

svn
  • 1,235
  • 10
  • 22
0

There is no way to customize the NSStackView itself to achieve this, every view is either leading, trailing, or centered.

However, you can add a constraint to the horizontal stack view that contains the buttons and pin it to the trailing side of the enclosing vertical stack view:

let cancelButton = NSButton(title: "Cancel", target: nil, action: nil)
let loginButton = NSButton(title: "Login", target: nil, action: nil)

// Set content hugging high enough so that the vertical stack view won't
// stretch the buttons in an effort to align them along the leading edge
cancelButton.setContentHuggingPriority(.defaultHigh, for: .horizontal)
loginButton.setContentHuggingPriority(.defaultHigh, for: .horizontal)

// The horizontal stack view's distribution needs to be fill
let horizontalStackView = NSStackView(views: [cancelButton, loginButton])
horizontalStackView.distribution = .fill

stackView.addArrangedSubview(horizontalStackView)

// Pins the buttons to the right (trailing) edge of the vertical stack view
NSLayoutConstraint.activate([
    horizontalStackView.trailingAnchor.constraint(equalTo: stackView.trailingAnchor)
])

Alternatively, you might want to try NSGridView to accomplish layouts like this. enter image description here

Lucas Derraugh
  • 6,929
  • 3
  • 27
  • 43