diff options
author | Dominique Louis <savagesoftware@gmail.com> | 2018-09-06 19:39:20 +0300 |
---|---|---|
committer | Dominique Louis <dominique@DIPRAJ1.northamerica.corp.microsoft.com> | 2019-05-01 17:28:53 +0300 |
commit | ed2c36589052687c65bfd5c969211d859c236c85 (patch) | |
tree | ff7e0b183680066e262a6c3e882721e5bd312ed8 /Xamarin.PropertyEditing.Mac/Controls | |
parent | f74e027bd387a82be39e9458ddea1d9edfefaa0a (diff) |
[Mac] Initial implementation of Autocompletion.dominique-Autocompletion
Diffstat (limited to 'Xamarin.PropertyEditing.Mac/Controls')
5 files changed, 203 insertions, 35 deletions
diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/AutoClosePopOver.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/AutoClosePopOver.cs index 7626277..e079f3f 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/AutoClosePopOver.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/AutoClosePopOver.cs @@ -1,19 +1,31 @@ -using System; +using System; using AppKit; namespace Xamarin.PropertyEditing.Mac { internal class AutoClosePopOver : NSPopover { - public AutoClosePopOver () : base () + private IHostResourceProvider hostResources; + + public bool CloseOnEnter { get; internal set; } + + public AutoClosePopOver (IHostResourceProvider hostResources) : base () { + if (hostResources == null) + throw new ArgumentNullException (nameof (hostResources)); + + this.hostResources = hostResources; + Behavior = NSPopoverBehavior.Semitransient; + CloseOnEnter = true; + + this.SetAppearance (this.hostResources.GetVibrantAppearance (EffectiveAppearance)); } public override void KeyUp (NSEvent theEvent) { // If Enter Kit, close the pop-up - if (theEvent.KeyCode == 36) { + if (theEvent.KeyCode == 36 && CloseOnEnter) { this.Close (); } } diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/AutocompleteComboBox.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/AutocompleteComboBox.cs new file mode 100644 index 0000000..a7b819f --- /dev/null +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/AutocompleteComboBox.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Reflection; +using AppKit; +using Foundation; +using ObjCRuntime; +using Xamarin.PropertyEditing.ViewModels; + +namespace Xamarin.PropertyEditing.Mac.Controls +{ + internal class AutocompleteComboBox : NSComboBox + { + private readonly PropertyViewModel viewModel; + private readonly PropertyInfo previewCustomExpressionPropertyInfo; + public PropertyInfo PreviewCustomExpressionPropertyInfo + { + get { return this.PreviewCustomExpressionPropertyInfo; } + set { + this.PreviewCustomExpressionPropertyInfo = value; + } + } + private ObservableCollectionEx<string> values; + + protected IHostResourceProvider HostResources { + get; + private set; + } + + public AutocompleteComboBox (IHostResourceProvider hostResources, PropertyViewModel viewModel, ObservableCollectionEx<string> values, PropertyInfo previewCustomExpressionPropertyInfo) + { + if (hostResources == null) + throw new ArgumentNullException (nameof (hostResources)); + + if (viewModel == null) + throw new ArgumentNullException (nameof (viewModel)); + + if (values == null) + throw new ArgumentNullException (nameof (values)); + + if (previewCustomExpressionPropertyInfo == null) + throw new ArgumentNullException (nameof (previewCustomExpressionPropertyInfo)); + + HostResources = hostResources; + + this.viewModel = viewModel; + this.values = values; + this.previewCustomExpressionPropertyInfo = previewCustomExpressionPropertyInfo; + + this.values.CollectionChanged += (sender, e) => { + switch (e.Action) { + case NotifyCollectionChangedAction.Add: + if (e.NewStartingIndex == -1 || e.NewItems == null) { + Reset (); + } else { + var items = e.NewItems; + int startIndex = e.NewStartingIndex; + if (startIndex != -1 && startIndex < items.Count) { + for (var i = 0; i < items.Count; i++) { + Insert (new NSString ((string)items[i]), startIndex); + startIndex++; + } + } else { + PopulateComboBoxItems (items); + } + } + break; + + case NotifyCollectionChangedAction.Remove: + if (e.OldStartingIndex == -1 || e.OldItems == null) { + Reset (); + } else { + var items = e.OldItems; + int startIndex = e.OldStartingIndex; + if (startIndex != -1 && startIndex < items.Count) { + for (var i = 0; i < items.Count; i++) { + RemoveAt (startIndex); + } + } + } + break; + + case NotifyCollectionChangedAction.Move: + case NotifyCollectionChangedAction.Replace: + case NotifyCollectionChangedAction.Reset: + Reset (); + break; + + default: + break; + } + }; + + // Maximum number of items in the drop-down before scrolling kicks in. + VisibleItems = 8; + + var selectorPopup = new Selector ("popUp:"); + + Changed += (sender, e) => { + if (!Cell.AccessibilityExpanded) { + Cell.PerformSelector (selectorPopup); + } + + UpdatePropertyInfo (); + }; + + UpdatePropertyInfo (); + + ViewDidChangeEffectiveAppearance (); + } + + private void Reset () + { + RemoveAll (); + PopulateComboBoxItems (this.values); + } + + private void PopulateComboBoxItems (IList items) + { + for (var i = 0; i < items.Count; i++) { + Add (new NSString (this.values[i])); + } + } + + public void UpdatePropertyInfo () + { + this.previewCustomExpressionPropertyInfo.SetValue (this.viewModel, StringValue); + } + } +} diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/BasePopOverControl.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/BasePopOverControl.cs index 708a832..d705b9e 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/BasePopOverControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/BasePopOverControl.cs @@ -1,4 +1,4 @@ -using System; +using System; using AppKit; using CoreGraphics; @@ -7,6 +7,7 @@ namespace Xamarin.PropertyEditing.Mac internal class BasePopOverControl : NSView { const int DefaultIconButtonSize = 32; + private readonly UnfocusableTextField viewTitle; public BasePopOverControl (IHostResourceProvider hostResources, string title, string imageNamed) : base () { @@ -30,13 +31,13 @@ namespace Xamarin.PropertyEditing.Mac AddSubview (iconView); - var viewTitle = new UnfocusableTextField { + this.viewTitle = new UnfocusableTextField { Font = NSFont.BoldSystemFontOfSize (11), StringValue = title, TranslatesAutoresizingMaskIntoConstraints = false, }; - AddSubview (viewTitle); + AddSubview (this.viewTitle); this.AddConstraints (new[] { NSLayoutConstraint.Create (iconView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 5f), @@ -44,12 +45,15 @@ namespace Xamarin.PropertyEditing.Mac NSLayoutConstraint.Create (iconView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, 1f, DefaultIconButtonSize), NSLayoutConstraint.Create (iconView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, DefaultIconButtonSize), - NSLayoutConstraint.Create (viewTitle, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 7f), - NSLayoutConstraint.Create (viewTitle, NSLayoutAttribute.Left, NSLayoutRelation.Equal, iconView, NSLayoutAttribute.Right, 1f, 5f), - //NSLayoutConstraint.Create (viewTitle, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this, NSLayoutAttribute.Left, 1f, 38f), - NSLayoutConstraint.Create (viewTitle, NSLayoutAttribute.Width, NSLayoutRelation.Equal, 1f, 120), - NSLayoutConstraint.Create (viewTitle, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 24), + NSLayoutConstraint.Create (this.viewTitle, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 7f), + NSLayoutConstraint.Create (this.viewTitle, NSLayoutAttribute.Left, NSLayoutRelation.Equal, iconView, NSLayoutAttribute.Right, 1f, 5f), + NSLayoutConstraint.Create (this.viewTitle, NSLayoutAttribute.Width, NSLayoutRelation.Equal, 1f, 120), + NSLayoutConstraint.Create (this.viewTitle, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, PropertyEditorControl.DefaultControlHeight), }); + + this.SetAppearance (hostResources.GetVibrantAppearance (EffectiveAppearance)); + + ViewDidChangeEffectiveAppearance (); } protected IHostResourceProvider HostResources @@ -57,5 +61,10 @@ namespace Xamarin.PropertyEditing.Mac get; private set; } + + public override void ViewDidChangeEffectiveAppearance () + { + this.viewTitle.TextColor = HostResources.GetNamedColor (NamedResources.DescriptionLabelColor); + } } } diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs index b831f5b..3e3347a 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs @@ -1,4 +1,4 @@ -using System; +using System; using AppKit; using CoreGraphics; using Xamarin.PropertyEditing.ViewModels; @@ -212,10 +212,12 @@ namespace Xamarin.PropertyEditing.Mac Appearance = EffectiveAppearance }; - var customExpressionPopOver = new AutoClosePopOver { + var customExpressionPopOver = new AutoClosePopOver(this.hostResources) { + CloseOnEnter = false, ContentViewController = new NSViewController (null, null) { View = customExpressionView }, }; - customExpressionPopOver.SetAppearance (this.hostResources.GetVibrantAppearance (EffectiveAppearance)); + + customExpressionView.PopOver = customExpressionPopOver; customExpressionPopOver.Show (customExpressionView.Frame, (NSView)this, NSRectEdge.MinYEdge); } @@ -226,10 +228,9 @@ namespace Xamarin.PropertyEditing.Mac Appearance = EffectiveAppearance }; - var resourceSelectorPopOver = new AutoClosePopOver { + var resourceSelectorPopOver = new AutoClosePopOver(this.hostResources) { ContentViewController = new NSViewController (null, null) { View = requestResourceView }, }; - resourceSelectorPopOver.SetAppearance (this.hostResources.GetVibrantAppearance (EffectiveAppearance)); requestResourceView.PopOver = resourceSelectorPopOver; diff --git a/Xamarin.PropertyEditing.Mac/Controls/CustomExpressionView.cs b/Xamarin.PropertyEditing.Mac/Controls/CustomExpressionView.cs index 49ed8b0..ed82e78 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/CustomExpressionView.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/CustomExpressionView.cs @@ -4,43 +4,57 @@ using AppKit; using CoreGraphics; using Foundation; using ObjCRuntime; +using Xamarin.PropertyEditing.Mac.Controls; using Xamarin.PropertyEditing.ViewModels; namespace Xamarin.PropertyEditing.Mac { internal class CustomExpressionView : BasePopOverViewModelControl { - Type vmType; - const string CustomExpressionPropertyString = "CustomExpression"; - PropertyInfo customExpressionPropertyInfo; + private const string CustomExpressionPropertyString = "CustomExpression"; + private const string PreviewCustomExpressionString = "PreviewCustomExpression"; + private const string AutocompleteItemsString = "AutocompleteItems"; + + public AutoClosePopOver PopOver { get; internal set; } public CustomExpressionView (IHostResourceProvider hostResources, PropertyViewModel viewModel) : base (hostResources, viewModel, Properties.Resources.CustomExpression, "pe-custom-expression-32") { Frame = new CGRect (CGPoint.Empty, new CGSize (250, 80)); - var customExpressionField = new NSTextField { - StringValue = string.Empty, - TranslatesAutoresizingMaskIntoConstraints = false, - }; + Type vmType = viewModel.GetType (); + + PropertyInfo previewCustomExpressionPropertyInfo = vmType.GetProperty (PreviewCustomExpressionString); + previewCustomExpressionPropertyInfo.SetValue (viewModel, string.Empty); + + PropertyInfo customExpressionPropertyInfo = vmType.GetProperty (CustomExpressionPropertyString); + var value = customExpressionPropertyInfo.GetValue (viewModel); + + NSControl editorControl = null; + PropertyInfo customAutocompleteItemsPropertyInfo = vmType.GetProperty (AutocompleteItemsString); + if (customAutocompleteItemsPropertyInfo.GetValue (viewModel) is ObservableCollectionEx<string> values) { + if (values != null && values.Count > 0) { + editorControl = new AutocompleteComboBox (hostResources, viewModel, values, previewCustomExpressionPropertyInfo); + } else { + editorControl = new NSTextField (); + } + } - this.vmType = viewModel.GetType (); - this.customExpressionPropertyInfo = vmType.GetProperty (CustomExpressionPropertyString); - var value = this.customExpressionPropertyInfo.GetValue (viewModel); - if (value != null) - customExpressionField.StringValue = (string)value; + editorControl.TranslatesAutoresizingMaskIntoConstraints = false; + editorControl.StringValue = (string)value ?? string.Empty; - customExpressionField.Activated += (sender, e) => { - this.customExpressionPropertyInfo.SetValue (viewModel, customExpressionField.StringValue); + editorControl.Activated += (sender, e) => { + PopOver.CloseOnEnter = true; + customExpressionPropertyInfo.SetValue (viewModel, editorControl.StringValue); }; - AddSubview (customExpressionField); + AddSubview (editorControl); this.AddConstraints (new[] { - NSLayoutConstraint.Create (customExpressionField, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 37f), - NSLayoutConstraint.Create (customExpressionField, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this, NSLayoutAttribute.Left, 1f, 38f), - NSLayoutConstraint.Create (customExpressionField, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1f, -57f), - NSLayoutConstraint.Create (customExpressionField, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, 18), + NSLayoutConstraint.Create (editorControl, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1f, 37f), + NSLayoutConstraint.Create (editorControl, NSLayoutAttribute.Left, NSLayoutRelation.Equal, this, NSLayoutAttribute.Left, 1f, 38f), + NSLayoutConstraint.Create (editorControl, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1f, -57f), + NSLayoutConstraint.Create (editorControl, NSLayoutAttribute.Height, NSLayoutRelation.Equal, 1f, PropertyEditorControl.DefaultControlHeight), }); } } |