diff options
author | Bret Johnson <bret.johnson@microsoft.com> | 2022-03-01 18:15:41 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-01 18:15:41 +0300 |
commit | 67538aec107829384f0d13e64bb669574ba14bb5 (patch) | |
tree | 3b61f95fe7d20b0937aa0bfb181ef82243839d0c | |
parent | 32e42632f42dba9fb38f326dcc4e14ca19f9568b (diff) | |
parent | 2ca79fd2bc386f01aacbe81119475c540863cb3e (diff) |
Merge pull request #796 from xamarin/backport-pr-792-to-main
[main] Reimplementation UpdateKeyViews() based in ProxyRowResponder
26 files changed, 310 insertions, 70 deletions
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BasePathEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BasePathEditorControl.cs index 923281e..f7f0d39 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/BasePathEditorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/BasePathEditorControl.cs @@ -23,11 +23,35 @@ namespace Xamarin.PropertyEditing.Mac private readonly NSObject[] objects;
public override NSObject[] AccessibilityChildren { get => this.objects; }
+ private readonly DelegatedRowTextFieldDelegate textNextResponderDelegate; + + class BasePathEditorDelegate : DelegatedRowTextFieldDelegate + { + WeakReference<BasePathEditorControl<T>> weakView; + + public BasePathEditorDelegate (BasePathEditorControl<T> basePathEditorControl) + { + weakView = new WeakReference<BasePathEditorControl<T>>(basePathEditorControl); + } + + public override void Changed (NSNotification notification) + { + if (this.weakView.TryGetTarget(out BasePathEditorControl<T> t)) { + t.StoreCurrentValue (); + } + } + } + protected BasePathEditorControl (IHostResourceProvider hostResource)
: base (hostResource)
{
this.currentTextField = new TextFieldSmallButtonContainer ();
- this.currentTextField.Changed += CurrentTextField_Changed; + + this.textNextResponderDelegate = new BasePathEditorDelegate (this) + { + ProxyResponder = new ProxyResponder (this, ProxyRowType.SingleView) + }; + this.currentTextField.Delegate = this.textNextResponderDelegate; AddSubview (this.currentTextField); #region Reveal handler
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BasePointEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BasePointEditorControl.cs index e60f5f4..7193566 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/BasePointEditorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/BasePointEditorControl.cs @@ -28,6 +28,7 @@ namespace Xamarin.PropertyEditing.Mac BackgroundColor = NSColor.Clear, Value = 0.0f }; + XEditor.ProxyResponder = new ProxyResponder (this, ProxyRowType.FirstView); XEditor.ValueChanged += OnInputUpdated; YLabel = new UnfocusableTextField { @@ -39,6 +40,7 @@ namespace Xamarin.PropertyEditing.Mac BackgroundColor = NSColor.Clear, Value = 0.0f }; + YEditor.ProxyResponder = new ProxyResponder (this, ProxyRowType.LastView); YEditor.ValueChanged += OnInputUpdated; AddSubview (XLabel); diff --git a/Xamarin.PropertyEditing.Mac/Controls/BaseRectangleEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BaseRectangleEditorControl.cs index 005ef89..68406a1 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/BaseRectangleEditorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/BaseRectangleEditorControl.cs @@ -33,6 +33,7 @@ namespace Xamarin.PropertyEditing.Mac BackgroundColor = NSColor.Clear, Value = 0.0f }; + XEditor.ProxyResponder = new ProxyResponder (this, ProxyRowType.FirstView); XEditor.ValueChanged += OnInputUpdated; YLabel = new UnfocusableTextField { @@ -63,6 +64,7 @@ namespace Xamarin.PropertyEditing.Mac BackgroundColor = NSColor.Clear, Value = 0.0f }; + HeightEditor.ProxyResponder = new ProxyResponder (this, ProxyRowType.LastView); HeightEditor.ValueChanged += OnInputUpdated; AddSubview (XLabel); diff --git a/Xamarin.PropertyEditing.Mac/Controls/BooleanEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BooleanEditorControl.cs index d9541a6..b6c1ca5 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/BooleanEditorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/BooleanEditorControl.cs @@ -11,7 +11,10 @@ namespace Xamarin.PropertyEditing.Mac public BooleanEditorControl (IHostResourceProvider hostResource)
: base (hostResource) { - BooleanEditor = new FocusableBooleanButton (); + BooleanEditor = new FocusableBooleanButton () + { + ProxyResponder = new ProxyResponder (this, ProxyRowType.SingleView) + }; BooleanEditor.Title = string.Empty; // update the value on 'enter' diff --git a/Xamarin.PropertyEditing.Mac/Controls/BrushEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BrushEditorControl.cs index 53b5513..799a91d 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/BrushEditorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/BrushEditorControl.cs @@ -56,6 +56,7 @@ namespace Xamarin.PropertyEditing.Mac ControlSize = NSControlSize.Small, Font = NSFont.SystemFontOfSize (NSFont.SystemFontSizeForControlSize (NSControlSize.Small)), TranslatesAutoresizingMaskIntoConstraints = false, + ProxyResponder = new ProxyResponder (this, ProxyRowType.SingleView) }; this.popupButtonList = new NSMenu (); diff --git a/Xamarin.PropertyEditing.Mac/Controls/CharEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/CharEditorControl.cs index f68457d..e1eb1b6 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/CharEditorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/CharEditorControl.cs @@ -13,7 +13,11 @@ namespace Xamarin.PropertyEditing.Mac protected override EntryPropertyEditorDelegate<char> CreateDelegate (PropertyViewModel<char> viewModel) { - return new CharDelegate (viewModel); + var charDelegate = new CharDelegate (viewModel) + { + ProxyResponder = new ProxyResponder (this, ProxyRowType.SingleView) + }; + return charDelegate; } protected override void UpdateAccessibilityValues () diff --git a/Xamarin.PropertyEditing.Mac/Controls/CollectionInlineEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/CollectionInlineEditorControl.cs index 00608b1..0bdcabb 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/CollectionInlineEditorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/CollectionInlineEditorControl.cs @@ -24,6 +24,7 @@ namespace Xamarin.PropertyEditing.Mac Title = Properties.Resources.CollectionEditButton, BezelStyle = NSBezelStyle.Rounded, AccessibilityEnabled = true, + ProxyResponder = new ProxyResponder (this, ProxyRowType.SingleView), AccessibilityHelp = Properties.Resources.AccessibilityCollectionHelp }; diff --git a/Xamarin.PropertyEditing.Mac/Controls/CombinablePropertyEditor.cs b/Xamarin.PropertyEditing.Mac/Controls/CombinablePropertyEditor.cs index 5122f24..c2ce8a5 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/CombinablePropertyEditor.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/CombinablePropertyEditor.cs @@ -83,8 +83,21 @@ namespace Xamarin.PropertyEditing.Mac } // Set our tabable order - this.firstKeyView = this.combinableList.KeyAt (0); - this.lastKeyView = this.combinableList.KeyAt (this.combinableList.Count - 1); + var firstButton = (FocusableBooleanButton) this.combinableList.KeyAt (0); + this.firstKeyView = firstButton; + + var lastButton = (FocusableBooleanButton)this.combinableList.KeyAt (this.combinableList.Count - 1); + this.lastKeyView = lastButton; + + if (combinableList.Count > 0) + { + if (firstButton == lastButton) { + firstButton.ProxyResponder = new ProxyResponder (this, ProxyRowType.SingleView); + } else { + firstButton.ProxyResponder = new ProxyResponder (this, ProxyRowType.FirstView); + lastButton.ProxyResponder = new ProxyResponder (this, ProxyRowType.LastView); + } + } SetEnabled (); diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusableBooleanButton.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusableBooleanButton.cs index f8ed20d..8548985 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusableBooleanButton.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusableBooleanButton.cs @@ -3,7 +3,7 @@ using AppKit; namespace Xamarin.PropertyEditing.Mac { - internal class FocusableBooleanButton : NSButton + internal class FocusableBooleanButton : ProxyResponderButton { public override bool CanBecomeKeyView { get { return Enabled; } } diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusableButton.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusableButton.cs index 9e3366d..9d7476d 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusableButton.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusableButton.cs @@ -3,7 +3,7 @@ using AppKit; namespace Xamarin.PropertyEditing.Mac { - internal class FocusableButton : NSButton + internal class FocusableButton : ProxyResponderButton { public override bool CanBecomeKeyView { get { return Enabled; } } diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusableComboBox.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusableComboBox.cs index 577ce4b..b1f5eaa 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusableComboBox.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusableComboBox.cs @@ -5,6 +5,25 @@ namespace Xamarin.PropertyEditing.Mac { internal class FocusableComboBox : NSComboBox { + public ProxyResponder ProxyResponder { get; set; } + + public override void KeyDown (NSEvent theEvent) + { + switch (theEvent.KeyCode) { + case (int)NSKey.Tab: + if (ProxyResponder != null) { + if (theEvent.ModifierFlags.HasFlag(NSEventModifierMask.ShiftKeyMask)) { + ProxyResponder.PreviousResponder (); + } else { + ProxyResponder.NextResponder (); + } + return; + } + break; + } + base.KeyDown (theEvent); + } + public override bool BecomeFirstResponder () { var willBecomeFirstResponder = base.BecomeFirstResponder (); diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusablePopupButton.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusablePopupButton.cs index 988dc2b..7d1bc6c 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusablePopupButton.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/FocusablePopupButton.cs @@ -8,11 +8,30 @@ namespace Xamarin.PropertyEditing.Mac { public override bool CanBecomeKeyView { get { return Enabled; } } + public ProxyResponder ProxyResponder { get; set; } + public FocusablePopUpButton () { Cell.LineBreakMode = NSLineBreakMode.TruncatingMiddle; } + public override void KeyDown (NSEvent theEvent) + { + switch (theEvent.KeyCode) { + case (int)NSKey.Tab: + if (ProxyResponder != null) { + if (theEvent.ModifierFlags.HasFlag(NSEventModifierMask.ShiftKeyMask)) { + ProxyResponder.PreviousResponder (); + } else { + ProxyResponder.NextResponder (); + } + return; + } + break; + } + base.KeyDown (theEvent); + } + public override bool BecomeFirstResponder () { var willBecomeFirstResponder = base.BecomeFirstResponder (); diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericSpinEditor.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericSpinEditor.cs index de6f661..9da66b9 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericSpinEditor.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericSpinEditor.cs @@ -172,6 +172,12 @@ namespace Xamarin.PropertyEditing.Mac set { this.numericEditor.AccessibilityTitle = value; } } + public ProxyResponder ProxyResponder + { + get => this.numericEditor.ProxyResponder; + set => this.numericEditor.ProxyResponder = value; + } + public virtual void Reset () { } diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericTextField.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericTextField.cs index 4c215b7..9e00331 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericTextField.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericTextField.cs @@ -51,6 +51,19 @@ namespace Xamarin.PropertyEditing.Mac Delegate = keyUpDownDelegate; } + public ProxyResponder ProxyResponder + { + get { + return Delegate is KeyUpDownDelegate viewDownDelegate ? viewDownDelegate.ProxyResponder : null; + } + set + { + if (Delegate is KeyUpDownDelegate keydown) { + keydown.ProxyResponder = value; + } + } + } + public override CGSize IntrinsicContentSize => new CGSize(30, 20); public override bool ShouldBeginEditing (NSText textObject) @@ -156,28 +169,35 @@ namespace Xamarin.PropertyEditing.Mac } } - internal class KeyUpDownDelegate : NSTextFieldDelegate + internal class KeyUpDownDelegate : DelegatedRowTextFieldDelegate { public event EventHandler<bool> KeyArrowUp; public event EventHandler<bool> KeyArrowDown; public override bool DoCommandBySelector (NSControl control, NSTextView textView, Selector commandSelector) { + //if parent already handles command we break the event chain + var parentHandlesCommand = base.DoCommandBySelector (control, textView, commandSelector); + if (parentHandlesCommand) + { + return false; + } + switch (commandSelector.Name) { - case "moveUp:": - OnKeyArrowUp (); - break; - case "moveDown:": - OnKeyArrowDown (); - break; - case "moveUpAndModifySelection:": - OnKeyArrowUp (true); - break; - case "moveDownAndModifySelection:": - OnKeyArrowDown (true); - break; - default: - return false; + case "moveUp:": + OnKeyArrowUp (); + break; + case "moveDown:": + OnKeyArrowDown (); + break; + case "moveUpAndModifySelection:": + OnKeyArrowUp (true); + break; + case "moveDownAndModifySelection:": + OnKeyArrowDown (true); + break; + default: + return false; } return true; diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/ProxyResponderButton.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/ProxyResponderButton.cs new file mode 100644 index 0000000..a37479f --- /dev/null +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/ProxyResponderButton.cs @@ -0,0 +1,26 @@ +using AppKit; + +namespace Xamarin.PropertyEditing.Mac +{ + internal class ProxyResponderButton : NSButton + { + public ProxyResponder ProxyResponder { get; set; } + + public override void KeyDown (NSEvent theEvent) + { + switch (theEvent.KeyCode) { + case (int)NSKey.Tab: + if (ProxyResponder != null) { + if (theEvent.ModifierFlags.HasFlag(NSEventModifierMask.ShiftKeyMask)) { + ProxyResponder.PreviousResponder (); + } else { + ProxyResponder.NextResponder (); + } + return; + } + break; + } + base.KeyDown (theEvent); + } + } +} diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/TextFieldSmallButtonContainer.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/TextFieldSmallButtonContainer.cs index 0dbeb28..99e35e2 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/TextFieldSmallButtonContainer.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/TextFieldSmallButtonContainer.cs @@ -6,7 +6,7 @@ using Foundation; namespace Xamarin.PropertyEditing.Mac { - internal class SmallButton : NSButton + internal class SmallButton : ProxyResponderButton { private NSView previousKeyView; public override NSView PreviousKeyView => this.previousKeyView ?? base.PreviousKeyView; diff --git a/Xamarin.PropertyEditing.Mac/Controls/EntryPropertyEditor.cs b/Xamarin.PropertyEditing.Mac/Controls/EntryPropertyEditor.cs index f1d92ac..d6d7e1d 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/EntryPropertyEditor.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/EntryPropertyEditor.cs @@ -2,9 +2,35 @@ using System; using AppKit; using Foundation; using Xamarin.PropertyEditing.ViewModels; +using ObjCRuntime; namespace Xamarin.PropertyEditing.Mac { + class DelegatedRowTextFieldDelegate : NSTextFieldDelegate + { + public ProxyResponder ProxyResponder { get; set; } + + public override bool DoCommandBySelector (NSControl control, NSTextView textView, Selector commandSelector) + { + if (ProxyResponder != null) + { + switch (commandSelector.Name) { + case "insertTab:": + if (ProxyResponder.NextResponder ()) { + return true; + } + break; + case "insertBacktab:": + if (ProxyResponder.PreviousResponder ()) { + return true; + } + break; + } + } + return false; + } + } + internal abstract class EntryPropertyEditor<T> : PropertyEditorControl<PropertyViewModel<T>> { @@ -19,6 +45,11 @@ namespace Xamarin.PropertyEditing.Mac }; AddSubview (Entry); + Entry.Delegate = new DelegatedRowTextFieldDelegate () + { + ProxyResponder = new ProxyResponder(this, ProxyRowType.SingleView) + }; + RightEdgeConstraint = NSLayoutConstraint.Create (Entry, NSLayoutAttribute.Right, NSLayoutRelation.Equal, this, NSLayoutAttribute.Right, 1f, 0); AddConstraints (new[] { NSLayoutConstraint.Create (Entry, NSLayoutAttribute.CenterY, NSLayoutRelation.Equal, this, NSLayoutAttribute.CenterY, 1f, 0), @@ -61,7 +92,11 @@ namespace Xamarin.PropertyEditing.Mac protected virtual EntryPropertyEditorDelegate<T> CreateDelegate (PropertyViewModel<T> viewModel) { - return new EntryPropertyEditorDelegate<T> (viewModel); + var propertyEditorDelegate = new EntryPropertyEditorDelegate<T> (viewModel) + { + ProxyResponder = new ProxyResponder (this, ProxyRowType.SingleView) + }; + return propertyEditorDelegate; } protected virtual string GetValue (T value) @@ -71,7 +106,7 @@ namespace Xamarin.PropertyEditing.Mac } internal class EntryPropertyEditorDelegate<T> - : NSTextFieldDelegate + : DelegatedRowTextFieldDelegate { public EntryPropertyEditorDelegate (PropertyViewModel<T> viewModel) { diff --git a/Xamarin.PropertyEditing.Mac/Controls/NumericEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/NumericEditorControl.cs index e56debf..3a00b28 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/NumericEditorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/NumericEditorControl.cs @@ -16,7 +16,10 @@ namespace Xamarin.PropertyEditing.Mac { base.TranslatesAutoresizingMaskIntoConstraints = false; - NumericEditor = new NumericSpinEditor<T> (hostResources); + NumericEditor = new NumericSpinEditor<T> (hostResources) + { + ProxyResponder = new ProxyResponder (this, ProxyRowType.SingleView) + }; NumericEditor.ValueChanged += OnValueChanged; var t = typeof (T); @@ -129,6 +132,9 @@ namespace Xamarin.PropertyEditing.Mac TranslatesAutoresizingMaskIntoConstraints = false, }; + this.NumericEditor.ProxyResponder = new ProxyResponder (this, ProxyRowType.FirstView); + this.inputModePopup.ProxyResponder = new ProxyResponder (this, ProxyRowType.LastView); + this.inputModePopup.Activated += (o, e) => { var popupButton = o as NSPopUpButton; ViewModel.InputMode = this.viewModelInputModes.FirstOrDefault (im => im.Identifier == popupButton.Title); @@ -163,7 +169,7 @@ namespace Xamarin.PropertyEditing.Mac private Type underlyingType; - internal NSPopUpButton inputModePopup; + internal FocusablePopUpButton inputModePopup; private IReadOnlyList<InputMode> viewModelInputModes; private readonly NSLayoutConstraint editorRightConstraint; diff --git a/Xamarin.PropertyEditing.Mac/Controls/PredefinedValuesEditor.cs b/Xamarin.PropertyEditing.Mac/Controls/PredefinedValuesEditor.cs index f402bf7..77f6edb 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/PredefinedValuesEditor.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/PredefinedValuesEditor.cs @@ -74,8 +74,8 @@ namespace Xamarin.PropertyEditing.Mac } } - private NSComboBox comboBox; - private NSPopUpButton popupButton; + private FocusableComboBox comboBox; + private FocusablePopUpButton popupButton; private NSMenu popupButtonList; private NSView firstKeyView; @@ -113,8 +113,9 @@ namespace Xamarin.PropertyEditing.Mac Font = NSFont.SystemFontOfSize (NSFont.SystemFontSizeForControlSize (NSControlSize.Small)), TranslatesAutoresizingMaskIntoConstraints = false, StringValue = String.Empty, + ProxyResponder = new ProxyResponder (this, ProxyRowType.SingleView) }; - + this.popupButton.ProxyResponder = new ProxyResponder (this, ProxyRowType.SingleView); this.popupButtonList = new NSMenu (); this.popupButton.Menu = this.popupButtonList; this.popupButton.Activated += PopupButton_Activated; @@ -155,12 +156,13 @@ namespace Xamarin.PropertyEditing.Mac LineBreakMode = NSLineBreakMode.TruncatingTail, UsesSingleLineMode = true, }, + ProxyResponder = new ProxyResponder (this, ProxyRowType.SingleView), ControlSize = NSControlSize.Small, Font = NSFont.SystemFontOfSize (NSFont.SystemFontSizeForControlSize (NSControlSize.Small)), TranslatesAutoresizingMaskIntoConstraints = false, StringValue = String.Empty, }; - + this.comboBox.ProxyResponder = new ProxyResponder (this, ProxyRowType.SingleView); this.comboBox.SelectionChanged += ComboBox_SelectionChanged; AddSubview (this.comboBox); diff --git a/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs index e2d5eb9..0f2cec0 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs @@ -64,43 +64,9 @@ namespace Xamarin.PropertyEditing.Mac NSView INativeContainer.NativeView => this; - [Export ("_primitiveSetDefaultNextKeyView:")] - public void SetDefaultNextKeyView (NSView child) - { - if (child == FirstKeyView || child == LastKeyView) { - UpdateKeyViews (); - } - } public virtual bool NeedsPropertyButton => true; - public void UpdateKeyViews () - { - 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); - if (view is PropertyEditorControl pec) { // This is to include the CategoryContainer - ctrl = pec; - } else { - 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); - } - } - } /// <remarks>You should treat the implementation of this as static.</remarks> public virtual nint GetHeight (EditorViewModel vm) @@ -146,6 +112,42 @@ namespace Xamarin.PropertyEditing.Mac AppearanceChanged (); } + + public void OnNextResponderRequested (bool reverse) + { + if (TableView != null) { + var modifier = reverse ? -1 : 1; + + nint row = TableView.RowForView (this) + modifier; + + NSView view; + PropertyEditorControl ctrl = null; + + var rowCount = TableView.RowCount; + for (; reverse ? row > 0 : row < rowCount; row += modifier) { + + view = TableView.GetView (0, row, makeIfNecessary: false); + if (view is PropertyEditorControl pec) { // This is to include the CategoryContainer + ctrl = pec; + } else { + ctrl = (view as EditorContainer)?.EditorView?.NativeView as PropertyEditorControl; + } + + if (ctrl?.viewModel != null && !ctrl.viewModel.IsInputEnabled) { + ctrl = null; + } + + if (ctrl != null) { + var targetView = reverse ? ctrl.LastKeyView : ctrl.FirstKeyView; + Window?.MakeFirstResponder (targetView); + return; + } else if (row == 0 && view is PanelHeaderEditorControl header) { + Window?.MakeFirstResponder (header); + return; + } + } + } + } } internal abstract class PropertyEditorControl<TViewModel> diff --git a/Xamarin.PropertyEditing.Mac/Controls/ProxyRowResponder.cs b/Xamarin.PropertyEditing.Mac/Controls/ProxyRowResponder.cs new file mode 100644 index 0000000..406bde4 --- /dev/null +++ b/Xamarin.PropertyEditing.Mac/Controls/ProxyRowResponder.cs @@ -0,0 +1,48 @@ +using System; + +namespace Xamarin.PropertyEditing.Mac +{ + internal enum ProxyRowType + { + SingleView, + FirstView, + LastView + } + + internal class ProxyResponder + { + protected WeakReference<PropertyEditorControl> editorControl; + + readonly ProxyRowType rowType; + + public ProxyResponder (PropertyEditorControl editorControl, ProxyRowType rowType) + { + this.rowType = rowType; + this.editorControl = new WeakReference<PropertyEditorControl> (editorControl); + } + + public bool NextResponder() + { + if (this.editorControl.TryGetTarget (out var editor)) + { + if (this.rowType == ProxyRowType.LastView || this.rowType == ProxyRowType.SingleView) { + editor.OnNextResponderRequested (false); + return true; + } + } + return false; + } + + public bool PreviousResponder () + { + if (this.editorControl.TryGetTarget (out var editor)) + { + if (this.rowType == ProxyRowType.FirstView || this.rowType == ProxyRowType.SingleView) { + editor.OnNextResponderRequested (true); + return true; + } + } + return false; + } + } +} diff --git a/Xamarin.PropertyEditing.Mac/Controls/RatioEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/RatioEditorControl.cs index 7591c2b..a5c8fdc 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/RatioEditorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/RatioEditorControl.cs @@ -16,6 +16,7 @@ namespace Xamarin.PropertyEditing.Mac base.TranslatesAutoresizingMaskIntoConstraints = false; this.ratioEditor = new RatioEditor<T> (hostResources); + this.ratioEditor.ProxyResponder = new ProxyResponder (this, ProxyRowType.SingleView); this.ratioEditor.SetFormatter (null); // update the value on keypress diff --git a/Xamarin.PropertyEditing.Mac/Controls/StringEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/StringEditorControl.cs index e10ec78..01a4af4 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/StringEditorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/StringEditorControl.cs @@ -45,7 +45,7 @@ namespace Xamarin.PropertyEditing.Mac Font = NSFont.SystemFontOfSize (NSFont.SystemFontSizeForControlSize (NSControlSize.Small)), TranslatesAutoresizingMaskIntoConstraints = false }; - + this.inputModePopup.ProxyResponder = new ProxyResponder (this, ProxyRowType.SingleView); this.inputModePopup.Activated += (o, e) => { var popupButton = o as NSPopUpButton; ViewModel.InputMode = this.viewModelInputModes.FirstOrDefault (im => im.Identifier == popupButton.Title); @@ -104,7 +104,7 @@ namespace Xamarin.PropertyEditing.Mac private NSView lastKeyView; private NSLayoutConstraint editorInputModeConstraint; - private NSPopUpButton inputModePopup; + private FocusablePopUpButton inputModePopup; private IReadOnlyList<InputMode> viewModelInputModes; } } diff --git a/Xamarin.PropertyEditing.Mac/Controls/TimeSpanEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/TimeSpanEditorControl.cs index 222af81..d6c6361 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/TimeSpanEditorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/TimeSpanEditorControl.cs @@ -13,7 +13,9 @@ namespace Xamarin.PropertyEditing.Mac protected override EntryPropertyEditorDelegate<TimeSpan> CreateDelegate (PropertyViewModel<TimeSpan> viewModel) { - return new TimeSpanDelegate (viewModel); + return new TimeSpanDelegate (viewModel) { + ProxyResponder = new ProxyResponder (this, ProxyRowType.SingleView) + }; } protected override void UpdateAccessibilityValues () diff --git a/Xamarin.PropertyEditing.Mac/Controls/TypeEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/TypeEditorControl.cs index 9ee86d1..0baee02 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/TypeEditorControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/TypeEditorControl.cs @@ -22,7 +22,9 @@ namespace Xamarin.PropertyEditing.Mac this.selectType = new FocusableButton { BezelStyle = NSBezelStyle.Rounded, Title = Properties.Resources.Select, + ProxyResponder = new ProxyResponder(this, ProxyRowType.SingleView) }; + this.selectType.Activated += OnSelectPressed; AddSubview (this.selectType); @@ -89,7 +91,7 @@ namespace Xamarin.PropertyEditing.Mac } private readonly UnfocusableTextField typeLabel; - private readonly NSButton selectType; + private readonly FocusableButton selectType; private void OnTypeRequested (object sender, TypeRequestedEventArgs e) { diff --git a/Xamarin.PropertyEditing.Mac/PropertyList.cs b/Xamarin.PropertyEditing.Mac/PropertyList.cs index 8e242a1..027b21f 100644 --- a/Xamarin.PropertyEditing.Mac/PropertyList.cs +++ b/Xamarin.PropertyEditing.Mac/PropertyList.cs @@ -129,7 +129,9 @@ namespace Xamarin.PropertyEditing.Mac SelectRow (0, false); this.tabbedIn = true; var row = GetRowView ((nint)SelectedRows.FirstIndex, false); - return Window.MakeFirstResponder (row.NextValidKeyView); + if (row != null) { + return Window.MakeFirstResponder (row.NextValidKeyView); + } } } this.tabbedIn = false; |