diff options
author | Dominique Louis <dominique@Dominiques-MacBook-Pro-2.local> | 2019-03-21 16:54:10 +0300 |
---|---|---|
committer | CartBlanche <savagesoftware@gmail.com> | 2019-06-26 21:17:31 +0300 |
commit | bbe46e57cb1627d26ccc0e68dc9b2ed877b3d170 (patch) | |
tree | db3205f282da1b63cf92c1a5cee3d7586743c525 /Xamarin.PropertyEditing.Mac/Controls | |
parent | 6be4f60fa2d4adf31893c75d8a8ef8ce879b6bd3 (diff) |
[Mac] Make Binding Dialog Modal
[Mac] Ensure property button view is cleared
Diffstat (limited to 'Xamarin.PropertyEditing.Mac/Controls')
16 files changed, 1212 insertions, 1452 deletions
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BaseSelectorOutlineView.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BaseSelectorOutlineView.cs new file mode 100644 index 0000000..e18c197 --- /dev/null +++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BaseSelectorOutlineView.cs @@ -0,0 +1,38 @@ +using System; +using AppKit; +using Foundation; + +namespace Xamarin.PropertyEditing.Mac +{ + internal class BaseSelectorOutlineView : NSOutlineView + { + public BaseSelectorOutlineView () + { + Initialize (); + } + + // Called when created from unmanaged code + public BaseSelectorOutlineView (IntPtr handle) : base (handle) + { + Initialize (); + } + + // Called when created directly from a XIB file + [Export ("initWithCoder:")] + public BaseSelectorOutlineView (NSCoder coder) : base (coder) + { + Initialize (); + } + + public override bool ValidateProposedFirstResponder (NSResponder responder, NSEvent forEvent) + { + return true; + } + + private void Initialize () + { + HeaderView = null; + TranslatesAutoresizingMaskIntoConstraints = false; + } + } +} diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingEditorWindow.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingEditorWindow.cs index 7e66a6b..f41673f 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingEditorWindow.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingEditorWindow.cs @@ -10,243 +10,536 @@ using Xamarin.PropertyEditing.ViewModels; namespace Xamarin.PropertyEditing.Mac { - internal class BindingEditorWindow : BasePanelWindow + internal class BindingEditorWindow : NSPanel { - private readonly CreateBindingViewModel viewModel; + private NSButton buttonDone; + private NSButton buttonCancel; + + private NSPopUpButton bindingTypePopup; + + private NSPopUpButton valueConverterPopup; + + private NSButton addConverterButton; + + private NSView ancestorTypeBox; + + private NSView mainContainer; + private NSView bindingPropertiesView; + private NSView flagsPropertiesView; + private NSButton buttonMoreSettings; + + private nfloat MoreSettingsViewHeight { get; set; } + + private const float AddConverterButtonSize = 20; + + private new ModalWindowCloseDelegate Delegate + { + get => (ModalWindowCloseDelegate)base.Delegate; + set => base.Delegate = value; + } + private readonly PropertyEditorSelector editorSelector = new PropertyEditorSelector (); - internal BindingEditorWindow (IHostResourceProvider hostResources, PropertyViewModel propertyViewModel) + private const string BindingPropertiesIdentifier = "BindingProperties"; + private const string FlagPropertiesIdentifier = "FlagProperties"; + internal const float HeaderHeight = 28f; + + internal CreateBindingViewModel ViewModel { get; } + + private HeaderView typeHeader; + + private UnfocusableTextField longDescription; + private UnfocusableTextField labelOtherSettings; + private TypeSelectorControl typeSelectorControl; + + private nfloat heightConstant, titleBarHeight; + + private NSLayoutConstraint ancestorTypeBoxHeightConstraint; + private NSLayoutConstraint bindingPropertiesViewHeightConstraint; + + private BindingPathSelectorControl pathSelectorControl; + + internal BindingEditorWindow (IHostResourceProvider hostResources, PropertyViewModel propertyViewModel) + : base (new CGRect (0, 0, 728, 445), NSWindowStyle.Titled | NSWindowStyle.Closable | NSWindowStyle.Resizable, NSBackingStore.Buffered, true) { - this.viewModel = new CreateBindingViewModel (propertyViewModel.TargetPlatform, propertyViewModel.Editors.Single (), propertyViewModel.Property); + if (hostResources == null) + throw new ArgumentNullException (nameof (hostResources)); + if (propertyViewModel == null) + throw new ArgumentNullException (nameof (propertyViewModel)); - Title = this.viewModel.PropertyDisplay; - this.ButtonDone.Title = Properties.Resources.CreateBindingTitle; + ViewModel = new CreateBindingViewModel (propertyViewModel.TargetPlatform, propertyViewModel.Editors.Single (), propertyViewModel.Property, includeAddValueConverter: false); - foreach (BindingSource item in this.viewModel.BindingSources.Value) { - this.BindingTypePopup.Menu.AddItem (new NSMenuItem (item.Name) { - RepresentedObject = new NSObjectFacade (item) - }); - } + Delegate = new ModalWindowCloseDelegate (); + + FloatingPanel = true; + + MaxSize = new CGSize (960, 720); // TODO discuss what the Max/Min Size should be and if we should have one. + MinSize = new CGSize (320, 240); + + this.mainContainer = new NSView { + TranslatesAutoresizingMaskIntoConstraints = false + }; + + this.buttonDone = new NSButton { + BezelStyle = NSBezelStyle.Rounded, + ControlSize = NSControlSize.Regular, + Highlighted = true, + KeyEquivalent = "\r", // Fire when enter pressed + TranslatesAutoresizingMaskIntoConstraints = false, + }; + + this.mainContainer.AddSubview (this.buttonDone); + + this.buttonCancel = new NSButton { + BezelStyle = NSBezelStyle.Rounded, + ControlSize = NSControlSize.Regular, + Title = Properties.Resources.Cancel, + TranslatesAutoresizingMaskIntoConstraints = false, + }; + + this.buttonCancel.Activated += (sender, e) => { + Delegate.Response = NSModalResponse.Cancel; + Close (); + }; - this.BindingTypePopup.Activated += (o, e) => { - if (this.BindingTypePopup.Menu.HighlightedItem.RepresentedObject is NSObjectFacade facade) { - this.viewModel.SelectedBindingSource = (BindingSource)facade.Target; + this.mainContainer.AddSubview (this.buttonCancel); + + var bindingTypeLabel = new UnfocusableTextField { + Alignment = NSTextAlignment.Right, + Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, 13), + StringValue = Properties.Resources.BindingType + ":", + TranslatesAutoresizingMaskIntoConstraints = false, + }; + + this.mainContainer.AddSubview (bindingTypeLabel); + + this.bindingTypePopup = new FocusablePopUpButton { + ControlSize = NSControlSize.Regular, + Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, 13), + StringValue = String.Empty, + TranslatesAutoresizingMaskIntoConstraints = false, + }; + + var bindingTypeMenuList = new NSMenu (); + this.bindingTypePopup.Menu = bindingTypeMenuList; + this.mainContainer.AddSubview (this.bindingTypePopup); + + var valueConverterLabel = new UnfocusableTextField { + Alignment = NSTextAlignment.Right, + Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, 13), + StringValue = Properties.Resources.Converter + ":", + TranslatesAutoresizingMaskIntoConstraints = false, + }; + + this.ancestorTypeBox = new NSView { + TranslatesAutoresizingMaskIntoConstraints = false, + WantsLayer = true, + + // Layer out of alphabetical order so that WantsLayer creates the layer first + Layer = { + CornerRadius = 1.0f, + BorderColor = new CGColor (.5f, .5f, .5f, 1.0f), + BorderWidth = 1, + }, + }; + + this.mainContainer.AddSubview (this.ancestorTypeBox); + + this.mainContainer.AddSubview (valueConverterLabel); + + this.valueConverterPopup = new FocusablePopUpButton { + TranslatesAutoresizingMaskIntoConstraints = false, + StringValue = String.Empty, + ControlSize = NSControlSize.Regular, + Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, 13), + }; + + var valueConverterMenuList = new NSMenu (); + this.valueConverterPopup.Menu = valueConverterMenuList; + this.mainContainer.AddSubview (this.valueConverterPopup); + + this.addConverterButton = new CommandButton { + BezelStyle = NSBezelStyle.Rounded, + Command = ViewModel.RequestAddValueConverterCommand, + Image = NSImage.ImageNamed (NSImageName.AddTemplate), + Title = string.Empty, + ToolTip = Properties.Resources.AddValueConverterEllipsis, + TranslatesAutoresizingMaskIntoConstraints = false, + }; + + this.mainContainer.AddSubview (this.addConverterButton); + + this.buttonMoreSettings = new NSButton { + BezelStyle = NSBezelStyle.Disclosure, + Title = string.Empty, + TranslatesAutoresizingMaskIntoConstraints = false, + }; + this.buttonMoreSettings.SetButtonType (NSButtonType.PushOnPushOff); + + this.mainContainer.AddSubview (this.buttonMoreSettings); + + this.labelOtherSettings = new UnfocusableTextField { + Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, 13), + StringValue = Properties.Resources.OtherSettings, + TranslatesAutoresizingMaskIntoConstraints = false, + }; + + this.mainContainer.AddSubview (this.labelOtherSettings); + + this.bindingPropertiesView = new NSView { + Hidden = true, + TranslatesAutoresizingMaskIntoConstraints = false, + WantsLayer = true, + + // Layer out of alphabetical order so that WantsLayer creates the layer first + Layer = { + CornerRadius = 1.0f, + BorderColor = new CGColor (.5f, .5f, .5f, .5f), + BorderWidth = 1, + }, + }; + + this.mainContainer.AddSubview (this.bindingPropertiesView); + + this.flagsPropertiesView = new NSView { + Hidden = true, + TranslatesAutoresizingMaskIntoConstraints = false, + WantsLayer = true, + + // Layer out of alphabetical order so that WantsLayer creates the layer first + Layer = { + CornerRadius = 1.0f, + BorderColor = new CGColor (.5f, .5f, .5f, .5f), + BorderWidth = 1, + }, + }; + + this.mainContainer.AddSubview (this.flagsPropertiesView); + + //Work out the titlebar height + this.titleBarHeight = Frame.Size.Height - ContentRectFor (Frame).Size.Height; + + this.ancestorTypeBoxHeightConstraint = NSLayoutConstraint.Create (this.ancestorTypeBox, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this.mainContainer, NSLayoutAttribute.Bottom, 1f, -145f); + this.heightConstant = this.ancestorTypeBoxHeightConstraint.Constant; + + this.bindingPropertiesViewHeightConstraint = NSLayoutConstraint.Create (this.bindingPropertiesView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 124); + + this.buttonMoreSettings.Activated += OnButtonMoreSettingsToggled; + + this.pathSelectorControl = new BindingPathSelectorControl (ViewModel); + this.mainContainer.AddSubview (this.pathSelectorControl); + + this.mainContainer.AddConstraints (new[] { + NSLayoutConstraint.Create (bindingTypeLabel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.bindingTypePopup, NSLayoutAttribute.Top, 1f, 0f), + NSLayoutConstraint.Create (bindingTypeLabel, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.mainContainer, NSLayoutAttribute.Left, 1f, 21f), + NSLayoutConstraint.Create (bindingTypeLabel, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 20), + + NSLayoutConstraint.Create (this.bindingTypePopup, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.mainContainer, NSLayoutAttribute.Top, 1f, 18f), + NSLayoutConstraint.Create (this.bindingTypePopup, NSLayoutAttribute.Left, NSLayoutRelation.Equal, bindingTypeLabel, NSLayoutAttribute.Right, 1f, 10f), + + NSLayoutConstraint.Create (this.ancestorTypeBox, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.bindingTypePopup, NSLayoutAttribute.Bottom, 1f, 18f), + NSLayoutConstraint.Create (this.ancestorTypeBox, NSLayoutAttribute.Left, NSLayoutRelation.Equal, bindingTypeLabel, NSLayoutAttribute.Left, 1f, 0f), + NSLayoutConstraint.Create (this.ancestorTypeBox, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.pathSelectorControl, NSLayoutAttribute.Left, 1f, -8f), + this.ancestorTypeBoxHeightConstraint, + + NSLayoutConstraint.Create (this.pathSelectorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Top, 1f, 0f), + NSLayoutConstraint.Create (this.pathSelectorControl, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.mainContainer, NSLayoutAttribute.Right, 1f, -21f), + NSLayoutConstraint.Create (this.pathSelectorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, -30f), + NSLayoutConstraint.Create (this.pathSelectorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal,this.ancestorTypeBox, NSLayoutAttribute.Height, 1f, 0f), + + NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Bottom, 1f, 22f), + NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Left, NSLayoutRelation.Equal, bindingTypeLabel, NSLayoutAttribute.Left, 1f, 0f), + NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 20), + + NSLayoutConstraint.Create (this.valueConverterPopup, NSLayoutAttribute.Top, NSLayoutRelation.Equal, valueConverterLabel, NSLayoutAttribute.Top, 1f, 0f), + NSLayoutConstraint.Create (this.valueConverterPopup, NSLayoutAttribute.Left, NSLayoutRelation.Equal, valueConverterLabel, NSLayoutAttribute.Right, 1f, 10f), + NSLayoutConstraint.Create (this.valueConverterPopup, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, -AddConverterButtonSize - 83), // TODO Need a better calculation here + + NSLayoutConstraint.Create (this.addConverterButton, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.valueConverterPopup, NSLayoutAttribute.Top, 1f, 0f), + NSLayoutConstraint.Create (this.addConverterButton, NSLayoutAttribute.Right, NSLayoutRelation.Equal,this.ancestorTypeBox, NSLayoutAttribute.Right, 1f, 0f), + NSLayoutConstraint.Create (this.addConverterButton, NSLayoutAttribute.Width, NSLayoutRelation.Equal, 1f, AddConverterButtonSize), + NSLayoutConstraint.Create (this.addConverterButton, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, AddConverterButtonSize), + + NSLayoutConstraint.Create (this.buttonMoreSettings, NSLayoutAttribute.Top, NSLayoutRelation.Equal, valueConverterLabel, NSLayoutAttribute.Bottom, 1f, 18f), + NSLayoutConstraint.Create (this.buttonMoreSettings, NSLayoutAttribute.Left, NSLayoutRelation.Equal, bindingTypeLabel, NSLayoutAttribute.Left, 1f, -5f), + NSLayoutConstraint.Create (this.buttonMoreSettings, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 20), + NSLayoutConstraint.Create (this.buttonMoreSettings, NSLayoutAttribute.Width, NSLayoutRelation.Equal, 1f, 20), + + NSLayoutConstraint.Create (this.labelOtherSettings, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.buttonMoreSettings, NSLayoutAttribute.Top, 1f, -1f), + NSLayoutConstraint.Create (this.labelOtherSettings, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.buttonMoreSettings, NSLayoutAttribute.Right, 1f, 0f), + NSLayoutConstraint.Create (this.labelOtherSettings, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 20), + + NSLayoutConstraint.Create (this.bindingPropertiesView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.buttonMoreSettings, NSLayoutAttribute.Bottom, 1f, 10f), + NSLayoutConstraint.Create (this.bindingPropertiesView, NSLayoutAttribute.Left, NSLayoutRelation.Equal, bindingTypeLabel, NSLayoutAttribute.Left, 1f, 0f), + NSLayoutConstraint.Create (this.bindingPropertiesView, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.flagsPropertiesView, NSLayoutAttribute.Left, 1f, -8f), + bindingPropertiesViewHeightConstraint, + NSLayoutConstraint.Create (this.bindingPropertiesView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, 0f), + + NSLayoutConstraint.Create (this.flagsPropertiesView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.bindingPropertiesView, NSLayoutAttribute.Top, 1f, 0f), + NSLayoutConstraint.Create (this.flagsPropertiesView, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.pathSelectorControl, NSLayoutAttribute.Right, 1f, 0f), + NSLayoutConstraint.Create (this.flagsPropertiesView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.pathSelectorControl, NSLayoutAttribute.Width, 1f, 0f), + NSLayoutConstraint.Create (this.flagsPropertiesView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this.bindingPropertiesView, NSLayoutAttribute.Height, 1f, 0f), + + NSLayoutConstraint.Create (this.buttonDone, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.mainContainer, NSLayoutAttribute.Bottom, 1f, -44f), + NSLayoutConstraint.Create (this.buttonDone, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.pathSelectorControl, NSLayoutAttribute.Right, 1f, 0f), + NSLayoutConstraint.Create (this.buttonDone, NSLayoutAttribute.Width, NSLayoutRelation.GreaterThanOrEqual, 1f, 80f), + + NSLayoutConstraint.Create (this.buttonCancel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.buttonDone, NSLayoutAttribute.Top, 1f, 0f), + NSLayoutConstraint.Create (this.buttonCancel, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.buttonDone, NSLayoutAttribute.Left, 1f, -10f), + NSLayoutConstraint.Create (this.buttonCancel, NSLayoutAttribute.Width, NSLayoutRelation.GreaterThanOrEqual, 1f, 80f), + }); + + // put the MainContainer inside this panel's ContentView + ContentView.AddSubview (this.mainContainer); + + ContentView.AddConstraints (new[] { + NSLayoutConstraint.Create (this.mainContainer, NSLayoutAttribute.Top, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Top, 1f, 0f), + NSLayoutConstraint.Create (this.mainContainer, NSLayoutAttribute.Left, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Left, 1f, 0f), + NSLayoutConstraint.Create (this.mainContainer, NSLayoutAttribute.Height, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Height, 1f, 0f), + NSLayoutConstraint.Create (this.mainContainer, NSLayoutAttribute.Width, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Width, 1f, 0f), + + }); + + Title = ViewModel.PropertyDisplay; + this.buttonDone.Title = Properties.Resources.CreateBindingTitle; + this.buttonDone.Enabled = ViewModel.CanCreateBinding; + + ViewModel.BindingSources.Task.ContinueWith (t => { + foreach (BindingSource item in ViewModel.BindingSources.Value) { + this.bindingTypePopup.Menu.AddItem (new NSMenuItem (item.Name) { + RepresentedObject = new NSObjectFacade (item) + }); + } + }, TaskScheduler.FromCurrentSynchronizationContext ()); + + this.bindingTypePopup.Activated += (o, e) => { + if (this.bindingTypePopup.Menu.HighlightedItem.RepresentedObject is NSObjectFacade facade) { + ViewModel.SelectedBindingSource = (BindingSource)facade.Target; } }; - this.ValueConverterPopup.Activated += (o, e) => { - if (this.ValueConverterPopup.Menu.HighlightedItem.RepresentedObject is NSObjectFacade facade) { - this.viewModel.SelectedValueConverter = (Resource)facade.Target; + this.valueConverterPopup.Activated += (o, e) => { + if (this.valueConverterPopup.Menu.HighlightedItem.RepresentedObject is NSObjectFacade facade) { + ViewModel.SelectedValueConverter = (Resource)facade.Target; } }; RepopulateValueConverterPopup (); - this.AddConverterButton.Activated += (sender, e) => { - this.viewModel.SelectedValueConverter = CreateBindingViewModel.AddValueConverter; - }; - - var typeHeader = new HeaderView { + this.typeHeader = new HeaderView { Title = Properties.Resources.Type, }; - this.AncestorTypeBox.AddSubview (typeHeader); + this.ancestorTypeBox.AddSubview (this.typeHeader); - this.AncestorTypeBox.AddConstraints (new[] { - NSLayoutConstraint.Create (typeHeader, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Top, 1f, 0f), - NSLayoutConstraint.Create (typeHeader, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Left, 1f, 0f), - NSLayoutConstraint.Create (typeHeader, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Width, 1f, 0f), - NSLayoutConstraint.Create (typeHeader, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 40), + this.ancestorTypeBox.AddConstraints (new[] { + NSLayoutConstraint.Create (this.typeHeader, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Top, 1f, 0f), + NSLayoutConstraint.Create (this.typeHeader, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Left, 1f, 0f), + NSLayoutConstraint.Create (this.typeHeader, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, 0f), + NSLayoutConstraint.Create (this.typeHeader, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, HeaderHeight), }); - var typeSelectorControl = new TypeSelectorControl { + this.typeSelectorControl = new TypeSelectorControl { + Flush = true, Hidden = true, TranslatesAutoresizingMaskIntoConstraints = false, }; - this.AncestorTypeBox.AddSubview (typeSelectorControl); + this.ancestorTypeBox.AddSubview (this.typeSelectorControl); - this.AncestorTypeBox.AddConstraints (new[] { - NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Top, 1f, 36f), - NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Left, 1f, 0f), - NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Width, 1f, 0f), - NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Height, 1f, -35f) + this.ancestorTypeBox.AddConstraints (new[] { + NSLayoutConstraint.Create (this.typeSelectorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.typeHeader, NSLayoutAttribute.Bottom, 1f, 0f), + NSLayoutConstraint.Create (this.typeSelectorControl, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Left, 1f, 0f), + NSLayoutConstraint.Create (this.typeSelectorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, 0f), + NSLayoutConstraint.Create (this.typeSelectorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Height, 1f, -10f) }); - var resourceSelectorControl = new BindingResourceSelectorControl (this.viewModel) { + var resourceSelectorControl = new BindingResourceSelectorControl (ViewModel) { Hidden = true, }; - this.AncestorTypeBox.AddSubview (resourceSelectorControl); + this.ancestorTypeBox.AddSubview (resourceSelectorControl); - this.AncestorTypeBox.AddConstraints (new[] { - NSLayoutConstraint.Create (resourceSelectorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Top, 1f, 5f), - NSLayoutConstraint.Create (resourceSelectorControl, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Left, 1f, 5f), - NSLayoutConstraint.Create (resourceSelectorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Width, 1f, -10f), - NSLayoutConstraint.Create (resourceSelectorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Height, 1f, -10f) + this.ancestorTypeBox.AddConstraints (new[] { + NSLayoutConstraint.Create (resourceSelectorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Top, 1f, 0f), + NSLayoutConstraint.Create (resourceSelectorControl, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Left, 1f, 0f), + NSLayoutConstraint.Create (resourceSelectorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, 0f), + NSLayoutConstraint.Create (resourceSelectorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Height, 1f, 0f) }); - var objectSelectorControl = new BindingObjectSelectorControl (this.viewModel) { + var objectSelectorControl = new BindingObjectSelectorControl (ViewModel) { Hidden = true, }; - this.AncestorTypeBox.AddSubview (objectSelectorControl); + this.ancestorTypeBox.AddSubview (objectSelectorControl); - this.AncestorTypeBox.AddConstraints (new[] { - NSLayoutConstraint.Create (objectSelectorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Top, 1f, 5f), - NSLayoutConstraint.Create (objectSelectorControl, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Left, 1f, 5f), - NSLayoutConstraint.Create (objectSelectorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Width, 1f, -10f), - NSLayoutConstraint.Create (objectSelectorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Height, 1f, -10f) + this.ancestorTypeBox.AddConstraints (new[] { + NSLayoutConstraint.Create (objectSelectorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Top, 1f, 0f), + NSLayoutConstraint.Create (objectSelectorControl, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Left, 1f, 0f), + NSLayoutConstraint.Create (objectSelectorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, 0f), + NSLayoutConstraint.Create (objectSelectorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Height, 1f, 0f) }); - var longDescription = new UnfocusableTextField { + this.longDescription = new UnfocusableTextField { Alignment = NSTextAlignment.Left, TranslatesAutoresizingMaskIntoConstraints = false, StringValue = string.Empty, }; - this.AncestorTypeBox.AddSubview (longDescription); + this.ancestorTypeBox.AddSubview (this.longDescription); - this.AncestorTypeBox.AddConstraints (new[] { - NSLayoutConstraint.Create (longDescription, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Top, 1f, 10f), - NSLayoutConstraint.Create (longDescription, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Left, 1f, 10f), - NSLayoutConstraint.Create (longDescription, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Width, 1f, -10f), - NSLayoutConstraint.Create (longDescription, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 24), + this.ancestorTypeBox.AddConstraints (new[] { + NSLayoutConstraint.Create (this.longDescription, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Top, 1f, 10f), + NSLayoutConstraint.Create (this.longDescription, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Left, 1f, 10f), + NSLayoutConstraint.Create (this.longDescription, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.ancestorTypeBox, NSLayoutAttribute.Width, 1f, -10f), + NSLayoutConstraint.Create (this.longDescription, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 24), }); - var pathHeader = new HeaderView { - Title = Properties.Resources.Path, - }; + ViewModel.PropertyChanged += OnPropertyChanged; - this.PathBox.AddSubview (pathHeader); + ViewModel.CreateValueConverterRequested += OnCreateValueConverterRequested; - this.PathBox.AddConstraints (new[] { - NSLayoutConstraint.Create (pathHeader, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.PathBox, NSLayoutAttribute.Top, 1f, 0f), - NSLayoutConstraint.Create (pathHeader, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.PathBox, NSLayoutAttribute.Left, 1f, 0f), - NSLayoutConstraint.Create (pathHeader, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.PathBox, NSLayoutAttribute.Width, 1f, 0f), - NSLayoutConstraint.Create (pathHeader, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 40), - }); + this.buttonDone.Activated += OnButtonDoneActivated; - var pathSelectorControl = new BindingPathSelectorControl (this.viewModel); + CreateMorePropertiesEditors (hostResources); + } - this.PathBox.AddSubview (pathSelectorControl); + private void OnButtonDoneActivated (object sender, EventArgs e) + { + if (!string.IsNullOrEmpty (this.pathSelectorControl.CustomPath)) { + ViewModel.Path = this.pathSelectorControl.CustomPath; + } + Delegate.Response = NSModalResponse.OK; + Close (); + } - this.PathBox.AddConstraints (new[] { - NSLayoutConstraint.Create (pathSelectorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.PathBox, NSLayoutAttribute.Top, 1f, 5f), - NSLayoutConstraint.Create (pathSelectorControl, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.PathBox, NSLayoutAttribute.Left, 1f, 5f), - NSLayoutConstraint.Create (pathSelectorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.PathBox, NSLayoutAttribute.Width, 1f, -10f), - NSLayoutConstraint.Create (pathSelectorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this.PathBox, NSLayoutAttribute.Height, 1f, -10f) - }); - this.viewModel.PropertyChanged += (sender, e) => { - if (e.PropertyName == nameof (CreateBindingViewModel.ShowLongDescription)) { - longDescription.Hidden = !this.viewModel.ShowLongDescription; - longDescription.StringValue = this.viewModel.ShowLongDescription ? this.viewModel.SelectedBindingSource.Description : string.Empty; - typeHeader.Hidden = this.viewModel.ShowLongDescription; - } + private void OnButtonMoreSettingsToggled (object sender, EventArgs e) + { + if (sender is NSButton moreButton) { + this.bindingPropertiesView.Hidden = moreButton.State == NSCellStateValue.Off; + this.flagsPropertiesView.Hidden = this.bindingPropertiesView.Hidden; + + this.bindingPropertiesViewHeightConstraint.Constant = this.MoreSettingsViewHeight; + this.ancestorTypeBoxHeightConstraint.Constant = this.bindingPropertiesView.Hidden ? this.heightConstant : this.heightConstant - (MoreSettingsViewHeight + 20); + this.mainContainer.SetFrameSize (new CGSize (this.mainContainer.Frame.Width, this.bindingPropertiesView.Hidden ? this.mainContainer.Frame.Height - MoreSettingsViewHeight : this.mainContainer.Frame.Height + MoreSettingsViewHeight)); + SetFrame (new CGRect (new CGPoint (Frame.X, Frame.Y), new CGSize (Frame.Width, this.mainContainer.Frame.Height + this.titleBarHeight)), false, true); + } + } - if (e.PropertyName == nameof (CreateBindingViewModel.ShowObjectSelector)) { - if (this.viewModel.ShowObjectSelector) { - typeHeader.Title = Properties.Resources.SelectObjectTitle; - } + + private void OnPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof (CreateBindingViewModel.ShowLongDescription)) { + this.longDescription.Hidden = !ViewModel.ShowLongDescription; + this.longDescription.StringValue = ViewModel.ShowLongDescription ? ViewModel.SelectedBindingSource.Description : string.Empty; + this.typeHeader.Hidden = ViewModel.ShowLongDescription; + } + + if (e.PropertyName == nameof (CreateBindingViewModel.ShowObjectSelector)) { + if (ViewModel.ShowObjectSelector) { + this.typeHeader.Title = Properties.Resources.SelectObjectTitle; } + } - if (e.PropertyName == nameof (CreateBindingViewModel.ShowTypeSelector)) { - typeSelectorControl.Hidden = !this.viewModel.ShowTypeSelector; + if (e.PropertyName == nameof (CreateBindingViewModel.ShowTypeSelector)) { + this.typeSelectorControl.Hidden = !ViewModel.ShowTypeSelector; - if (this.viewModel.ShowTypeSelector) { - typeHeader.Title = Properties.Resources.SelectTypeTitle; + if (ViewModel.ShowTypeSelector) { + this.typeHeader.Title = Properties.Resources.SelectTypeTitle; - if (this.viewModel.ShowTypeSelector && this.viewModel.TypeSelector != null) { - typeSelectorControl.ViewModel = this.viewModel.TypeSelector; - } + if (ViewModel.ShowTypeSelector && ViewModel.TypeSelector != null) { + this.typeSelectorControl.ViewModel = ViewModel.TypeSelector; } } + } - if (e.PropertyName == nameof (CreateBindingViewModel.ShowResourceSelector)) { - if (this.viewModel.ShowResourceSelector) { - typeHeader.Title = Properties.Resources.SelectResourceTitle; - } + if (e.PropertyName == nameof (CreateBindingViewModel.ShowResourceSelector)) { + if (ViewModel.ShowResourceSelector) { + this.typeHeader.Title = Properties.Resources.SelectResourceTitle; } + } - if (e.PropertyName == nameof (CreateBindingViewModel.SelectedValueConverter)) { - RepopulateValueConverterPopup (); - } - }; + if (e.PropertyName == nameof (CreateBindingViewModel.SelectedValueConverter)) { + RepopulateValueConverterPopup (); + } - this.viewModel.CreateValueConverterRequested += OnCreateValueConverterRequested; + if (e.PropertyName == nameof (CreateBindingViewModel.PropertyDisplay)) { + Title = ViewModel.PropertyDisplay; + } - this.ButtonDone.Activated += (sender, e) => { - if (pathSelectorControl.CustomPath.Enabled && !string.IsNullOrEmpty (pathSelectorControl.CustomPath.Cell.Title)) { - this.viewModel.Path = pathSelectorControl.CustomPath.Cell.Title; - } + if (e.PropertyName == nameof (CreateBindingViewModel.CanCreateBinding)) { + this.buttonDone.Enabled = ViewModel.CanCreateBinding; + } + } - Close (); - }; - // More Settings - var controlTop = 6; - var identifier = "BindingProperties"; + private void CreateMorePropertiesEditors (IHostResourceProvider hostResources) + { + var controlTop = 8; + int editorHeight; - foreach (PropertyViewModel vm in this.viewModel.BindingProperties) { + foreach (PropertyViewModel vm in ViewModel.BindingProperties) { IEditorView editor = this.editorSelector.GetEditor (hostResources, vm); - NSView nSView = new EditorContainer (hostResources, editor) { - Identifier = identifier, + NSView nSView = new EditorContainer (hostResources, editor, false) { + Identifier = BindingPropertiesIdentifier, Label = vm.Property.Name, TranslatesAutoresizingMaskIntoConstraints = false, ViewModel = vm, }; - this.BindingPropertiesView.AddSubview (nSView); + this.bindingPropertiesView.AddSubview (nSView); - this.BindingPropertiesView.AddConstraints (new[] { - NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.BindingPropertiesView, NSLayoutAttribute.Top, 1f, controlTop), - NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.BindingPropertiesView, NSLayoutAttribute.Left, 1f, 16f), - NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.BindingPropertiesView, NSLayoutAttribute.Width, 1f, -20f), + editorHeight = (int)editor.GetHeight (vm); + this.bindingPropertiesView.AddConstraints (new[] { + NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.bindingPropertiesView, NSLayoutAttribute.Top, 1f, controlTop), + NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.bindingPropertiesView, NSLayoutAttribute.Right, 1f, -9f), + NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.bindingPropertiesView, NSLayoutAttribute.Width, 1f, 0f), + NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, editorHeight), }); - controlTop += PropertyEditorControl.DefaultControlHeight; + controlTop += editorHeight; } var boundsHeight = controlTop; - controlTop = 9; - identifier = "FlagsProperties"; - foreach (PropertyViewModel vm in this.viewModel.FlagsProperties) { + controlTop = 8; + foreach (PropertyViewModel vm in ViewModel.FlagsProperties) { - IEditorView editor = this.editorSelector.GetEditor (hostResources, vm); + IEditorView editor = this.editorSelector.GetEditor (hostResources, vm); - NSView nSView = new EditorContainer (hostResources, editor) { - Identifier = identifier, + NSView nSView = new EditorContainer (hostResources, editor, false) { + Identifier = FlagPropertiesIdentifier, Label = vm.Property.Name, TranslatesAutoresizingMaskIntoConstraints = false, ViewModel = vm, }; - this.FlagsPropertiesView.AddSubview (nSView); + this.flagsPropertiesView.AddSubview (nSView); - this.FlagsPropertiesView.AddConstraints (new[] { - NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.FlagsPropertiesView, NSLayoutAttribute.Top, 1f, controlTop), - NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.FlagsPropertiesView, NSLayoutAttribute.Left, 1f, 16f), - NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.FlagsPropertiesView, NSLayoutAttribute.Width, 1f, -20f), - NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 18f), + editorHeight = (int)editor.GetHeight (vm); + this.flagsPropertiesView.AddConstraints (new[] { + NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.flagsPropertiesView, NSLayoutAttribute.Top, 1f, controlTop), + NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.flagsPropertiesView, NSLayoutAttribute.Left, 1f, 0f), + NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.flagsPropertiesView, NSLayoutAttribute.Width, 1f, 0f), + NSLayoutConstraint.Create (nSView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, editorHeight) }); - controlTop += PropertyEditorControl.DefaultControlHeight; + controlTop += editorHeight; } if (boundsHeight < controlTop) boundsHeight = controlTop; - this.MoreSettingsViewHeight = boundsHeight + 8; + MoreSettingsViewHeight = boundsHeight + 8; } private void RepopulateValueConverterPopup () { - this.ValueConverterPopup.RemoveAllItems (); - foreach (Resource item in this.viewModel.ValueConverters.Value) { - this.ValueConverterPopup.Menu.AddItem (new NSMenuItem (item.Name) { + this.valueConverterPopup.RemoveAllItems (); + foreach (Resource item in ViewModel.ValueConverters.Value) { + this.valueConverterPopup.Menu.AddItem (new NSMenuItem (item.Name) { RepresentedObject = new NSObjectFacade (item) }); } @@ -254,12 +547,15 @@ namespace Xamarin.PropertyEditing.Mac private void OnCreateValueConverterRequested (object sender, CreateValueConverterEventArgs e) { - ITypeInfo valueConverter = this.viewModel.TargetPlatform.EditorProvider.KnownTypes[typeof (CommonValueConverter)]; + ITypeInfo valueConverter = ViewModel.TargetPlatform.EditorProvider.KnownTypes[typeof (CommonValueConverter)]; - var typesTask = this.viewModel.TargetPlatform.EditorProvider.GetAssignableTypesAsync (valueConverter, childTypes: false) + var typesTask = ViewModel.TargetPlatform.EditorProvider.GetAssignableTypesAsync (valueConverter, childTypes: false) .ContinueWith (t => t.Result.GetTypeTree (), TaskScheduler.Default); - var createValueConverterWindow = new CreateValueConverterWindow (this.viewModel, new AsyncValue<IReadOnlyDictionary<IAssemblyInfo, ILookup<string, ITypeInfo>>> (typesTask)); + var createValueConverterWindow = new CreateValueConverterWindow (ViewModel, new AsyncValue<IReadOnlyDictionary<IAssemblyInfo, ILookup<string, ITypeInfo>>> (typesTask)) { + Appearance = EffectiveAppearance, + }; + var result = (NSModalResponse)(int)NSApplication.SharedApplication.RunModalForWindow (createValueConverterWindow); if (result == NSModalResponse.OK) { if (createValueConverterWindow.ViewModel.SelectedType != null) { diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingObjectSelectorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingObjectSelectorControl.cs index 9022c37..8e82477 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingObjectSelectorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingObjectSelectorControl.cs @@ -6,206 +6,73 @@ using Xamarin.PropertyEditing.ViewModels; namespace Xamarin.PropertyEditing.Mac { - internal class BindingObjectSelectorControl : NSView + internal class BindingObjectSelectorControl + : NotifyingView<CreateBindingViewModel> { - internal class ObjectOutlineView : NSOutlineView - { - private IReadOnlyList<ObjectTreeElement> viewModel; - public IReadOnlyList<ObjectTreeElement> ViewModel { - get => this.viewModel; - set { - if (this.viewModel != value) { - this.viewModel = value; - var dataSource = new ObjectOutlineViewDataSource (this.viewModel); - Delegate = new ObjectOutlineViewDelegate (dataSource); - DataSource = dataSource; - } - - if (this.viewModel != null) { - ReloadData (); - - ExpandItem (null, true); - } - } - } + private ObjectOutlineView objectOutlineView; - public ObjectOutlineView () - { - Initialize (); - } + private const string ObjectSelectorColId = "ObjectSelectorColumn"; - // Called when created from unmanaged code - public ObjectOutlineView (IntPtr handle) : base (handle) - { - Initialize (); - } + internal BindingObjectSelectorControl (CreateBindingViewModel viewModel) + { + if (viewModel == null) + throw new ArgumentNullException (nameof (viewModel)); - // Called when created directly from a XIB file - [Export ("initWithCoder:")] - public ObjectOutlineView (NSCoder coder) : base (coder) - { - Initialize (); - } + ViewModel = viewModel; - [Export ("validateProposedFirstResponder:forEvent:")] - public bool ValidateProposedFirstResponder (NSResponder responder, NSEvent forEvent) - { - return true; - } + this.objectOutlineView = new ObjectOutlineView (); + TranslatesAutoresizingMaskIntoConstraints = false; - public void Initialize () - { - AutoresizingMask = NSViewResizingMask.WidthSizable; - HeaderView = null; - TranslatesAutoresizingMaskIntoConstraints = false; - } - } + this.objectOutlineView.Activated += OnObjectOutlineViewSelected; - internal class ObjectOutlineViewDelegate : NSOutlineViewDelegate - { - private ObjectOutlineViewDataSource dataSource; + var resourceColumn = new NSTableColumn (ObjectSelectorColId); + this.objectOutlineView.AddColumn (resourceColumn); - public ObjectOutlineViewDelegate (ObjectOutlineViewDataSource dataSource) - { - this.dataSource = dataSource; - } + // Set OutlineTableColumn or the arrows showing children/expansion will not be drawn + this.objectOutlineView.OutlineTableColumn = resourceColumn; - public override nfloat GetRowHeight (NSOutlineView outlineView, NSObject item) - { - return PropertyEditorControl.DefaultControlHeight; - } + // create a table view and a scroll view + var outlineViewContainer = new NSScrollView { + TranslatesAutoresizingMaskIntoConstraints = false, + }; - public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) - { - var labelContainer = (UnfocusableTextField)outlineView.MakeView ("type", this); - if (labelContainer == null) { - labelContainer = new UnfocusableTextField { - Identifier = "type", - }; - } - var target = (item as NSObjectFacade).Target; - - switch (target) { - case KeyValuePair<string, SimpleCollectionView> kvp: - labelContainer.StringValue = kvp.Key; - break; - case TypeInfo info: - labelContainer.StringValue = info.Name; - break; - default: - labelContainer.StringValue = "Type Not Supported"; - break; - } + // add the panel to the window + outlineViewContainer.DocumentView = this.objectOutlineView; + AddSubview (outlineViewContainer); - return labelContainer; - } + AddConstraints (new[] { + NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 28f), + NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1f, 0f), + NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this, NSLayoutAttribute.CenterX, 1, 0), + NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal,this, NSLayoutAttribute.Bottom, 1f, 0f), + }); - public override bool ShouldSelectItem (NSOutlineView outlineView, NSObject item) - { - var target = (item as NSObjectFacade).Target; - switch (target) { - case KeyValuePair<string, SimpleCollectionView> kvp: - return false; - case TypeInfo info: - return true; - - default: - return false; - } - } + viewModel.PropertyChanged += OnPropertyChanged; } - internal class ObjectOutlineViewDataSource : NSOutlineViewDataSource + public override void OnPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e) { - public IReadOnlyList<ObjectTreeElement> ViewModel { get; } - - internal ObjectOutlineViewDataSource (IReadOnlyList<ObjectTreeElement> viewModel) - { - if (viewModel == null) - throw new ArgumentNullException (nameof (viewModel)); - - ViewModel = viewModel; - } - - public override nint GetChildrenCount (NSOutlineView outlineView, NSObject item) - { - var childCount = 0; - if (item == null) { - childCount = this.ViewModel != null ? this.ViewModel.Count () : 0; - } else { - var target = (item as NSObjectFacade).Target; - switch (target) { - case KeyValuePair<string, SimpleCollectionView> kvp: - childCount = kvp.Value.Count; - break; - case TypeInfo info: - childCount = 0; - break; - default: - childCount = 0; - break; - } - } + if (e.PropertyName == nameof (CreateBindingViewModel.ShowObjectSelector)) { + Hidden = !ViewModel.ShowObjectSelector; - return childCount; + if (ViewModel.ShowObjectSelector && ViewModel.ObjectElementRoots != null) { + this.objectOutlineView.ItemsSource = ViewModel.ObjectElementRoots.Value; + }; } + } - public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, NSObject item) - { - object element; - - if (item == null) { - element = this.ViewModel.ElementAt ((int)childIndex); - } else { - var target = (item as NSObjectFacade).Target; - switch (target) { - case KeyValuePair<string, SimpleCollectionView> kvp: - element = kvp.Value[(int)childIndex]; - break; - case TypeInfo info: - element = info; - break; - default: - return null; + private void OnObjectOutlineViewSelected (object sender, EventArgs e) + { + if (sender is ObjectOutlineView rov) { + if (rov.SelectedRow != -1) { + if (rov.ItemAtRow (rov.SelectedRow) is NSObjectFacade item) { + if (item.Target is Resource resource) { + ViewModel.SelectedResource = resource; + } } } - - return new NSObjectFacade (element); - } - - public override bool ItemExpandable (NSOutlineView outlineView, NSObject item) - { - var target = (item as NSObjectFacade).Target; - switch (target) { - case KeyValuePair<string, SimpleCollectionView> kvp: - return kvp.Value.Count > 0; - case TypeInfo info: - return false; - default: - return false; - } } } - internal ObjectOutlineView objectOutlineView; - - internal BindingObjectSelectorControl (CreateBindingViewModel viewModel) - { - if (viewModel == null) - throw new ArgumentNullException (nameof (viewModel)); - - this.objectOutlineView = new ObjectOutlineView (); - TranslatesAutoresizingMaskIntoConstraints = false; - - viewModel.PropertyChanged += (sender, e) => { - if (e.PropertyName == nameof (CreateBindingViewModel.ShowObjectSelector)) { - Hidden = !viewModel.ShowObjectSelector; - - if (viewModel.ShowObjectSelector && viewModel.ObjectElementRoots != null) { - this.objectOutlineView.ViewModel = viewModel.ObjectElementRoots.Value; - }; - } - }; - } } } diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingPathSelectorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingPathSelectorControl.cs index 0123d7b..2d84be3 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingPathSelectorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingPathSelectorControl.cs @@ -1,236 +1,66 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; using AppKit; +using CoreGraphics; using Foundation; using Xamarin.PropertyEditing.ViewModels; namespace Xamarin.PropertyEditing.Mac { - internal class PathOutlineView : NSOutlineView + internal class BindingPathSelectorControl + : NotifyingView<CreateBindingViewModel> { - private IReadOnlyCollection<object> viewModel; - private PropertyTreeRoot propertyTreeRoot; - - private IReadOnlyCollection<object> ViewModel - { - get => this.viewModel; - set { - if (this.viewModel != value) { - this.viewModel = value; - - var dataSource = new PathOutlineViewDataSource (this.viewModel, this.targetName); - Delegate = new PathOutlineViewDelegate (dataSource); - DataSource = dataSource; - - ReloadData (); - - ExpandItem (ItemAtRow (0)); - } - } - } + private readonly PathOutlineView pathOutlineView; + internal const string PathSelectorColumnColId = "PathSelectorColumn"; - private string targetName { get; set; } - public PropertyTreeRoot PropertyTreeRoot - { - get { return this.propertyTreeRoot; } - internal set { - if (this.propertyTreeRoot != value) { - this.propertyTreeRoot = value; - if (this.propertyTreeRoot != null) { - targetName = this.propertyTreeRoot.TargetType.Name; - ViewModel = this.propertyTreeRoot.Children; - } else { - targetName = string.Empty; - ViewModel = null; - } - } - } + public string CustomPath { + get { + return this.customPathControl.StringValue; + } } + private NSTextField customPathControl { get; } - public PathOutlineView () - { - Initialize (); - } + private const float HorizontalCustomOffSet = 30.5f; - // Called when created from unmanaged code - public PathOutlineView (IntPtr handle) : base (handle) - { - Initialize (); - } + private HeaderView pathHeader; + private NSView pathBox; - // Called when created directly from a XIB file - [Export ("initWithCoder:")] - public PathOutlineView (NSCoder coder) : base (coder) + public BindingPathSelectorControl (CreateBindingViewModel viewModel) { - Initialize (); - } + if (viewModel == null) + throw new ArgumentNullException (nameof (viewModel)); - [Export ("validateProposedFirstResponder:forEvent:")] - public bool ValidateProposedFirstResponder (NSResponder responder, NSEvent forEvent) - { - return true; - } + ViewModel = viewModel; - public void Initialize () - { - AutoresizingMask = NSViewResizingMask.WidthSizable; - HeaderView = null; TranslatesAutoresizingMaskIntoConstraints = false; - } - } - - internal class PathOutlineViewDelegate : NSOutlineViewDelegate - { - private readonly PathOutlineViewDataSource dataSource; - - public PathOutlineViewDelegate (PathOutlineViewDataSource dataSource) - { - this.dataSource = dataSource; - } - - public override nfloat GetRowHeight (NSOutlineView outlineView, NSObject item) - { - return PropertyEditorControl.DefaultControlHeight; - } - - public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) - { - var labelContainer = (UnfocusableTextField)outlineView.MakeView ("path", this); - if (labelContainer == null) { - labelContainer = new UnfocusableTextField { - Identifier = "path", - }; - } - var target = (item as NSObjectFacade).Target; - - switch (target) { - case PropertyTreeElement propertyTreeElement: - labelContainer.StringValue = string.Format("{0}: ({1})", propertyTreeElement.Property.Name, propertyTreeElement.Property.RealType.Name); - break; - - case string targetName: - labelContainer.StringValue = targetName; - break; - - default: - labelContainer.StringValue = "Type Not Supported"; - break; - } - - return labelContainer; - } - - public override bool ShouldSelectItem (NSOutlineView outlineView, NSObject item) - { - if (item is NSObjectFacade facade) { - switch (facade.Target) { - case PropertyTreeElement propertyTreeElement: - var propertyTreeResult = propertyTreeElement.Children.Task.Result; - return propertyTreeResult.Count == 0; - - default: - return false; - } - } else { - return false; - } - } - } - - internal class PathOutlineViewDataSource : NSOutlineViewDataSource - { - private readonly IReadOnlyCollection<object> viewModel; - private string targetName; - - internal PathOutlineViewDataSource (IReadOnlyCollection<object> viewModel, string targetName) - { - this.viewModel = viewModel; - this.targetName = targetName; - } - public override nint GetChildrenCount (NSOutlineView outlineView, NSObject item) - { - nint childCount; - if (item == null) { - childCount = this.viewModel != null ? this.viewModel.Count () + 1 : 0; - } else { - var target = (item as NSObjectFacade).Target; - switch (target) { - case PropertyTreeElement propertyTreeElement: - IReadOnlyCollection<PropertyTreeElement> propertyTrees = propertyTreeElement.Children.Task.Result; - childCount = propertyTrees.Count; - break; - - case string targetName: - childCount = this.viewModel.Count (); - break; - - default: - childCount = 0; - break; - } - } - - return childCount; - } - - public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, NSObject item) - { - if (childIndex == 0 && item == null) { - return new NSObjectFacade (targetName); - } - - if (item is NSObjectFacade objectFacade) { - var target = objectFacade.Target; - switch (target) { - case PropertyTreeElement propertyTreeElement: - IReadOnlyCollection<PropertyTreeElement> propertyTrees = propertyTreeElement.Children.Task.Result; - return new NSObjectFacade (propertyTrees.ElementAt ((int)childIndex)); - - case string targetName: - return new NSObjectFacade (this.viewModel.ElementAt ((int)childIndex)); - - default: - return null; - } - - } - return null; - } + this.pathBox = new NSView { + TranslatesAutoresizingMaskIntoConstraints = false, + WantsLayer = true, + + // Layer out of alphabetical order so that WantsLayer creates the layer first + Layer = { + CornerRadius = 1.0f, + BorderColor = new CGColor (.5f, .5f, .5f, 1.0f), + BorderWidth = 1, + }, + }; - public override bool ItemExpandable (NSOutlineView outlineView, NSObject item) - { - if (item is NSObjectFacade objectFacade) { - var target = objectFacade.Target; - switch (target) { - case PropertyTreeElement propertyTreeElement: - IReadOnlyCollection<PropertyTreeElement> propertyTrees = propertyTreeElement.Children.Task.Result; - return propertyTrees.Count > 0; - - case string targetName: - return true; - - default: - return false; - } - } + AddSubview (this.pathBox); - return false; - } - } + this.pathHeader = new HeaderView { + Title = Properties.Resources.Path, + }; + this.pathHeader.HorizonalTitleOffset = -HorizontalCustomOffSet; - internal class BindingPathSelectorControl : NSView - { - private PathOutlineView pathOutlineView; - internal const string PathSelectorColumnColId = "PathSelectorColumn"; - private const float spacing = 10f; - private NSTextField customPath; - public NSTextField CustomPath { get; private set; } + this.pathBox.AddSubview (this.pathHeader); - public BindingPathSelectorControl (CreateBindingViewModel viewModel) - { - TranslatesAutoresizingMaskIntoConstraints = false; + this.pathBox.AddConstraints (new[] { + NSLayoutConstraint.Create (this.pathHeader, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.Top, 1f, 0f), + NSLayoutConstraint.Create (this.pathHeader, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.Left, 1f, 0f), + NSLayoutConstraint.Create (this.pathHeader, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.Width, 1f, 0f), + NSLayoutConstraint.Create (this.pathHeader, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, BindingEditorWindow.HeaderHeight), + }); var customCheckBox = new NSButton { ControlSize = NSControlSize.Small, @@ -241,26 +71,25 @@ namespace Xamarin.PropertyEditing.Mac customCheckBox.SetButtonType (NSButtonType.Switch); - AddSubview (customCheckBox); - AddConstraints (new[] { - NSLayoutConstraint.Create (customCheckBox, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 8f), - NSLayoutConstraint.Create (customCheckBox, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this, NSLayoutAttribute.Right, 1f, -90f), + this.pathHeader.AddSubview (customCheckBox); + this.pathHeader.AddConstraints (new[] { + NSLayoutConstraint.Create (customCheckBox, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this.pathHeader, NSLayoutAttribute.CenterX, 1, HorizontalCustomOffSet), + NSLayoutConstraint.Create (customCheckBox, NSLayoutAttribute.CenterY, NSLayoutRelation.Equal, this.pathHeader, NSLayoutAttribute.CenterY, 1, 0f), }); - this.customPath = new NSTextField { - ControlSize = NSControlSize.Mini, + this.customPathControl = new NSTextField { + ControlSize = NSControlSize.Regular, Enabled = false, - Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize), TranslatesAutoresizingMaskIntoConstraints = false, }; - var customPathHeightConstraint = NSLayoutConstraint.Create (this.customPath, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 0); + var customPathHeightConstraint = NSLayoutConstraint.Create (this.customPathControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 0); - AddSubview (this.customPath); - AddConstraints (new[] { - NSLayoutConstraint.Create (this.customPath, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 45f), - NSLayoutConstraint.Create (this.customPath, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1f, -10f), - NSLayoutConstraint.Create (this.customPath, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this, NSLayoutAttribute.CenterX, 1, 0), + this.pathBox.AddSubview (this.customPathControl); + this.pathBox.AddConstraints (new[] { + NSLayoutConstraint.Create (this.customPathControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.Top, 1f, 28f), + NSLayoutConstraint.Create (this.customPathControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.Width, 1f, 0f), + NSLayoutConstraint.Create (this.customPathControl, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.CenterX, 1, 0), customPathHeightConstraint, }); @@ -269,39 +98,20 @@ namespace Xamarin.PropertyEditing.Mac TranslatesAutoresizingMaskIntoConstraints = false, }; - var outlineViewContainerTopConstraint = NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.customPath, NSLayoutAttribute.Bottom, 1f, 0f); customCheckBox.Activated += (sender, e) => { - this.customPath.Enabled = customCheckBox.State == NSCellStateValue.On; - customPathHeightConstraint.Constant = this.customPath.Enabled ? PropertyEditorControl.DefaultControlHeight : 0; - outlineViewContainerTopConstraint.Constant = this.customPath.Enabled ? 10 : 0; - SetCustomPath (viewModel); + this.customPathControl.Enabled = customCheckBox.State == NSCellStateValue.On; + customPathHeightConstraint.Constant = this.customPathControl.Enabled ? 22 : 0; }; - this.customPath.Changed += (sender, e) => { - viewModel.Path = this.customPath.StringValue; + this.customPathControl.Changed += (sender, e) => { + viewModel.Path = this.customPathControl.StringValue; }; this.pathOutlineView = new PathOutlineView { }; - this.pathOutlineView.Activated += (sender, e) => { - if (sender is PathOutlineView pov) { - if (pov.SelectedRow != -1) { - if (pov.ItemAtRow (pov.SelectedRow) is NSObjectFacade facade) { - switch (facade.Target) { - case PropertyTreeElement propertyTreeElement: - viewModel.SelectedPropertyElement = propertyTreeElement; - break; - - default: - break; - } - SetCustomPath (viewModel); - } - } - } - }; + this.pathOutlineView.Activated += OnPathOutlineViewSelected; var pathColumn = new NSTableColumn (PathSelectorColumnColId); this.pathOutlineView.AddColumn (pathColumn); @@ -311,27 +121,58 @@ namespace Xamarin.PropertyEditing.Mac // add the panel to the window outlineViewContainer.DocumentView = this.pathOutlineView; - AddSubview (outlineViewContainer); + + this.pathBox.AddSubview (outlineViewContainer); + + this.pathBox.AddConstraints (new[] { + NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.customPathControl, NSLayoutAttribute.Bottom, 1f, 0f), + NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.Width, 1f, 0f), + NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.CenterX, 1, 0), + NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this.pathBox, NSLayoutAttribute.Bottom, 1f, 0f), + }); AddConstraints (new[] { - outlineViewContainerTopConstraint, - NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1f, -10f), - NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this, NSLayoutAttribute.CenterX, 1, 0), - NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal,this, NSLayoutAttribute.Bottom, 1f, -5f), + NSLayoutConstraint.Create (this.pathBox, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 0f), + NSLayoutConstraint.Create (this.pathBox, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this, NSLayoutAttribute.Left, 1f, 0f), + NSLayoutConstraint.Create (this.pathBox, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this, NSLayoutAttribute.Height, 1f, 0f), + NSLayoutConstraint.Create (this.pathBox, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1f, 0f), }); - viewModel.PropertyChanged += async (sender, e) => { - if (viewModel.PropertyRoot != null) { - this.pathOutlineView.PropertyTreeRoot = await viewModel.PropertyRoot.Task; + viewModel.PropertyChanged += OnPropertyChanged; + } + + public override async void OnPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof (CreateBindingViewModel.PropertyRoot)) { + if (ViewModel.PropertyRoot != null) { + this.pathOutlineView.PropertyTreeRoot = await ViewModel.PropertyRoot.Task; } else { this.pathOutlineView.PropertyTreeRoot = null; } - }; + } + + if (e.PropertyName == nameof (CreateBindingViewModel.Path)) { + this.customPathControl.StringValue = ViewModel.Path ?? string.Empty; + } } - private void SetCustomPath (CreateBindingViewModel viewModel) + private void OnPathOutlineViewSelected (object sender, EventArgs e) { - this.customPath.StringValue = this.customPath.Enabled ? viewModel.Path ?? string.Empty : string.Empty; + if (sender is PathOutlineView pov) { + if (pov.SelectedRow != -1) { + if (pov.ItemAtRow (pov.SelectedRow) is NSObjectFacade facade) { + switch (facade.Target) { + case PropertyTreeElement propertyTreeElement: + ViewModel.SelectedPropertyElement = propertyTreeElement; + break; + + default: + break; + } + } + } + } } + } } diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceOutlineView.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceOutlineView.cs new file mode 100644 index 0000000..025fcba --- /dev/null +++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceOutlineView.cs @@ -0,0 +1,139 @@ +using System; +using System.Linq; +using AppKit; +using Foundation; + +namespace Xamarin.PropertyEditing.Mac +{ + internal class BindingResourceOutlineView : BaseSelectorOutlineView + { + private ILookup<ResourceSource, Resource> itemsSource; + public ILookup<ResourceSource, Resource> ItemsSource + { + get => this.itemsSource; + set + { + if (this.itemsSource != value) { + this.itemsSource = value; + + DataSource = new BindingResourceOutlineViewDataSource (this.itemsSource); + Delegate = new BindingResourceOutlineViewDelegate (); + } + + ReloadData (); + + ExpandItem (null, true); + } + } + } + + internal class BindingResourceOutlineViewDelegate : NSOutlineViewDelegate + { + private const string ResourceIdentifier = "resource"; + + public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) + { + var labelContainer = (UnfocusableTextField)outlineView.MakeView (ResourceIdentifier, this); + if (labelContainer == null) { + labelContainer = new UnfocusableTextField { + Identifier = ResourceIdentifier, + }; + } + var target = (item as NSObjectFacade).Target; + + switch (target) { + case IGrouping<ResourceSource, Resource> kvp: + labelContainer.StringValue = kvp.Key.Name; + break; + case Resource resource: + labelContainer.StringValue = resource.Name; + break; + default: + labelContainer.StringValue = Properties.Resources.ResourceNotSupported; + break; + } + + return labelContainer; + } + + public override bool ShouldSelectItem (NSOutlineView outlineView, NSObject item) + { + var target = (item as NSObjectFacade).Target; + switch (target) { + case IGrouping<ResourceSource, Resource> kvp: + return false; + case Resource resource: + return true; + + default: + return false; + } + } + } + + internal class BindingResourceOutlineViewDataSource : NSOutlineViewDataSource + { + public ILookup<ResourceSource, Resource> ItemsSource { get; } + + internal BindingResourceOutlineViewDataSource (ILookup<ResourceSource, Resource> itemsSource) + { + if (itemsSource == null) + throw new ArgumentNullException (nameof (itemsSource)); + + ItemsSource = itemsSource; + } + + public override nint GetChildrenCount (NSOutlineView outlineView, NSObject item) + { + if (item == null) { + return ItemsSource != null ? ItemsSource.Count : 0; + } else { + var target = (item as NSObjectFacade).Target; + switch (target) { + case IGrouping<ResourceSource, Resource> kvp: + return kvp.Count (); + case Resource resource: + return 0; + default: + return 0; + } + } + } + + public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, NSObject item) + { + object element; + + if (item == null) { + element = ItemsSource.ElementAt ((int)childIndex); + } else { + var target = (item as NSObjectFacade).Target; + switch (target) { + case IGrouping<ResourceSource, Resource> kvp: + element = kvp.ElementAt ((int)childIndex); + break; + case Resource resource: + element = resource; + break; + default: + return null; + } + } + + return new NSObjectFacade (element); + } + + public override bool ItemExpandable (NSOutlineView outlineView, NSObject item) + { + var target = (item as NSObjectFacade).Target; + switch (target) { + case IGrouping<ResourceSource, Resource> kvp: + return kvp.Any (); + case Resource resource: + return false; + default: + return false; + } + } + } +} diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceSelectorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceSelectorControl.cs index afcf746..54a5e4b 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceSelectorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceSelectorControl.cs @@ -7,209 +7,24 @@ using Xamarin.PropertyEditing.ViewModels; namespace Xamarin.PropertyEditing.Mac { - internal class BindingResourceSelectorControl : NSView + internal class BindingResourceSelectorControl + : NotifyingView<CreateBindingViewModel> { - internal class ResourceOutlineView : NSOutlineView - { - private ILookup<ResourceSource, Resource> viewModel; - public ILookup<ResourceSource, Resource> ViewModel { - get => this.viewModel; - set { - if (this.viewModel != value) { - this.viewModel = value; - var dataSource = new ResourceOutlineViewDataSource (this.viewModel); - Delegate = new ResourceOutlineViewDelegate (dataSource); - DataSource = dataSource; - } - - if (this.viewModel != null) { - ReloadData (); - - ExpandItem (null, true); - } - } - } + private const string ResourceSelectorColId = "ResourceSelectorColumn"; - public ResourceOutlineView () - { - Initialize (); - } - - // Called when created from unmanaged code - public ResourceOutlineView (IntPtr handle) : base (handle) - { - Initialize (); - } - - // Called when created directly from a XIB file - [Export ("initWithCoder:")] - public ResourceOutlineView (NSCoder coder) : base (coder) - { - Initialize (); - } - - [Export ("validateProposedFirstResponder:forEvent:")] - public bool ValidateProposedFirstResponder (NSResponder responder, NSEvent forEvent) - { - return true; - } - - public void Initialize () - { - AutoresizingMask = NSViewResizingMask.WidthSizable; - HeaderView = null; - TranslatesAutoresizingMaskIntoConstraints = false; - } - } - - internal class ResourceOutlineViewDelegate : NSOutlineViewDelegate - { - private readonly ResourceOutlineViewDataSource dataSource; + public BindingResourceOutlineView resourceOutlineView; - public ResourceOutlineViewDelegate (ResourceOutlineViewDataSource datasource) - { - this.dataSource = datasource; - } - - public override nfloat GetRowHeight (NSOutlineView outlineView, NSObject item) - { - return PropertyEditorControl.DefaultControlHeight; - } - - public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) - { - var labelContainer = (UnfocusableTextField)outlineView.MakeView ("resource", this); - if (labelContainer == null) { - labelContainer = new UnfocusableTextField { - Identifier = "resource", - }; - } - var target = (item as NSObjectFacade).Target; - - switch (target) { - case IGrouping<ResourceSource, Resource> kvp: - labelContainer.StringValue = kvp.Key.Name; - break; - case Resource resource: - labelContainer.StringValue = resource.Name; - break; - default: - labelContainer.StringValue = "Resource Not Supported"; - break; - } - - return labelContainer; - } - - public override bool ShouldSelectItem (NSOutlineView outlineView, NSObject item) - { - var target = (item as NSObjectFacade).Target; - switch (target) { - case IGrouping<ResourceSource, Resource> kvp: - return false; - case Resource resource: - return true; - - default: - return false; - } - } - } - - internal class ResourceOutlineViewDataSource : NSOutlineViewDataSource + internal BindingResourceSelectorControl (CreateBindingViewModel viewModel) { - public ILookup<ResourceSource, Resource> ViewModel { get; } + if (viewModel == null) + throw new ArgumentNullException (nameof (viewModel)); - internal ResourceOutlineViewDataSource (ILookup<ResourceSource, Resource> viewModel) - { - if (viewModel == null) - throw new ArgumentNullException (nameof (viewModel)); - - ViewModel = viewModel; - } + ViewModel = viewModel; - public override nint GetChildrenCount (NSOutlineView outlineView, NSObject item) - { - var childCount = 0; - if (item == null) { - childCount = this.ViewModel != null ? this.ViewModel.Count () : 0; - } else { - var target = (item as NSObjectFacade).Target; - switch (target) { - case IGrouping < ResourceSource, Resource> kvp: - childCount = kvp.Count (); - break; - case Resource resource: - childCount = 0; - break; - default: - childCount = 0; - break; - } - } - - return childCount; - } - - public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, NSObject item) - { - object element; - - if (item == null) { - element = this.ViewModel.ElementAt ((int)childIndex); - } else { - var target = (item as NSObjectFacade).Target; - switch (target) { - case IGrouping<ResourceSource, Resource> kvp: - element = kvp.ElementAt ((int)childIndex); - break; - case Resource resource: - element = resource; - break; - default: - return null; - } - } - - return new NSObjectFacade (element); - } - - public override bool ItemExpandable (NSOutlineView outlineView, NSObject item) - { - var target = (item as NSObjectFacade).Target; - switch (target) { - case IGrouping<ResourceSource, Resource> kvp: - return kvp.Count() > 0; - case Resource resource: - return false; - default: - return false; - } - } - } - - internal const string ResourceSelectorColId = "ResourceSelectorColumn"; - - public ResourceOutlineView resourceOutlineView; - - internal BindingResourceSelectorControl (CreateBindingViewModel viewModel) - { TranslatesAutoresizingMaskIntoConstraints = false; - this.resourceOutlineView = new ResourceOutlineView { - - }; - this.resourceOutlineView.Activated += (sender, e) => { - if (sender is ResourceOutlineView rov) { - if (rov.SelectedRow != -1) { - if (rov.ItemAtRow (rov.SelectedRow) is NSObjectFacade item) { - if (item.Target is Resource resource) { - viewModel.SelectedResource = resource; - } - } - } - } - }; + this.resourceOutlineView = new BindingResourceOutlineView (); + this.resourceOutlineView.Activated += OnResourceOutlineViewSelected; var resourceColumn = new NSTableColumn (ResourceSelectorColId); this.resourceOutlineView.AddColumn (resourceColumn); @@ -227,21 +42,37 @@ namespace Xamarin.PropertyEditing.Mac AddSubview (outlineViewContainer); AddConstraints (new[] { - NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 45f), - NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this, NSLayoutAttribute.Left, 1f, 5f), - NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1f, -10f), - NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Height, NSLayoutRelation.Equal,this, NSLayoutAttribute.Height, 1f, -50f), + NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 28f), + NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1f, 0f), + NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this, NSLayoutAttribute.CenterX, 1, 0), + NSLayoutConstraint.Create (outlineViewContainer, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal,this, NSLayoutAttribute.Bottom, 1f, 0f), }); - viewModel.PropertyChanged += (sender, e) => { - if (e.PropertyName == nameof (CreateBindingViewModel.ShowResourceSelector)) { - Hidden = !viewModel.ShowResourceSelector; + viewModel.PropertyChanged += OnPropertyChanged; + } + + public override void OnPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof (CreateBindingViewModel.ShowResourceSelector)) { + Hidden = !ViewModel.ShowResourceSelector; - if (viewModel.ShowResourceSelector && viewModel.SourceResources != null) { - this.resourceOutlineView.ViewModel = viewModel.SourceResources.Value; - }; + if (ViewModel.ShowResourceSelector && ViewModel.SourceResources != null) { + this.resourceOutlineView.ItemsSource = ViewModel.SourceResources.Value; + }; + } + } + + private void OnResourceOutlineViewSelected (object sender, EventArgs e) + { + if (sender is BindingResourceOutlineView rov) { + if (rov.SelectedRow != -1) { + if (rov.ItemAtRow (rov.SelectedRow) is NSObjectFacade item) { + if (item.Target is Resource resource) { + ViewModel.SelectedResource = resource; + } + } } - }; + } } } } diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingTypeSelectorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingTypeSelectorControl.cs deleted file mode 100644 index bbfebc9..0000000 --- a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingTypeSelectorControl.cs +++ /dev/null @@ -1,311 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using AppKit; -using Foundation; -using Xamarin.PropertyEditing.ViewModels; - -namespace Xamarin.PropertyEditing.Mac -{ - internal class BindingTypeSelectorControl : NSView - { - internal class TypeOutlineView : NSOutlineView - { - private TypeSelectorViewModel viewModel; - public TypeSelectorViewModel ViewModel { - get => this.viewModel; - set { - if (this.viewModel != null) { - this.viewModel.PropertyChanged -= OnPropertyChanged; - } - - if (this.viewModel != value) { - this.viewModel = value; - var dataSource = new TypeOutlineViewDataSource (this.viewModel); - Delegate = new TypeOutlineViewDelegate (dataSource); - DataSource = dataSource; - } - - OnPropertyChanged (this.viewModel, new PropertyChangedEventArgs (null)); - if (this.viewModel != null) { - this.viewModel.PropertyChanged += OnPropertyChanged; - } - } - } - - private void OnPropertyChanged (object sender, PropertyChangedEventArgs e) - { - ReloadData (); - - ExpandItem (null, true); - } - - public TypeOutlineView () - { - Initialize (); - } - - // Called when created from unmanaged code - public TypeOutlineView (IntPtr handle) : base (handle) - { - Initialize (); - } - - // Called when created directly from a XIB file - [Export ("initWithCoder:")] - public TypeOutlineView (NSCoder coder) : base (coder) - { - Initialize (); - } - - [Export ("validateProposedFirstResponder:forEvent:")] - public bool ValidateProposedFirstResponder (NSResponder responder, NSEvent forEvent) - { - return true; - } - - public void Initialize () - { - AutoresizingMask = NSViewResizingMask.WidthSizable; - HeaderView = null; - TranslatesAutoresizingMaskIntoConstraints = false; - } - } - - internal class TypeOutlineViewDelegate : NSOutlineViewDelegate - { - private TypeOutlineViewDataSource dataSource; - - public TypeOutlineViewDelegate (TypeOutlineViewDataSource dataSource) - { - this.dataSource = dataSource; - } - - public override nfloat GetRowHeight (NSOutlineView outlineView, NSObject item) - { - return PropertyEditorControl.DefaultControlHeight; - } - - public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) - { - var labelContainer = (UnfocusableTextField)outlineView.MakeView ("type", this); - if (labelContainer == null) { - labelContainer = new UnfocusableTextField { - Identifier = "type", - }; - } - var target = (item as NSObjectFacade).Target; - - switch (target) { - case KeyValuePair<string, SimpleCollectionView> kvp: - labelContainer.StringValue = kvp.Key; - break; - case TypeInfo info: - labelContainer.StringValue = info.Name; - break; - default: - labelContainer.StringValue = "Type Not Supported"; - break; - } - - return labelContainer; - } - - public override bool ShouldSelectItem (NSOutlineView outlineView, NSObject item) - { - var target = (item as NSObjectFacade).Target; - switch (target) { - case KeyValuePair<string, SimpleCollectionView> kvp: - return false; - case TypeInfo info: - return true; - - default: - return false; - } - } - } - - internal class TypeOutlineViewDataSource : NSOutlineViewDataSource - { - public TypeSelectorViewModel ViewModel { get; } - - internal TypeOutlineViewDataSource (TypeSelectorViewModel viewModel) - { - if (viewModel == null) - throw new ArgumentNullException (nameof (viewModel)); - - ViewModel = viewModel; - } - - public override nint GetChildrenCount (NSOutlineView outlineView, NSObject item) - { - var childCount = 0; - if (item == null) { - childCount = this.ViewModel.Types != null ? this.ViewModel.Types.Count () : 0; - } else { - var target = (item as NSObjectFacade).Target; - switch (target) { - case KeyValuePair<string, SimpleCollectionView> kvp: - childCount = kvp.Value.Count; - break; - case TypeInfo info: - childCount = 0; - break; - default: - childCount = 0; - break; - } - } - - return childCount; - } - - public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, NSObject item) - { - object element; - - if (item == null) { - element = this.ViewModel.Types.ElementAt ((int)childIndex); - } else { - var target = (item as NSObjectFacade).Target; - switch (target) { - case KeyValuePair<string, SimpleCollectionView> kvp: - element = kvp.Value[(int)childIndex]; - break; - case TypeInfo info: - element = info; - break; - default: - return null; - } - } - - return new NSObjectFacade (element); - } - - public override bool ItemExpandable (NSOutlineView outlineView, NSObject item) - { - var target = (item as NSObjectFacade).Target; - switch (target) { - case KeyValuePair<string, SimpleCollectionView> kvp: - return kvp.Value.Count > 0; - case TypeInfo info: - return false; - default: - return false; - } - } - } - internal const string TypeSelectorColId = "TypeSelectorColumn"; - - internal TypeOutlineView typeOutlineView; - private NSButton showAllAssembliesCheckBox; - - public CreateBindingViewModel ViewModel { get; set; } - - public BindingTypeSelectorControl (CreateBindingViewModel viewModel) - { - ViewModel = viewModel; - TranslatesAutoresizingMaskIntoConstraints = false; - - this.typeOutlineView = new TypeOutlineView { - - }; - - this.typeOutlineView.Activated += (sender, e) => { - if (sender is TypeOutlineView tov) { - if (tov.SelectedRow != -1) { - if (tov.ItemAtRow (tov.SelectedRow) is NSObjectFacade item) { - if (item.Target is ITypeInfo typeInfo) { - viewModel.TypeSelector.SelectedType = typeInfo; - } - } - } - } - }; - - var typeColumn = new NSTableColumn (TypeSelectorColId); - this.typeOutlineView.AddColumn (typeColumn); - - // Set OutlineTableColumn or the arrows showing children/expansion will not be drawn - this.typeOutlineView.OutlineTableColumn = typeColumn; - - // create a table view and a scroll view - var tableContainer = new NSScrollView { - TranslatesAutoresizingMaskIntoConstraints = false, - }; - - // add the panel to the window - tableContainer.DocumentView = this.typeOutlineView; - AddSubview (tableContainer); - - var filterObjects = new NSSearchField { - ControlSize = NSControlSize.Mini, - Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize), - PlaceholderString = Properties.Resources.SearchObjectsTitle, - TranslatesAutoresizingMaskIntoConstraints = false, - }; - - filterObjects.Changed += (sender, e) => { - viewModel.TypeSelector.FilterText = filterObjects.Cell.Title; - this.typeOutlineView.ReloadData (); - this.typeOutlineView.ExpandItem (null, true); - }; - - AddSubview (filterObjects); - AddConstraints (new[] { - NSLayoutConstraint.Create (filterObjects, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 45f), - NSLayoutConstraint.Create (filterObjects, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this, NSLayoutAttribute.Left, 1f, 5f), - NSLayoutConstraint.Create (filterObjects, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1f, -10f), - NSLayoutConstraint.Create (filterObjects, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 24), - }); - - // Position based on filterObjects bottom and All Assemblies Top. - AddConstraints (new[] { - NSLayoutConstraint.Create (tableContainer, NSLayoutAttribute.Top, NSLayoutRelation.Equal, filterObjects, NSLayoutAttribute.Bottom, 1f, 5f), - NSLayoutConstraint.Create (tableContainer, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this, NSLayoutAttribute.Left, 1f, 5f), - NSLayoutConstraint.Create (tableContainer, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1f, -10f), - NSLayoutConstraint.Create (tableContainer, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this, NSLayoutAttribute.Height, 1f, -105f), - }); - - this.showAllAssembliesCheckBox = new NSButton { - ControlSize = NSControlSize.Small, - Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize), - Title = Properties.Resources.ShowAllAssemblies, - TranslatesAutoresizingMaskIntoConstraints = false, - }; - - this.showAllAssembliesCheckBox.SetButtonType (NSButtonType.Switch); - this.showAllAssembliesCheckBox.Activated += SelectionChanged; - - AddSubview (this.showAllAssembliesCheckBox); - AddConstraints (new[] { - NSLayoutConstraint.Create (this.showAllAssembliesCheckBox, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Bottom, 1f, -30f), - NSLayoutConstraint.Create (this.showAllAssembliesCheckBox, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this, NSLayoutAttribute.Left, 1f, 10f), - NSLayoutConstraint.Create (this.showAllAssembliesCheckBox, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1f, -10f), - NSLayoutConstraint.Create (this.showAllAssembliesCheckBox, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 24), - }); - - viewModel.PropertyChanged += (sender, e) => { - if (e.PropertyName == nameof (CreateBindingViewModel.ShowTypeSelector)) { - Hidden = !viewModel.ShowTypeSelector; - - if (viewModel.ShowTypeSelector && viewModel.TypeSelector != null) { - this.typeOutlineView.ViewModel = viewModel.TypeSelector; - - this.showAllAssembliesCheckBox.State = viewModel.TypeSelector.ShowAllAssemblies ? NSCellStateValue.On : NSCellStateValue.Off; - } - } - }; - } - - private void SelectionChanged (object sender, EventArgs e) - { - if (sender is NSButton button) { - this.typeOutlineView.ViewModel.ShowAllAssemblies = (button.State == NSCellStateValue.On) ? true : false; - } - } - } -} diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/CreateValueConverterWindow.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/CreateValueConverterWindow.cs index e97a9b4..b8c5c0e 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/CreateValueConverterWindow.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/CreateValueConverterWindow.cs @@ -10,7 +10,7 @@ namespace Xamarin.PropertyEditing.Mac { internal class CreateValueConverterWindow : NSPanel { - new ModalWindowCloseDelegate Delegate { + private new ModalWindowCloseDelegate Delegate { get => (ModalWindowCloseDelegate)base.Delegate; set => base.Delegate = value; } @@ -42,31 +42,32 @@ namespace Xamarin.PropertyEditing.Mac }; var valueConverterLabel = new UnfocusableTextField { - StringValue = Properties.Resources.ValueConverterName, + Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, 13), + StringValue = Properties.Resources.ValueConverterName + ":", TranslatesAutoresizingMaskIntoConstraints = false, }; container.AddSubview (valueConverterLabel); container.AddConstraints (new[] { - NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, container, NSLayoutAttribute.Top, 1f, 0f), - NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Left, NSLayoutRelation.Equal, container, NSLayoutAttribute.Left, 1f, 5f), - NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 24), + NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, container, NSLayoutAttribute.Top, 1f, 18f), + NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Left, NSLayoutRelation.Equal, container, NSLayoutAttribute.Left, 1f, 21f), + NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 20), }); this.valueConverterName = new NSTextField { - ControlSize = NSControlSize.Small, + ControlSize = NSControlSize.Regular, TranslatesAutoresizingMaskIntoConstraints = false, }; container.AddSubview (this.valueConverterName); container.AddConstraints (new[] { NSLayoutConstraint.Create (this.valueConverterName, NSLayoutAttribute.Top, NSLayoutRelation.Equal, valueConverterLabel, NSLayoutAttribute.Bottom, 1f, 1f), - NSLayoutConstraint.Create (this.valueConverterName, NSLayoutAttribute.Left, NSLayoutRelation.Equal, container, NSLayoutAttribute.Left, 1f, 5f), - NSLayoutConstraint.Create (this.valueConverterName, NSLayoutAttribute.Width, NSLayoutRelation.Equal, container, NSLayoutAttribute.Width, 1f, -10f), - NSLayoutConstraint.Create (this.valueConverterName, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 24), + NSLayoutConstraint.Create (this.valueConverterName, NSLayoutAttribute.Left, NSLayoutRelation.Equal, valueConverterLabel, NSLayoutAttribute.Left, 1f, 0f), + NSLayoutConstraint.Create (this.valueConverterName, NSLayoutAttribute.Width, NSLayoutRelation.Equal, container, NSLayoutAttribute.Width, 1f, -40f), }); var typeSelectorControl = new TypeSelectorControl { + Flush = true, ViewModel = ViewModel, TranslatesAutoresizingMaskIntoConstraints = false, }; @@ -74,31 +75,53 @@ namespace Xamarin.PropertyEditing.Mac container.AddSubview (typeSelectorControl); container.AddConstraints (new[] { - NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, container, NSLayoutAttribute.Top, 1f, 45f), - NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Left, NSLayoutRelation.Equal, container, NSLayoutAttribute.Left, 1f, 0f), - NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, container, NSLayoutAttribute.Width, 1f, 0f), - NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, container, NSLayoutAttribute.Height, 1f, -50f) + NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.valueConverterName, NSLayoutAttribute.Bottom, 1f, 8f), + NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Left, NSLayoutRelation.Equal, valueConverterLabel, NSLayoutAttribute.Left, 1f, 0f), + NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.valueConverterName, NSLayoutAttribute.Width, 1f, 0f), + NSLayoutConstraint.Create (typeSelectorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, container, NSLayoutAttribute.Height, 1f, -95f), }); - var buttonDone = new NSButton { + var buttonSelect = new NSButton { BezelStyle = NSBezelStyle.Rounded, + ControlSize = NSControlSize.Regular, + Enabled = false, Highlighted = true, KeyEquivalent = "\r", // Fire when enter pressed - Title = Properties.Resources.DoneTitle, + Title = Properties.Resources.Select, TranslatesAutoresizingMaskIntoConstraints = false, }; - buttonDone.Activated += (sender, e) => { + buttonSelect.Activated += (sender, e) => { Delegate.Response = NSModalResponse.OK; Close (); }; - container.AddSubview (buttonDone); + container.AddSubview (buttonSelect); container.AddConstraints (new[] { - NSLayoutConstraint.Create (buttonDone, NSLayoutAttribute.Top, NSLayoutRelation.Equal, container, NSLayoutAttribute.Bottom, 1f, -32f), - NSLayoutConstraint.Create (buttonDone, NSLayoutAttribute.Right, NSLayoutRelation.Equal, container, NSLayoutAttribute.Right, 1f, -16f), - NSLayoutConstraint.Create (buttonDone, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 24), + NSLayoutConstraint.Create (buttonSelect, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, container, NSLayoutAttribute.Bottom, 1f, -20f), + NSLayoutConstraint.Create (buttonSelect, NSLayoutAttribute.Right, NSLayoutRelation.Equal, typeSelectorControl, NSLayoutAttribute.Right, 1f, 0f), + NSLayoutConstraint.Create (buttonSelect, NSLayoutAttribute.Width, NSLayoutRelation.GreaterThanOrEqual, 1f, 80f), + }); + + var buttonCancel = new NSButton { + BezelStyle = NSBezelStyle.Rounded, + ControlSize = NSControlSize.Regular, + Title = Properties.Resources.Cancel, + TranslatesAutoresizingMaskIntoConstraints = false, + }; + + buttonCancel.Activated += (sender, e) => { + Delegate.Response = NSModalResponse.Cancel; + Close (); + }; + + container.AddSubview (buttonCancel); + + container.AddConstraints (new[] { + NSLayoutConstraint.Create (buttonCancel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, buttonSelect, NSLayoutAttribute.Top, 1f, 0f), + NSLayoutConstraint.Create (buttonCancel, NSLayoutAttribute.Right, NSLayoutRelation.Equal, buttonSelect, NSLayoutAttribute.Left, 1f, -10f), + NSLayoutConstraint.Create (buttonCancel, NSLayoutAttribute.Width, NSLayoutRelation.GreaterThanOrEqual, 1f, 80f), }); ContentViewController = new NSViewController (null, null) { @@ -106,20 +129,11 @@ namespace Xamarin.PropertyEditing.Mac }; ViewModel.PropertyChanged += (sender, e) => { - if (e.PropertyName == nameof (ViewModel.SelectedType)) { - this.valueConverterName.StringValue = ViewModel.SelectedType.Name; + if (e.PropertyName == nameof (AddValueConverterViewModel.SelectedType)) { + this.valueConverterName.StringValue = ViewModel.SelectedType != null ? ViewModel.SelectedType.Name : string.Empty; + buttonSelect.Enabled = ViewModel.SelectedType != null; } }; } } - - public class ModalWindowCloseDelegate : NSWindowDelegate - { - public NSModalResponse Response { get; set; } = NSModalResponse.Cancel; - - public override void WillClose (NSNotification notification) - { - NSApplication.SharedApplication.StopModalWithCode ((int)Response); - } - } } diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/HeaderView.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/HeaderView.cs index 5fb377b..833a76b 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/HeaderView.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/HeaderView.cs @@ -7,13 +7,20 @@ namespace Xamarin.PropertyEditing.Mac { internal class HeaderView : NSView { - public string Title - { + public string Title { get { return this.headerText.StringValue; } set { this.headerText.StringValue = value; } } - private UnfocusableTextField headerText = new UnfocusableTextField (); + private NSLayoutConstraint horizonalHeaderTextAlignment; + public nfloat HorizonalTitleOffset { + get { return this.horizonalHeaderTextAlignment.Constant; } + set { this.horizonalHeaderTextAlignment.Constant = value; } + } + + private UnfocusableTextField headerText = new UnfocusableTextField { + TranslatesAutoresizingMaskIntoConstraints = false, + }; internal HeaderView () { @@ -23,19 +30,17 @@ namespace Xamarin.PropertyEditing.Mac // Layer out of alphabetical order so that WantsLayer creates the layer first Layer = new CALayer { CornerRadius = 1.0f, - BorderColor = new CGColor (.5f, .5f, .5f, .5f), + BorderColor = new CGColor (.5f, .5f, .5f, 1.0f), BorderWidth = 1, }; - this.headerText.Alignment = NSTextAlignment.Center; - this.headerText.TranslatesAutoresizingMaskIntoConstraints = false; + this.horizonalHeaderTextAlignment = NSLayoutConstraint.Create (this.headerText, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this, NSLayoutAttribute.CenterX, 1, 0); AddSubview (this.headerText); AddConstraints (new[] { - NSLayoutConstraint.Create (this.headerText, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 0f), - NSLayoutConstraint.Create (this.headerText, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this, NSLayoutAttribute.Left, 1f, 0f), - NSLayoutConstraint.Create (this.headerText, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1f, 0f), NSLayoutConstraint.Create (this.headerText, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this, NSLayoutAttribute.Height, 1f, 0f), + this.horizonalHeaderTextAlignment, + NSLayoutConstraint.Create (this.headerText, NSLayoutAttribute.CenterY, NSLayoutRelation.Equal, this, NSLayoutAttribute.CenterY, 1, 0f), }); } } diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/ObjectOutlineView.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/ObjectOutlineView.cs new file mode 100644 index 0000000..18ee0cf --- /dev/null +++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/ObjectOutlineView.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using AppKit; +using Foundation; +using Xamarin.PropertyEditing.ViewModels; + +namespace Xamarin.PropertyEditing.Mac +{ + internal class ObjectOutlineView : BaseSelectorOutlineView + { + private IReadOnlyList<ObjectTreeElement> itemsSource; + public IReadOnlyList<ObjectTreeElement> ItemsSource + { + get => this.itemsSource; + set + { + if (this.itemsSource != value) { + this.itemsSource = value; + + DataSource = new ObjectOutlineViewDataSource (this.itemsSource); ; + Delegate = new ObjectOutlineViewDelegate (); + } + + ReloadData (); + + ExpandItem (null, true); + } + } + } + + internal class ObjectOutlineViewDelegate : NSOutlineViewDelegate + { + private const string TypeIdentifier = "type"; + + public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) + { + var labelContainer = (UnfocusableTextField)outlineView.MakeView (TypeIdentifier, this); + if (labelContainer == null) { + labelContainer = new UnfocusableTextField { + Identifier = TypeIdentifier, + }; + } + var target = (item as NSObjectFacade).Target; + + switch (target) { + case KeyValuePair<string, SimpleCollectionView> kvp: + labelContainer.StringValue = kvp.Key; + break; + case TypeInfo info: + labelContainer.StringValue = info.Name; + break; + default: + labelContainer.StringValue = Properties.Resources.TypeNotSupported; + break; + } + + return labelContainer; + } + + public override bool ShouldSelectItem (NSOutlineView outlineView, NSObject item) + { + var target = (item as NSObjectFacade).Target; + switch (target) { + case KeyValuePair<string, SimpleCollectionView> kvp: + return false; + case TypeInfo info: + return true; + + default: + return false; + } + } + } + + internal class ObjectOutlineViewDataSource : NSOutlineViewDataSource + { + public IReadOnlyList<ObjectTreeElement> ItemsSource { get; } + + internal ObjectOutlineViewDataSource (IReadOnlyList<ObjectTreeElement> itemsSource) + { + if (itemsSource == null) + throw new ArgumentNullException (nameof (itemsSource)); + + ItemsSource = itemsSource; + } + + public override nint GetChildrenCount (NSOutlineView outlineView, NSObject item) + { + if (item == null) { + return ItemsSource != null ? ItemsSource.Count : 0; + } else { + var target = (item as NSObjectFacade).Target; + switch (target) { + case KeyValuePair<string, SimpleCollectionView> kvp: + return kvp.Value.Count; + case TypeInfo info: + return 0; + default: + return 0; + } + } + } + + public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, NSObject item) + { + object element; + + if (item == null) { + element = ItemsSource.ElementAt ((int)childIndex); + } else { + var target = (item as NSObjectFacade).Target; + switch (target) { + case KeyValuePair<string, SimpleCollectionView> kvp: + element = kvp.Value[(int)childIndex]; + break; + case TypeInfo info: + element = info; + break; + default: + return null; + } + } + + return new NSObjectFacade (element); + } + + public override bool ItemExpandable (NSOutlineView outlineView, NSObject item) + { + var target = (item as NSObjectFacade).Target; + switch (target) { + case KeyValuePair<string, SimpleCollectionView> kvp: + return kvp.Value.Count > 0; + case TypeInfo info: + return false; + default: + return false; + } + } + } +} diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/PathOutlineView.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/PathOutlineView.cs new file mode 100644 index 0000000..124cee6 --- /dev/null +++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/PathOutlineView.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections.Generic; +using AppKit; +using Foundation; +using Xamarin.PropertyEditing.ViewModels; + +namespace Xamarin.PropertyEditing.Mac +{ + internal class PathOutlineView : BaseSelectorOutlineView + { + private IReadOnlyCollection<object> itemsSource; + private PropertyTreeRoot propertyTreeRoot; + + private void SetItemsSource (IReadOnlyCollection<object> value, string targetName) + { + if (this.itemsSource != value) { + this.itemsSource = value; + + DataSource = new PathOutlineViewDataSource (this.itemsSource, targetName); ; + Delegate = new PathOutlineViewDelegate (); + + ReloadData (); + + ExpandItem (ItemAtRow (0)); + } + } + + public PropertyTreeRoot PropertyTreeRoot + { + get { return this.propertyTreeRoot; } + internal set + { + if (this.propertyTreeRoot != value) { + this.propertyTreeRoot = value; + if (this.propertyTreeRoot != null) { + SetItemsSource (this.propertyTreeRoot.Children, this.propertyTreeRoot.TargetType.Name); + } else { + SetItemsSource (null, string.Empty); + } + } + } + } + } + + internal class PathOutlineViewDelegate : NSOutlineViewDelegate + { + private const string PathIdentifier = "path"; + + public override NSView GetView (NSOutlineView outlineView, NSTableColumn tableColumn, NSObject item) + { + var labelContainer = (UnfocusableTextField)outlineView.MakeView (PathIdentifier, this); + if (labelContainer == null) { + labelContainer = new UnfocusableTextField { + Identifier = PathIdentifier, + }; + } + var target = (item as NSObjectFacade).Target; + + switch (target) { + case PropertyTreeElement propertyTreeElement: + labelContainer.StringValue = string.Format ("{0}: ({1})", propertyTreeElement.Property.Name, propertyTreeElement.Property.RealType.Name); + break; + + case string targetName: + labelContainer.StringValue = targetName; + break; + + default: + labelContainer.StringValue = Properties.Resources.TypeNotSupported; + break; + } + + return labelContainer; + } + + public override bool ShouldSelectItem (NSOutlineView outlineView, NSObject item) + { + if (item is NSObjectFacade facade) { + switch (facade.Target) { + case PropertyTreeElement propertyTreeElement: + var propertyTreeResult = propertyTreeElement.Children.Task.Result; + return propertyTreeResult.Count == 0; + + default: + return false; + } + } else { + return false; + } + } + } + + internal class PathOutlineViewDataSource : NSOutlineViewDataSource + { + private readonly IReadOnlyCollection<object> itemsSource; + private readonly string targetName; + + internal PathOutlineViewDataSource (IReadOnlyCollection<object> itemsSource, string targetName) + { + this.itemsSource = itemsSource; + this.targetName = targetName; + } + + public override nint GetChildrenCount (NSOutlineView outlineView, NSObject item) + { + if (item == null) { + return this.itemsSource != null ? this.itemsSource.Count + 1 : 0; + } else { + var target = (item as NSObjectFacade).Target; + switch (target) { + case PropertyTreeElement propertyTreeElement: + IReadOnlyCollection<PropertyTreeElement> propertyTrees = propertyTreeElement.Children.Task.Result; + return propertyTrees.Count; + + case string targetName: + return this.itemsSource.Count; + + default: + return 0; + } + } + } + + public override NSObject GetChild (NSOutlineView outlineView, nint childIndex, NSObject item) + { + if (childIndex == 0 && item == null) { + return new NSObjectFacade (targetName); + } + + if (item is NSObjectFacade objectFacade) { + var target = objectFacade.Target; + switch (target) { + case PropertyTreeElement propertyTreeElement: + IReadOnlyCollection<PropertyTreeElement> propertyTrees = propertyTreeElement.Children.Task.Result; + return new NSObjectFacade (propertyTrees.ElementAt ((int)childIndex)); + + case string targetName: + return new NSObjectFacade (this.itemsSource.ElementAt ((int)childIndex)); + + default: + return null; + } + + } + return null; + } + + public override bool ItemExpandable (NSOutlineView outlineView, NSObject item) + { + if (item is NSObjectFacade objectFacade) { + var target = objectFacade.Target; + switch (target) { + case PropertyTreeElement propertyTreeElement: + IReadOnlyCollection<PropertyTreeElement> propertyTrees = propertyTreeElement.Children.Task.Result; + return propertyTrees.Count > 0; + + case string targetName: + return true; + + default: + return false; + } + } + + return false; + } + } +} diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/BasePanelWindow.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/BasePanelWindow.cs deleted file mode 100644 index d22ea4b..0000000 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/BasePanelWindow.cs +++ /dev/null @@ -1,301 +0,0 @@ -using System; -using System.Linq; -using AppKit; -using CoreGraphics; -using Foundation; -using Xamarin.PropertyEditing.ViewModels; - -namespace Xamarin.PropertyEditing.Mac -{ - internal class BasePanelWindow : NSPanel - { - protected NSButton ButtonDone; - private NSButton buttonCancel; - private NSButton buttonHelp; - - protected NSPopUpButton BindingTypePopup; - - protected NSPopUpButton ValueConverterPopup; - - protected NSButton AddConverterButton; - - protected NSView AncestorTypeBox; - protected NSView PathBox; - - protected NSView MainContainer; - protected NSView BindingPropertiesView; - protected NSView FlagsPropertiesView; - protected NSButton ButtonMoreSettings; - - protected nfloat MoreSettingsViewHeight { get; set; } - - internal BasePanelWindow () - : base (new CGRect (0, 0, 728, 445), NSWindowStyle.Titled | NSWindowStyle.Closable | NSWindowStyle.Resizable, NSBackingStore.Buffered, true) - { - FloatingPanel = true; - - MaxSize = new CGSize (960, 720); // TODO discuss what the Max/Min Size should be and if we should have one. - MinSize = new CGSize (320, 240); - - this.MainContainer = new NSView { - TranslatesAutoresizingMaskIntoConstraints = false - }; - - this.ButtonDone = new NSButton { - BezelStyle = NSBezelStyle.Rounded, - KeyEquivalent = "\r", // Fire when enter pressed - Highlighted = true, - TranslatesAutoresizingMaskIntoConstraints = false, - }; - - this.MainContainer.AddSubview (this.ButtonDone); - - this.buttonCancel = new NSButton { - BezelStyle = NSBezelStyle.Rounded, - KeyEquivalent = "0x1b", // TODO Need to double check this is right - Title = Properties.Resources.Cancel, - TranslatesAutoresizingMaskIntoConstraints = false, - }; - - this.buttonCancel.Activated += (sender, e) => { - Close (); - }; - - this.MainContainer.AddSubview (this.buttonCancel); - - this.buttonHelp = new NSButton { - BezelStyle = NSBezelStyle.HelpButton, - Title = string.Empty, - TranslatesAutoresizingMaskIntoConstraints = false, - }; - - this.MainContainer.AddSubview (this.buttonHelp); - - var bindingTypeLabel = new UnfocusableTextField { - TranslatesAutoresizingMaskIntoConstraints = false, - Alignment = NSTextAlignment.Right, - }; - - bindingTypeLabel.StringValue = Properties.Resources.BindingType; - this.MainContainer.AddSubview (bindingTypeLabel); - - this.BindingTypePopup = new FocusablePopUpButton { - TranslatesAutoresizingMaskIntoConstraints = false, - StringValue = String.Empty, - ControlSize = NSControlSize.Small, - Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize), - }; - - var bindingTypeMenuList = new NSMenu (); - this.BindingTypePopup.Menu = bindingTypeMenuList; - this.MainContainer.AddSubview (this.BindingTypePopup); - - var valueConverterLabel = new UnfocusableTextField { - TranslatesAutoresizingMaskIntoConstraints = false, - Alignment = NSTextAlignment.Right, - }; - - this.AncestorTypeBox = new NSView { - TranslatesAutoresizingMaskIntoConstraints = false, - WantsLayer = true, - - // Layer out of alphabetical order so that WantsLayer creates the layer first - Layer = { - CornerRadius = 1.0f, - BorderColor = new CGColor (.5f, .5f, .5f, .5f), - BorderWidth = 1, - }, - }; - - this.MainContainer.AddSubview (this.AncestorTypeBox); - - this.PathBox = new NSView { - TranslatesAutoresizingMaskIntoConstraints = false, - WantsLayer = true, - - // Layer out of alphabetical order so that WantsLayer creates the layer first - Layer = { - CornerRadius = 1.0f, - BorderColor = new CGColor (.5f, .5f, .5f, .5f), - BorderWidth = 1, - }, - }; - - this.MainContainer.AddSubview (this.PathBox); - - valueConverterLabel.StringValue = Properties.Resources.Converter; - this.MainContainer.AddSubview (valueConverterLabel); - - this.ValueConverterPopup = new FocusablePopUpButton { - TranslatesAutoresizingMaskIntoConstraints = false, - StringValue = String.Empty, - ControlSize = NSControlSize.Small, - Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize), - }; - - var valueConverterMenuList = new NSMenu (); - this.ValueConverterPopup.Menu = valueConverterMenuList; - this.MainContainer.AddSubview (this.ValueConverterPopup); - - this.AddConverterButton = new NSButton { - BezelStyle = NSBezelStyle.Rounded, - Image = NSImage.ImageNamed (NSImageName.AddTemplate), - Title = string.Empty, - ToolTip = Properties.Resources.AddValueConverterEllipsis, - TranslatesAutoresizingMaskIntoConstraints = false, - }; - - this.MainContainer.AddSubview (this.AddConverterButton); - - this.ButtonMoreSettings = new NSButton { - BezelStyle = NSBezelStyle.Disclosure, - Title = string.Empty, - TranslatesAutoresizingMaskIntoConstraints = false, - }; - this.ButtonMoreSettings.SetButtonType (NSButtonType.PushOnPushOff); - - this.MainContainer.AddSubview (this.ButtonMoreSettings); - - var labelOtherSettings = new UnfocusableTextField { - TranslatesAutoresizingMaskIntoConstraints = false, - }; - - this.MainContainer.AddSubview (labelOtherSettings); - - this.BindingPropertiesView = new NSView { - Hidden = true, - TranslatesAutoresizingMaskIntoConstraints = false, - WantsLayer = true, - - // Layer out of alphabetical order so that WantsLayer creates the layer first - Layer = { - CornerRadius = 1.0f, - BorderColor = new CGColor (.5f, .5f, .5f, .5f), - BorderWidth = 1, - }, - }; - - this.MainContainer.AddSubview (this.BindingPropertiesView); - - this.FlagsPropertiesView = new NSView { - Hidden = true, - TranslatesAutoresizingMaskIntoConstraints = false, - WantsLayer = true, - - // Layer out of alphabetical order so that WantsLayer creates the layer first - Layer = { - CornerRadius = 1.0f, - BorderColor = new CGColor (.5f, .5f, .5f, .5f), - BorderWidth = 1, - }, - }; - - this.MainContainer.AddSubview (this.FlagsPropertiesView); - - //Work out the titlebar height - var titleBarHeight = Frame.Size.Height - ContentRectFor (Frame).Size.Height; - - var ancestorTypeBoxHeightConstraint = NSLayoutConstraint.Create (this.AncestorTypeBox, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this.MainContainer, NSLayoutAttribute.Bottom, 1f, -100f); - var heightConstant = ancestorTypeBoxHeightConstraint.Constant; - - var bindingPropertiesViewHeightConstraint = NSLayoutConstraint.Create (this.BindingPropertiesView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 124); - - this.ButtonMoreSettings.Activated += (sender, e) => { - if (sender is NSButton moreButton) { - ToggleSettingsLabel (moreButton.State == NSCellStateValue.Off, labelOtherSettings); - - this.BindingPropertiesView.Hidden = moreButton.State == NSCellStateValue.Off; - this.FlagsPropertiesView.Hidden = this.BindingPropertiesView.Hidden; - - bindingPropertiesViewHeightConstraint.Constant = this.MoreSettingsViewHeight; - ancestorTypeBoxHeightConstraint.Constant = this.BindingPropertiesView.Hidden ? heightConstant : heightConstant - (MoreSettingsViewHeight + 20); - this.MainContainer.SetFrameSize (new CGSize (this.MainContainer.Frame.Width, this.BindingPropertiesView.Hidden ? this.MainContainer.Frame.Height - MoreSettingsViewHeight : this.MainContainer.Frame.Height + MoreSettingsViewHeight)); - SetFrame (new CGRect (new CGPoint (Frame.X, Frame.Y), new CGSize (Frame.Width, this.MainContainer.Frame.Height + titleBarHeight)), false, true); - } - }; - - ToggleSettingsLabel (this.ButtonMoreSettings.State == NSCellStateValue.Off, labelOtherSettings); - - this.MainContainer.AddConstraints (new[] { - NSLayoutConstraint.Create (bindingTypeLabel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.MainContainer, NSLayoutAttribute.Top, 1f, 10f), - NSLayoutConstraint.Create (bindingTypeLabel, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.MainContainer, NSLayoutAttribute.Left, 1f, 20f), - NSLayoutConstraint.Create (bindingTypeLabel, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, PropertyEditorControl.DefaultControlHeight), - - NSLayoutConstraint.Create (this.BindingTypePopup, NSLayoutAttribute.Top, NSLayoutRelation.Equal, bindingTypeLabel, NSLayoutAttribute.Top, 1f, 0f), - NSLayoutConstraint.Create (this.BindingTypePopup, NSLayoutAttribute.Left, NSLayoutRelation.Equal, bindingTypeLabel, NSLayoutAttribute.Right, 1f, 5f), - NSLayoutConstraint.Create (this.BindingTypePopup, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, PropertyEditorControl.DefaultControlHeight), - - NSLayoutConstraint.Create (this.AncestorTypeBox, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.BindingTypePopup, NSLayoutAttribute.Bottom, 1f, 10f), - NSLayoutConstraint.Create (this.AncestorTypeBox, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.MainContainer, NSLayoutAttribute.Left, 1f, 20f), - NSLayoutConstraint.Create (this.AncestorTypeBox, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.PathBox, NSLayoutAttribute.Left, 1f, -10f), - ancestorTypeBoxHeightConstraint, - - NSLayoutConstraint.Create (this.PathBox, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Top, 1f, 0f), - NSLayoutConstraint.Create (this.PathBox, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.MainContainer, NSLayoutAttribute.Right, 1f, -20f), - NSLayoutConstraint.Create (this.PathBox, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Width, 1f, 0f), - NSLayoutConstraint.Create (this.PathBox, NSLayoutAttribute.Height, NSLayoutRelation.Equal,this.AncestorTypeBox, NSLayoutAttribute.Height, 1f, 0f), - - NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.AncestorTypeBox, NSLayoutAttribute.Bottom, 1f, 10f), - NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.MainContainer, NSLayoutAttribute.Left, 1f, 20f), - NSLayoutConstraint.Create (valueConverterLabel, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, PropertyEditorControl.DefaultControlHeight), - - NSLayoutConstraint.Create (this.ValueConverterPopup, NSLayoutAttribute.Top, NSLayoutRelation.Equal, valueConverterLabel, NSLayoutAttribute.Top, 1f, 0f), - NSLayoutConstraint.Create (this.ValueConverterPopup, NSLayoutAttribute.Left, NSLayoutRelation.Equal, valueConverterLabel, NSLayoutAttribute.Right, 1f, 5f), - NSLayoutConstraint.Create (this.ValueConverterPopup, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, PropertyEditorControl.DefaultControlHeight), - - NSLayoutConstraint.Create (this.AddConverterButton, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ValueConverterPopup, NSLayoutAttribute.Top, 1f, 2f), - NSLayoutConstraint.Create (this.AddConverterButton, NSLayoutAttribute.Left, NSLayoutRelation.Equal,this.ValueConverterPopup, NSLayoutAttribute.Right, 1f, 5f), - NSLayoutConstraint.Create (this.AddConverterButton, NSLayoutAttribute.Width, NSLayoutRelation.Equal, 1f, 20), - NSLayoutConstraint.Create (this.AddConverterButton, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 20), - - NSLayoutConstraint.Create (this.ButtonMoreSettings, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ValueConverterPopup, NSLayoutAttribute.Bottom, 1f, 2f), - NSLayoutConstraint.Create (this.ButtonMoreSettings, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.MainContainer, NSLayoutAttribute.Left, 1f, 16f), - NSLayoutConstraint.Create (this.ButtonMoreSettings, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 24), - NSLayoutConstraint.Create (this.ButtonMoreSettings, NSLayoutAttribute.Width, NSLayoutRelation.Equal, 1f, 24), - - NSLayoutConstraint.Create (labelOtherSettings, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ButtonMoreSettings, NSLayoutAttribute.Top, 1f, 0f), - NSLayoutConstraint.Create (labelOtherSettings, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.ButtonMoreSettings, NSLayoutAttribute.Right, 1f, -5f), - NSLayoutConstraint.Create (labelOtherSettings, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, PropertyEditorControl.DefaultControlHeight), - - NSLayoutConstraint.Create (this.BindingPropertiesView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ButtonMoreSettings, NSLayoutAttribute.Bottom, 1f, 10f), - NSLayoutConstraint.Create (this.BindingPropertiesView, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.MainContainer, NSLayoutAttribute.Left, 1f, 20f), - NSLayoutConstraint.Create (this.BindingPropertiesView, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.FlagsPropertiesView, NSLayoutAttribute.Left, 1f, -10f), - bindingPropertiesViewHeightConstraint, - - NSLayoutConstraint.Create (this.FlagsPropertiesView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.BindingPropertiesView, NSLayoutAttribute.Top, 1f, 0f), - NSLayoutConstraint.Create (this.FlagsPropertiesView, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.MainContainer, NSLayoutAttribute.Right, 1f, -20f), - NSLayoutConstraint.Create (this.FlagsPropertiesView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.BindingPropertiesView, NSLayoutAttribute.Width, 1f, 0f), - NSLayoutConstraint.Create (this.FlagsPropertiesView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, this.BindingPropertiesView, NSLayoutAttribute.Height, 1f, 0f), - - NSLayoutConstraint.Create (this.buttonHelp, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.MainContainer, NSLayoutAttribute.Bottom, 1f, -40f), - NSLayoutConstraint.Create (this.buttonHelp, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this.MainContainer, NSLayoutAttribute.Left, 1f, 20), - NSLayoutConstraint.Create (this.buttonHelp, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, PropertyEditorControl.DefaultControlHeight), - NSLayoutConstraint.Create (this.buttonHelp, NSLayoutAttribute.Width, NSLayoutRelation.Equal, 1f, 24), - - NSLayoutConstraint.Create (this.ButtonDone, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.MainContainer, NSLayoutAttribute.Bottom, 1f, -40f), - NSLayoutConstraint.Create (this.ButtonDone, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.MainContainer, NSLayoutAttribute.Right, 1f, -20f), - NSLayoutConstraint.Create (this.ButtonDone, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, PropertyEditorControl.DefaultControlHeight), - - NSLayoutConstraint.Create (this.buttonCancel, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.ButtonDone, NSLayoutAttribute.Top, 1f, 0f), - NSLayoutConstraint.Create (this.buttonCancel, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this.ButtonDone, NSLayoutAttribute.Left, 1f, -10f), - NSLayoutConstraint.Create (this.buttonCancel, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, PropertyEditorControl.DefaultControlHeight), - }); - - // put the MainContainer inside this panel's ContentView - ContentView.AddSubview (this.MainContainer); - - ContentView.AddConstraints (new[] { - NSLayoutConstraint.Create (this.MainContainer, NSLayoutAttribute.Top, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Top, 1f, 0f), - NSLayoutConstraint.Create (this.MainContainer, NSLayoutAttribute.Left, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Left, 1f, 0f), - NSLayoutConstraint.Create (this.MainContainer, NSLayoutAttribute.Height, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Height, 1f, 0f), - NSLayoutConstraint.Create (this.MainContainer, NSLayoutAttribute.Width, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Width, 1f, 0f), - - }); - } - - private static void ToggleSettingsLabel (bool show, UnfocusableTextField labelOtherSettings) - { - labelOtherSettings.StringValue = show ? Properties.Resources.ShowSettings : Properties.Resources.HideSettings; - } - } -} diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/CommandButton.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/CommandButton.cs index 4904bd8..4fde65f 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/CommandButton.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/CommandButton.cs @@ -2,7 +2,7 @@ using System; using System.Windows.Input; using AppKit; -namespace Xamarin.PropertyEditing.Mac.Controls.Custom +namespace Xamarin.PropertyEditing.Mac { internal class CommandButton : NSButton { @@ -11,8 +11,7 @@ namespace Xamarin.PropertyEditing.Mac.Controls.Custom public ICommand Command { get { return this.command; } - set - { + set { if (this.command != null) this.command.CanExecuteChanged -= CanExecuteChanged; diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs index 2533d97..5fc2093 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using AppKit; using CoreGraphics; using Xamarin.PropertyEditing.ViewModels; @@ -19,11 +20,16 @@ namespace Xamarin.PropertyEditing.Mac set { if (this.viewModel != null) { this.viewModel.PropertyChanged -= OnPropertyChanged; + if (this.viewModel.SupportsBindings) + this.viewModel.CreateBindingRequested -= OnBindingRequested; } this.viewModel = value; + if (this.viewModel != null) { this.viewModel.PropertyChanged += OnPropertyChanged; + if (this.viewModel.SupportsBindings) + this.viewModel.CreateBindingRequested += OnBindingRequested; ValueSourceChanged (this.viewModel.ValueSource); } } @@ -110,16 +116,13 @@ namespace Xamarin.PropertyEditing.Mac if (this.viewModel.SupportsBindings) { this.popUpContextMenu.AddItem (NSMenuItem.SeparatorItem); - var mi3 = new NSMenuItem (Properties.Resources.CreateDataBindingMenuItem) { + this.popUpContextMenu.AddItem (new CommandMenuItem (Properties.Resources.CreateDataBindingMenuItem, this.viewModel.RequestCreateBindingCommand) { AttributedTitle = new Foundation.NSAttributedString ( Properties.Resources.CreateDataBindingMenuItem, new CoreText.CTStringAttributes { Font = new CoreText.CTFont (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize + 1), }) - }; - - mi3.Activated += OnBindingRequested; - this.popUpContextMenu.AddItem (mi3); + }); } this.popUpContextMenu.AddItem (NSMenuItem.SeparatorItem); @@ -252,10 +255,16 @@ namespace Xamarin.PropertyEditing.Mac resourceSelectorPopOver.Show (requestResourceView.Frame, (NSView)this, NSRectEdge.MinYEdge); } - private void OnBindingRequested (object sender, EventArgs e) + private void OnBindingRequested (object sender, CreateBindingRequestedEventArgs e) { - var bindingEditorWindow = new BindingEditorWindow (this.hostResources, this.viewModel); - bindingEditorWindow.MakeKeyAndOrderFront (this); + var bindingEditorWindow = new BindingEditorWindow (this.hostResources, this.viewModel) { + Appearance = EffectiveAppearance, + }; + + var result = (NSModalResponse)(int)NSApplication.SharedApplication.RunModalForWindow (bindingEditorWindow); + if (result == NSModalResponse.OK) { + e.BindingObject = bindingEditorWindow.ViewModel.SelectedObjects.Single (); + } } } } diff --git a/Xamarin.PropertyEditing.Mac/Controls/EditorContainer.cs b/Xamarin.PropertyEditing.Mac/Controls/EditorContainer.cs index 2175b29..ca1d76b 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/EditorContainer.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/EditorContainer.cs @@ -6,8 +6,8 @@ namespace Xamarin.PropertyEditing.Mac internal class EditorContainer : PropertyContainer { - public EditorContainer (IHostResourceProvider hostResources, IEditorView editorView) - : base (hostResources, editorView, editorView?.NeedsPropertyButton ?? false) + public EditorContainer (IHostResourceProvider hostResources, IEditorView editorView, bool? needsPropertyButton = null) + : base (hostResources, editorView, needsPropertyButton ?? editorView?.NeedsPropertyButton ?? false) { } diff --git a/Xamarin.PropertyEditing.Mac/Controls/TypeSelectorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/TypeSelectorControl.cs index e58ee32..d5574cb 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/TypeSelectorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/TypeSelectorControl.cs @@ -11,6 +11,25 @@ namespace Xamarin.PropertyEditing.Mac internal class TypeSelectorControl : NotifyingView<TypeSelectorViewModel> { + private bool flush; + public bool Flush { + get { return this.flush; } + set { + this.flush = value; + this.filterTop.Constant = this.flush ? 0: 10; + this.filterWidth.Constant = this.flush ? 0 : -20; + this.scrollTop.Constant = this.flush ? 0 : 8; + this.checkBoxBottom.Constant = this.flush ? -28 : -10; + this.checkBoxLeft.Constant = this.flush ? 8 : 0; + } + } + + private NSLayoutConstraint filterTop; + private NSLayoutConstraint filterWidth; + private NSLayoutConstraint scrollTop; + private NSLayoutConstraint checkBoxBottom; + private NSLayoutConstraint checkBoxLeft; + public TypeSelectorControl() { this.checkbox = NSButton.CreateCheckbox (Properties.Resources.ShowAllAssemblies, OnCheckedChanged); @@ -36,7 +55,7 @@ namespace Xamarin.PropertyEditing.Mac AddSubview (scroll); - this.filter = new NSTextField { + this.filter = new NSSearchField { TranslatesAutoresizingMaskIntoConstraints = false, PlaceholderString = "Filter" }; @@ -44,18 +63,24 @@ namespace Xamarin.PropertyEditing.Mac AddSubview (this.filter); + this.filterTop = NSLayoutConstraint.Create (this.filter, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1, 10); + this.filterWidth = NSLayoutConstraint.Create (this.filter, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1, -20); + this.scrollTop = NSLayoutConstraint.Create (scroll, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.filter, NSLayoutAttribute.Bottom, 1, 8); + this.checkBoxBottom = NSLayoutConstraint.Create (this.checkbox, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this, NSLayoutAttribute.Bottom, 1, -10); + this.checkBoxLeft = NSLayoutConstraint.Create (this.checkbox, NSLayoutAttribute.Left, NSLayoutRelation.Equal, scroll, NSLayoutAttribute.Left, 1, 0); + AddConstraints (new[] { - NSLayoutConstraint.Create (this.filter, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1, 10), - NSLayoutConstraint.Create (this.filter, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1, -20), + this.filterTop, + this.filterWidth, NSLayoutConstraint.Create (this.filter, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this, NSLayoutAttribute.CenterX, 1, 0), - NSLayoutConstraint.Create (scroll, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this.filter, NSLayoutAttribute.Bottom, 1, 8), + this.scrollTop, NSLayoutConstraint.Create (scroll, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this.filter, NSLayoutAttribute.Width, 1, 0), NSLayoutConstraint.Create (scroll, NSLayoutAttribute.CenterX, NSLayoutRelation.Equal, this, NSLayoutAttribute.CenterX, 1, 0), NSLayoutConstraint.Create (scroll, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this.checkbox, NSLayoutAttribute.Top, 1, -8), - NSLayoutConstraint.Create (this.checkbox, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this, NSLayoutAttribute.Bottom, 1, -10), - NSLayoutConstraint.Create (this.checkbox, NSLayoutAttribute.Left, NSLayoutRelation.Equal, scroll, NSLayoutAttribute.Left, 1, 0) + this.checkBoxBottom, + this.checkBoxLeft, }); } |