Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/xamarin/Xamarin.PropertyEditing.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominique Louis <dominique@nirsingh-lap.fareast.corp.microsoft.com>2019-01-10 13:08:49 +0300
committerCartBlanche <savagesoftware@gmail.com>2019-06-26 21:12:35 +0300
commit820c53ae01fa95075fd3990f56a81a30e38e8312 (patch)
tree276edd87d93972381f5d6d245f1c7ceab68e3100 /Xamarin.PropertyEditing.Mac
parent50cbb497b21e77c752a808ff406db9ba47cff84f (diff)
[Mac] Initial Binding Editor Dialog.
Diffstat (limited to 'Xamarin.PropertyEditing.Mac')
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingEditorWindow.cs273
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingObjectSelectorControl.cs211
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingPathSelectorControl.cs337
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceSelectorControl.cs247
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingTypeSelectorControl.cs311
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/CreateValueConverterWindow.cs119
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BindingEditor/HeaderView.cs42
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/Custom/BasePanelWindow.cs301
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs23
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs36
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/TypeSelectorControl.cs2
-rw-r--r--Xamarin.PropertyEditing.Mac/PropertyTableDataSource.cs4
12 files changed, 1886 insertions, 20 deletions
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingEditorWindow.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingEditorWindow.cs
new file mode 100644
index 0000000..7e66a6b
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingEditorWindow.cs
@@ -0,0 +1,273 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using AppKit;
+using CoreGraphics;
+using Foundation;
+using Xamarin.PropertyEditing.Common;
+using Xamarin.PropertyEditing.ViewModels;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class BindingEditorWindow : BasePanelWindow
+ {
+ private readonly CreateBindingViewModel viewModel;
+ private readonly PropertyEditorSelector editorSelector = new PropertyEditorSelector ();
+
+ internal BindingEditorWindow (IHostResourceProvider hostResources, PropertyViewModel propertyViewModel)
+ {
+ this.viewModel = new CreateBindingViewModel (propertyViewModel.TargetPlatform, propertyViewModel.Editors.Single (), propertyViewModel.Property);
+
+ Title = this.viewModel.PropertyDisplay;
+ this.ButtonDone.Title = Properties.Resources.CreateBindingTitle;
+
+ foreach (BindingSource item in this.viewModel.BindingSources.Value) {
+ this.BindingTypePopup.Menu.AddItem (new NSMenuItem (item.Name) {
+ RepresentedObject = new NSObjectFacade (item)
+ });
+ }
+
+ this.BindingTypePopup.Activated += (o, e) => {
+ if (this.BindingTypePopup.Menu.HighlightedItem.RepresentedObject is NSObjectFacade facade) {
+ this.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;
+ }
+ };
+
+ RepopulateValueConverterPopup ();
+
+ this.AddConverterButton.Activated += (sender, e) => {
+ this.viewModel.SelectedValueConverter = CreateBindingViewModel.AddValueConverter;
+ };
+
+ var typeHeader = new HeaderView {
+ Title = Properties.Resources.Type,
+ };
+
+ this.AncestorTypeBox.AddSubview (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),
+ });
+
+ var typeSelectorControl = new TypeSelectorControl {
+ Hidden = true,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ this.AncestorTypeBox.AddSubview (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)
+ });
+
+ var resourceSelectorControl = new BindingResourceSelectorControl (this.viewModel) {
+ Hidden = true,
+ };
+
+ 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)
+ });
+
+ var objectSelectorControl = new BindingObjectSelectorControl (this.viewModel) {
+ Hidden = true,
+ };
+
+ 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)
+ });
+
+ var longDescription = new UnfocusableTextField {
+ Alignment = NSTextAlignment.Left,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ StringValue = string.Empty,
+ };
+
+ this.AncestorTypeBox.AddSubview (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),
+ });
+
+ var pathHeader = new HeaderView {
+ Title = Properties.Resources.Path,
+ };
+
+ this.PathBox.AddSubview (pathHeader);
+
+ 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),
+ });
+
+ var pathSelectorControl = new BindingPathSelectorControl (this.viewModel);
+
+ this.PathBox.AddSubview (pathSelectorControl);
+
+ 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;
+ }
+
+ if (e.PropertyName == nameof (CreateBindingViewModel.ShowObjectSelector)) {
+ if (this.viewModel.ShowObjectSelector) {
+ typeHeader.Title = Properties.Resources.SelectObjectTitle;
+ }
+ }
+
+ if (e.PropertyName == nameof (CreateBindingViewModel.ShowTypeSelector)) {
+ typeSelectorControl.Hidden = !this.viewModel.ShowTypeSelector;
+
+ if (this.viewModel.ShowTypeSelector) {
+ typeHeader.Title = Properties.Resources.SelectTypeTitle;
+
+ if (this.viewModel.ShowTypeSelector && this.viewModel.TypeSelector != null) {
+ typeSelectorControl.ViewModel = this.viewModel.TypeSelector;
+ }
+ }
+ }
+
+ if (e.PropertyName == nameof (CreateBindingViewModel.ShowResourceSelector)) {
+ if (this.viewModel.ShowResourceSelector) {
+ typeHeader.Title = Properties.Resources.SelectResourceTitle;
+ }
+ }
+
+ if (e.PropertyName == nameof (CreateBindingViewModel.SelectedValueConverter)) {
+ RepopulateValueConverterPopup ();
+ }
+ };
+
+ this.viewModel.CreateValueConverterRequested += OnCreateValueConverterRequested;
+
+ this.ButtonDone.Activated += (sender, e) => {
+ if (pathSelectorControl.CustomPath.Enabled && !string.IsNullOrEmpty (pathSelectorControl.CustomPath.Cell.Title)) {
+ this.viewModel.Path = pathSelectorControl.CustomPath.Cell.Title;
+ }
+
+ Close ();
+ };
+
+ // More Settings
+ var controlTop = 6;
+ var identifier = "BindingProperties";
+
+ foreach (PropertyViewModel vm in this.viewModel.BindingProperties) {
+ IEditorView editor = this.editorSelector.GetEditor (hostResources, vm);
+
+ NSView nSView = new EditorContainer (hostResources, editor) {
+ Identifier = identifier,
+ Label = vm.Property.Name,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ ViewModel = vm,
+ };
+
+ 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),
+ });
+
+ controlTop += PropertyEditorControl.DefaultControlHeight;
+ }
+
+ var boundsHeight = controlTop;
+
+ controlTop = 9;
+ identifier = "FlagsProperties";
+ foreach (PropertyViewModel vm in this.viewModel.FlagsProperties) {
+
+ IEditorView editor = this.editorSelector.GetEditor (hostResources, vm);
+
+ NSView nSView = new EditorContainer (hostResources, editor) {
+ Identifier = identifier,
+ Label = vm.Property.Name,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ ViewModel = vm,
+ };
+
+ 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),
+ });
+
+ controlTop += PropertyEditorControl.DefaultControlHeight;
+ }
+
+ if (boundsHeight < controlTop)
+ boundsHeight = controlTop;
+
+ this.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) {
+ RepresentedObject = new NSObjectFacade (item)
+ });
+ }
+ }
+
+ private void OnCreateValueConverterRequested (object sender, CreateValueConverterEventArgs e)
+ {
+ ITypeInfo valueConverter = this.viewModel.TargetPlatform.EditorProvider.KnownTypes[typeof (CommonValueConverter)];
+
+ var typesTask = this.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 result = (NSModalResponse)(int)NSApplication.SharedApplication.RunModalForWindow (createValueConverterWindow);
+ if (result == NSModalResponse.OK) {
+ if (createValueConverterWindow.ViewModel.SelectedType != null) {
+ e.Name = createValueConverterWindow.ValueConverterName;
+ e.ConverterType = createValueConverterWindow.ViewModel.SelectedType;
+ e.Source = createValueConverterWindow.ViewModel.Source;
+ }
+ }
+ }
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingObjectSelectorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingObjectSelectorControl.cs
new file mode 100644
index 0000000..9022c37
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingObjectSelectorControl.cs
@@ -0,0 +1,211 @@
+using System;
+using System.Collections.Generic;
+using AppKit;
+using Foundation;
+using Xamarin.PropertyEditing.ViewModels;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class BindingObjectSelectorControl : NSView
+ {
+ 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);
+ }
+ }
+ }
+
+ public ObjectOutlineView ()
+ {
+ Initialize ();
+ }
+
+ // Called when created from unmanaged code
+ public ObjectOutlineView (IntPtr handle) : base (handle)
+ {
+ Initialize ();
+ }
+
+ // Called when created directly from a XIB file
+ [Export ("initWithCoder:")]
+ public ObjectOutlineView (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 ObjectOutlineViewDelegate : NSOutlineViewDelegate
+ {
+ private ObjectOutlineViewDataSource dataSource;
+
+ public ObjectOutlineViewDelegate (ObjectOutlineViewDataSource 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 ObjectOutlineViewDataSource : NSOutlineViewDataSource
+ {
+ 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;
+ }
+ }
+
+ 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 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 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
new file mode 100644
index 0000000..0123d7b
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingPathSelectorControl.cs
@@ -0,0 +1,337 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using AppKit;
+using Foundation;
+using Xamarin.PropertyEditing.ViewModels;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class PathOutlineView : NSOutlineView
+ {
+ 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 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 PathOutlineView ()
+ {
+ Initialize ();
+ }
+
+ // Called when created from unmanaged code
+ public PathOutlineView (IntPtr handle) : base (handle)
+ {
+ Initialize ();
+ }
+
+ // Called when created directly from a XIB file
+ [Export ("initWithCoder:")]
+ public PathOutlineView (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 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;
+ }
+
+ 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;
+ }
+ }
+
+ 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; }
+
+ public BindingPathSelectorControl (CreateBindingViewModel viewModel)
+ {
+ TranslatesAutoresizingMaskIntoConstraints = false;
+
+ var customCheckBox = new NSButton {
+ ControlSize = NSControlSize.Small,
+ Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize),
+ Title = Properties.Resources.Custom,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ 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.customPath = new NSTextField {
+ ControlSize = NSControlSize.Mini,
+ Enabled = false,
+ Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize),
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ var customPathHeightConstraint = NSLayoutConstraint.Create (this.customPath, 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),
+ customPathHeightConstraint,
+ });
+
+ // create a table view and a scroll view
+ var outlineViewContainer = new NSScrollView {
+ 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.customPath.Changed += (sender, e) => {
+ viewModel.Path = this.customPath.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);
+ }
+ }
+ }
+ };
+
+ var pathColumn = new NSTableColumn (PathSelectorColumnColId);
+ this.pathOutlineView.AddColumn (pathColumn);
+
+ // Set OutlineTableColumn or the arrows showing children/expansion will not be drawn
+ this.pathOutlineView.OutlineTableColumn = pathColumn;
+
+ // add the panel to the window
+ outlineViewContainer.DocumentView = this.pathOutlineView;
+ AddSubview (outlineViewContainer);
+
+ 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),
+ });
+
+ viewModel.PropertyChanged += async (sender, e) => {
+ if (viewModel.PropertyRoot != null) {
+ this.pathOutlineView.PropertyTreeRoot = await viewModel.PropertyRoot.Task;
+ } else {
+ this.pathOutlineView.PropertyTreeRoot = null;
+ }
+ };
+ }
+
+ private void SetCustomPath (CreateBindingViewModel viewModel)
+ {
+ this.customPath.StringValue = this.customPath.Enabled ? viewModel.Path ?? string.Empty : string.Empty;
+ }
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceSelectorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceSelectorControl.cs
new file mode 100644
index 0000000..afcf746
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingResourceSelectorControl.cs
@@ -0,0 +1,247 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using AppKit;
+using Foundation;
+using Xamarin.PropertyEditing.ViewModels;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class BindingResourceSelectorControl : NSView
+ {
+ 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);
+ }
+ }
+ }
+
+ 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 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
+ {
+ public ILookup<ResourceSource, Resource> ViewModel { get; }
+
+ internal ResourceOutlineViewDataSource (ILookup<ResourceSource, Resource> 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 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;
+ }
+ }
+ }
+ }
+ };
+
+ var resourceColumn = new NSTableColumn (ResourceSelectorColId);
+ this.resourceOutlineView.AddColumn (resourceColumn);
+
+ // Set OutlineTableColumn or the arrows showing children/expansion will not be drawn
+ this.resourceOutlineView.OutlineTableColumn = resourceColumn;
+
+ // create a table view and a scroll view
+ var outlineViewContainer = new NSScrollView {
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ // add the panel to the window
+ outlineViewContainer.DocumentView = this.resourceOutlineView;
+ 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),
+ });
+
+ viewModel.PropertyChanged += (sender, e) => {
+ if (e.PropertyName == nameof (CreateBindingViewModel.ShowResourceSelector)) {
+ Hidden = !viewModel.ShowResourceSelector;
+
+ if (viewModel.ShowResourceSelector && viewModel.SourceResources != null) {
+ this.resourceOutlineView.ViewModel = viewModel.SourceResources.Value;
+ };
+ }
+ };
+ }
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingTypeSelectorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingTypeSelectorControl.cs
new file mode 100644
index 0000000..bbfebc9
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/BindingTypeSelectorControl.cs
@@ -0,0 +1,311 @@
+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
new file mode 100644
index 0000000..6415ae6
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/CreateValueConverterWindow.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using AppKit;
+using CoreGraphics;
+using Foundation;
+using Xamarin.PropertyEditing.ViewModels;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class CreateValueConverterWindow : NSWindow
+ {
+ public AddValueConverterViewModel ViewModel { get; }
+
+ private NSTextField valueConverterName;
+ public string ValueConverterName {
+ get { return this.valueConverterName.Cell.Title; }
+ }
+
+ public CreateValueConverterWindow (CreateBindingViewModel viewModel, AsyncValue<IReadOnlyDictionary<IAssemblyInfo, ILookup<string, ITypeInfo>>> typetasks)
+ {
+ if (viewModel == null)
+ throw new ArgumentNullException (nameof (viewModel));
+
+ ViewModel = new AddValueConverterViewModel (viewModel.TargetPlatform, viewModel.Target, typetasks);
+
+ StyleMask |= NSWindowStyle.Resizable;
+
+ Title = Properties.Resources.AddValueConverterTitle;
+
+ MaxSize = new CGSize (500, 560); // TODO discuss what the Max/Min Size should be and if we should have one.
+ MinSize = new CGSize (200, 320);
+
+ var container = new NSView (new CGRect (CGPoint.Empty, new CGSize (400, 400))) {
+ TranslatesAutoresizingMaskIntoConstraints = false
+ };
+
+ var valueConverterLabel = new UnfocusableTextField {
+ 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),
+ });
+
+ this.valueConverterName = new NSTextField {
+ ControlSize = NSControlSize.Small,
+ 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),
+ });
+
+ var typeSelectorControl = new TypeSelectorControl {
+ ViewModel = ViewModel,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ 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)
+ });
+
+ var buttonDone = new NSButton {
+ BezelStyle = NSBezelStyle.Rounded,
+ Highlighted = true,
+ KeyEquivalent = "\r", // Fire when enter pressed
+ Title = Properties.Resources.DoneTitle,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ buttonDone.Activated += (sender, e) => {
+ NSApplication.SharedApplication.StopModalWithCode ((int)NSModalResponse.OK);
+ Close ();
+ };
+
+ container.AddSubview (buttonDone);
+
+ 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),
+ });
+
+ ContentViewController = new NSViewController (null, null) {
+ View = container,
+ };
+
+ ViewModel.PropertyChanged += (sender, e) => {
+ if (e.PropertyName == nameof (ViewModel.SelectedType)) {
+ this.valueConverterName.StringValue = ViewModel.SelectedType.Name;
+ }
+ };
+ }
+
+ public override void KeyUp (NSEvent theEvent)
+ {
+ if (theEvent.KeyCode == 53) {
+ NSApplication.SharedApplication.StopModalWithCode ((int)NSModalResponse.Cancel);
+ Close ();
+ } else {
+ base.KeyUp (theEvent);
+ }
+ }
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/HeaderView.cs b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/HeaderView.cs
new file mode 100644
index 0000000..5fb377b
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/BindingEditor/HeaderView.cs
@@ -0,0 +1,42 @@
+using System;
+using AppKit;
+using CoreAnimation;
+using CoreGraphics;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class HeaderView : NSView
+ {
+ public string Title
+ {
+ get { return this.headerText.StringValue; }
+ set { this.headerText.StringValue = value; }
+ }
+
+ private UnfocusableTextField headerText = new UnfocusableTextField ();
+
+ internal HeaderView ()
+ {
+ TranslatesAutoresizingMaskIntoConstraints = false;
+ WantsLayer = true;
+
+ // 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),
+ BorderWidth = 1,
+ };
+
+ this.headerText.Alignment = NSTextAlignment.Center;
+ this.headerText.TranslatesAutoresizingMaskIntoConstraints = false;
+
+ 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),
+ });
+ }
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/BasePanelWindow.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/BasePanelWindow.cs
new file mode 100644
index 0000000..d22ea4b
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/BasePanelWindow.cs
@@ -0,0 +1,301 @@
+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/PropertyButton.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs
index 3e3347a..2533d97 100644
--- a/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs
+++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs
@@ -107,10 +107,25 @@ namespace Xamarin.PropertyEditing.Mac
this.popUpContextMenu.AddItem (mi2);
}
+ if (this.viewModel.SupportsBindings) {
+ this.popUpContextMenu.AddItem (NSMenuItem.SeparatorItem);
+
+ var mi3 = new NSMenuItem (Properties.Resources.CreateDataBindingMenuItem) {
+ 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);
// TODO If we add more menu items consider making the Label/Command a dictionary that we can iterate over to populate everything.
- this.popUpContextMenu.AddItem (new CommandMenuItem (Properties.Resources.Reset, viewModel.ClearValueCommand) {
+ this.popUpContextMenu.AddItem (new CommandMenuItem (Properties.Resources.Reset, this.viewModel.ClearValueCommand) {
AttributedTitle = new Foundation.NSAttributedString (
Properties.Resources.Reset,
new CoreText.CTStringAttributes {
@@ -236,5 +251,11 @@ namespace Xamarin.PropertyEditing.Mac
resourceSelectorPopOver.Show (requestResourceView.Frame, (NSView)this, NSRectEdge.MinYEdge);
}
+
+ private void OnBindingRequested (object sender, EventArgs e)
+ {
+ var bindingEditorWindow = new BindingEditorWindow (this.hostResources, this.viewModel);
+ bindingEditorWindow.MakeKeyAndOrderFront (this);
+ }
}
}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs
index 4b1e9b4..aff0ae5 100644
--- a/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs
+++ b/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs
@@ -75,23 +75,25 @@ namespace Xamarin.PropertyEditing.Mac
public void UpdateKeyViews ()
{
- nint row = TableView.RowForView (this);
- if (row <= 0)
- return;
-
- NSView view;
- PropertyEditorControl ctrl = null;
- do {
- row--;
- view = TableView.GetView (0, row, makeIfNecessary: false);
- ctrl = (view as EditorContainer)?.EditorView?.NativeView as PropertyEditorControl;
- } while (row > 0 && ctrl == null);
-
- if (ctrl != null) {
- ctrl.LastKeyView.NextKeyView = FirstKeyView;
- ctrl.UpdateKeyViews ();
- } else if (row == 0 && view is PanelHeaderEditorControl header) {
- header.SetNextKeyView (FirstKeyView);
+ if (TableView != null) {
+ nint row = TableView.RowForView (this);
+ if (row <= 0)
+ return;
+
+ NSView view;
+ PropertyEditorControl ctrl = null;
+ do {
+ row--;
+ view = TableView.GetView (0, row, makeIfNecessary: false);
+ ctrl = (view as EditorContainer)?.EditorView?.NativeView as PropertyEditorControl;
+ } while (row > 0 && ctrl == null);
+
+ if (ctrl != null) {
+ ctrl.LastKeyView.NextKeyView = FirstKeyView;
+ ctrl.UpdateKeyViews ();
+ } else if (row == 0 && view is PanelHeaderEditorControl header) {
+ header.SetNextKeyView (FirstKeyView);
+ }
}
}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/TypeSelectorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/TypeSelectorControl.cs
index 747ca64..e58ee32 100644
--- a/Xamarin.PropertyEditing.Mac/Controls/TypeSelectorControl.cs
+++ b/Xamarin.PropertyEditing.Mac/Controls/TypeSelectorControl.cs
@@ -109,6 +109,8 @@ namespace Xamarin.PropertyEditing.Mac
for (int i = 0; i < this.outlineView.RowCount; i++) {
this.outlineView.ExpandItem (this.outlineView.ItemAtRow (i));
}
+ } else {
+ this.outlineView.ExpandItem (null, true);
}
}
diff --git a/Xamarin.PropertyEditing.Mac/PropertyTableDataSource.cs b/Xamarin.PropertyEditing.Mac/PropertyTableDataSource.cs
index 39e4f63..c5bada9 100644
--- a/Xamarin.PropertyEditing.Mac/PropertyTableDataSource.cs
+++ b/Xamarin.PropertyEditing.Mac/PropertyTableDataSource.cs
@@ -37,10 +37,10 @@ namespace Xamarin.PropertyEditing.Mac
var facade = (NSObjectFacade)item;
if (facade?.Target is ObjectPropertyViewModel ovm)
return ovm.ValueModel.Properties.Count;
-
+
int headerCount = (ShowHeader && !Filtering) ? 1 : 0;
- int childCount;
+ nint childCount;
if (this.vm.ArrangeMode == PropertyArrangeMode.Name)
childCount = this.vm.ArrangedEditors[0].Editors.Count + headerCount;
else {