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 <savagesoftware@gmail.com>2017-11-01 21:37:54 +0300
committerDominique Louis <savagesoftware@gmail.com>2018-08-08 09:33:19 +0300
commitb6c0aeba09b2167c3f9d83004f3942c3e6ae066e (patch)
treec0433c95632f770675034e1ff65cfc6699600034 /Xamarin.PropertyEditing.Mac/Controls
parenta7b11a56e99a00177c705031b65de932f217dd11 (diff)
[Mac] Initial CommonRatio implementation.
Diffstat (limited to 'Xamarin.PropertyEditing.Mac/Controls')
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BasePointEditorControl.cs2
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/BaseRectangleEditorControl.cs2
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/Custom/NumericSpinEditor.cs229
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/Custom/NumericTextField.cs135
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs120
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/Custom/RatioEditor.cs80
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/Custom/SpinnerButton.cs49
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/Custom/UnfocusableButton.cs104
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/NumericEditorControl.cs2
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs22
-rw-r--r--Xamarin.PropertyEditing.Mac/Controls/RatioEditorControl.cs78
11 files changed, 607 insertions, 216 deletions
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BasePointEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BasePointEditorControl.cs
index b438f2c..287a92f 100644
--- a/Xamarin.PropertyEditing.Mac/Controls/BasePointEditorControl.cs
+++ b/Xamarin.PropertyEditing.Mac/Controls/BasePointEditorControl.cs
@@ -15,7 +15,7 @@ namespace Xamarin.PropertyEditing.Mac
internal NumericSpinEditor<T> YEditor { get; set; }
public override NSView FirstKeyView => XEditor;
- public override NSView LastKeyView => YEditor;
+ public override NSView LastKeyView => YEditor.DecrementButton;
public BasePointEditorControl ()
{
diff --git a/Xamarin.PropertyEditing.Mac/Controls/BaseRectangleEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/BaseRectangleEditorControl.cs
index 5cdd872..1c57694 100644
--- a/Xamarin.PropertyEditing.Mac/Controls/BaseRectangleEditorControl.cs
+++ b/Xamarin.PropertyEditing.Mac/Controls/BaseRectangleEditorControl.cs
@@ -21,7 +21,7 @@ namespace Xamarin.PropertyEditing.Mac
protected NumericSpinEditor<T> HeightEditor { get; set; }
public override NSView FirstKeyView => XEditor;
- public override NSView LastKeyView => HeightEditor;
+ public override NSView LastKeyView => HeightEditor.DecrementButton;
public BaseRectangleEditorControl ()
{
diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericSpinEditor.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericSpinEditor.cs
index edb17f5..1aabaa0 100644
--- a/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericSpinEditor.cs
+++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericSpinEditor.cs
@@ -2,6 +2,8 @@
using AppKit;
using CoreGraphics;
using Foundation;
+using Xamarin.PropertyEditing.Drawing;
+using Xamarin.PropertyEditing.Themes;
namespace Xamarin.PropertyEditing.Mac
{
@@ -12,8 +14,21 @@ namespace Xamarin.PropertyEditing.Mac
internal class NumericSpinEditor : NSView, INSAccessibilityGroup
{
NumericTextField numericEditor;
- NSStepper stepper;
- bool editing;
+ public NumericTextField NumericEditor {
+ get { return numericEditor; }
+ }
+
+ UpSpinnerButton incrementButton;
+ public UpSpinnerButton IncrementButton {
+ get { return incrementButton; }
+ }
+
+ DownSpinnerButton decrementButton;
+ public DownSpinnerButton DecrementButton {
+ get { return decrementButton; }
+ }
+
+ protected bool editing;
public event EventHandler ValueChanged;
public event EventHandler EditingEnded;
@@ -31,28 +46,16 @@ namespace Xamarin.PropertyEditing.Mac
set { ((NSTextFieldCell)numericEditor.Cell).PlaceholderString = value; }
}
- NSStepper Stepper {
- get { return stepper; }
- }
-
- public NSTextField TextField {
- get { return numericEditor; }
- }
-
public override CGSize IntrinsicContentSize {
get {
- var baseSize = stepper.IntrinsicContentSize;
- return new CGSize (baseSize.Width + 40, baseSize.Height);
+ var baseSize = numericEditor.IntrinsicContentSize;
+ return new CGSize (baseSize.Width + 20, baseSize.Height);
}
}
public NSColor BackgroundColor {
- get {
- return numericEditor.BackgroundColor;
- }
- set {
- numericEditor.BackgroundColor = value;
- }
+ get { return numericEditor.BackgroundColor; }
+ set { numericEditor.BackgroundColor = value; }
}
public override nfloat BaselineOffsetFromBottom {
@@ -66,7 +69,7 @@ namespace Xamarin.PropertyEditing.Mac
public double Value {
- get { return stepper.DoubleValue; }
+ get { return numericEditor.DoubleValue; }
set { SetValue (value); }
}
@@ -76,47 +79,38 @@ namespace Xamarin.PropertyEditing.Mac
set { SetValue (value); }
}
- public bool Wrap {
- get { return stepper.ValueWraps; }
- set { stepper.ValueWraps = value; }
- }
-
public double MinimumValue {
- get { return stepper.MinValue; }
+ get { return formatter.Minimum.DoubleValue; }
set {
- stepper.MinValue = value;
formatter.Minimum = new NSNumber (value);
}
}
public double MaximumValue {
- get { return stepper.MaxValue; }
+ get { return formatter.Maximum.DoubleValue; }
set {
- stepper.MaxValue = value;
formatter.Maximum = new NSNumber (value);
}
}
+ double incrementValue = 1.0f;
public double IncrementValue {
- get { return stepper.Increment; }
- set { stepper.Increment = value; }
+ get { return incrementValue; }
+ set { incrementValue = value; }
}
public bool Enabled {
- get {
- return numericEditor.Enabled;
- }
+ get { return numericEditor.Enabled; }
set {
numericEditor.Enabled = value;
- stepper.Enabled = value;
+ incrementButton.Enabled = value;
+ decrementButton.Enabled = value;
}
}
NSNumberFormatter formatter;
public NSNumberFormatter Formatter {
- get {
- return formatter;
- }
+ get { return formatter; }
set {
formatter = value;
numericEditor.Formatter = formatter;
@@ -124,32 +118,31 @@ namespace Xamarin.PropertyEditing.Mac
}
public bool IsIndeterminate {
- get {
- return !string.IsNullOrEmpty (numericEditor.StringValue);
- }
+ get { return !string.IsNullOrEmpty (numericEditor.StringValue); }
set {
if (value)
numericEditor.StringValue = string.Empty;
- else
- numericEditor.DoubleValue = stepper.DoubleValue;
}
}
public bool Editable {
- get {
- return numericEditor.Editable;
- }
+ get { return numericEditor.Editable; }
set {
numericEditor.Editable = value;
- stepper.Enabled = value;
+ incrementButton.Enabled = value;
+ decrementButton.Enabled = value;
}
}
public NSNumberFormatterStyle NumberStyle {
get { return formatter.NumberStyle; }
- set {
- formatter.NumberStyle = value;
- }
+ set { formatter.NumberStyle = value; }
+ }
+
+ public bool AllowRatios
+ {
+ get { return numericEditor.AllowRatios; }
+ set { numericEditor.AllowRatios = value; }
}
protected virtual void OnConfigureNumericTextField ()
@@ -157,6 +150,12 @@ namespace Xamarin.PropertyEditing.Mac
numericEditor.Formatter = formatter;
}
+ public bool AllowNegativeValues
+ {
+ get { return numericEditor.AllowNegativeValues; }
+ set { numericEditor.AllowNegativeValues = value; }
+ }
+
public virtual void Reset ()
{
}
@@ -166,99 +165,110 @@ namespace Xamarin.PropertyEditing.Mac
TranslatesAutoresizingMaskIntoConstraints = false;
var controlSize = NSControlSize.Small;
- stepper = new NSStepper {
- TranslatesAutoresizingMaskIntoConstraints = false,
- ValueWraps = false,
- ControlSize = controlSize,
- };
+ incrementButton = new UpSpinnerButton ();
+
+ decrementButton = new DownSpinnerButton ();
formatter = new NSNumberFormatter {
FormatterBehavior = NSNumberFormatterBehavior.Version_10_4,
Locale = NSLocale.CurrentLocale,
MaximumFractionDigits = 15,
+ Maximum = double.MaxValue,
+ Minimum = double.MinValue,
NumberStyle = NSNumberFormatterStyle.Decimal,
UsesGroupingSeparator = false,
};
numericEditor = new NumericTextField {
Alignment = NSTextAlignment.Right,
- Formatter = formatter,
TranslatesAutoresizingMaskIntoConstraints = false,
Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize),
ControlSize = controlSize,
};
- stepper.Activated += (s, e) => {
- OnStepperActivated (s, e);
- };
+ incrementButton.OnMouseLeftDown += (sender, e) => { IncrementNumericValue (); };
+ decrementButton.OnMouseLeftDown += (sender, e) => { DecrementNumericValue (); };
- numericEditor.KeyArrowUp += (sender, e) => { IncrementNumericValue (); };
- numericEditor.KeyArrowDown += (sender, e) => { DecrementNumericValue (); };
+ numericEditor.KeyArrowUp += (sender, e) => { IncrementNumericValue (e); };
+ numericEditor.KeyArrowDown += (sender, e) => { DecrementNumericValue (e); };
numericEditor.ValidatedEditingEnded += (s, e) => {
OnEditingEnded (s, e);
};
- AddSubview (stepper);
AddSubview (numericEditor);
+ AddSubview (incrementButton);
+ AddSubview (decrementButton);
this.DoConstraints (new[] {
numericEditor.ConstraintTo (this, (n, c) => n.Width == c.Width - 16),
- numericEditor.ConstraintTo (this, (n, c) => n.Height == 19),
- stepper.ConstraintTo (numericEditor, (s, n) => s.Left == n.Right + 4),
- stepper.ConstraintTo (numericEditor, (s, n) => s.Top == n.Top),
+ numericEditor.ConstraintTo (this, (n, c) => n.Height == PropertyEditorControl.DefaultControlHeight - 3),
+ incrementButton.ConstraintTo (numericEditor, (s, n) => s.Left == n.Right + 5),
+ incrementButton.ConstraintTo (numericEditor, (s, n) => s.Top == n.Top + 1),
+ incrementButton.ConstraintTo (numericEditor, (s, n) => s.Width == 9),
+ incrementButton.ConstraintTo (numericEditor, (s, n) => s.Height == 9),
+ decrementButton.ConstraintTo (numericEditor, (s, n) => s.Left == n.Right + 5),
+ decrementButton.ConstraintTo (numericEditor, (s, n) => s.Top == n.Top + 10),
+ decrementButton.ConstraintTo (numericEditor, (s, n) => s.Width == 9),
+ decrementButton.ConstraintTo (numericEditor, (s, n) => s.Height == 9),
});
+
+ PropertyEditorPanel.ThemeManager.ThemeChanged += ThemeManager_ThemeChanged;
+
+ UpdateTheme ();
}
- protected virtual void SetStepperActivated ()
+ protected override void Dispose (bool disposing)
{
- SetValue (stepper.DoubleValue);
+ if (disposing) {
+ PropertyEditorPanel.ThemeManager.ThemeChanged -= ThemeManager_ThemeChanged;
+ }
}
- protected void OnStepperActivated (object sender, EventArgs e)
+ void ThemeManager_ThemeChanged (object sender, EventArgs e)
{
- if (!editing) {
- editing = true;
- SetStepperActivated ();
- if (ValueChanged != null)
- ValueChanged (this, EventArgs.Empty);
- editing = false;
- }
+ UpdateTheme ();
}
- protected void OnValueChanged (object sender, EventArgs e)
+ protected void UpdateTheme ()
{
- if (!editing) {
- editing = true;
- SetValue (numericEditor.StringValue);
- if (ValueChanged != null)
- ValueChanged (this, EventArgs.Empty);
- editing = false;
+ this.Appearance = PropertyEditorPanel.ThemeManager.CurrentAppearance;
+
+ // Skin the inc/dec buttons until we support theming files
+ switch (PropertyEditorPanel.ThemeManager.Theme) {
+ case PropertyEditorTheme.Dark:
+ incrementButton.Image = NSImage.ImageNamed ("stepper-up"); // TODO path to proper image
+ decrementButton.Image = NSImage.ImageNamed ("stepper-down"); // TODO path to proper image
+ break;
+
+ case PropertyEditorTheme.Light:
+ incrementButton.Image = NSImage.ImageNamed ("stepper-up"); // TODO path to proper image
+ decrementButton.Image = NSImage.ImageNamed ("stepper-down"); // TODO path to proper image
+ break;
+
+ case PropertyEditorTheme.None:
+ incrementButton.Image = NSImage.ImageNamed ("stepper-up"); // TODO path to proper image
+ decrementButton.Image = NSImage.ImageNamed ("stepper-down"); // TODO path to proper image
+ break;
}
+
}
- protected void OnEditingEnded (object sender, EventArgs e)
+ virtual protected void OnEditingEnded (object sender, EventArgs e)
{
if (!editing) {
editing = true;
SetValue (numericEditor.StringValue);
- if (EditingEnded != null)
- EditingEnded (this, EventArgs.Empty);
- if (ValueChanged != null)
- ValueChanged (this, EventArgs.Empty);
+ EditingEnded?.Invoke (this, EventArgs.Empty);
editing = false;
}
}
void SetValue (string value)
{
- //Regulates maximun and minium out of range
- if (!string.IsNullOrEmpty (value)) {
- stepper.DoubleValue = CoerceValue (FieldValidation.FixInitialValue (value, Value.ToEditorString ()).ToEditorDouble ());
- numericEditor.StringValue = FieldValidation.RoundDoubleValue (stepper.DoubleValue.ToEditorString (), NumericMode == ValidationType.Decimal ? FieldValidation.DefaultXcodeMaxRoundDigits : 0);
- } else {
- stepper.StringValue = value;
+ if (numericEditor.StringValue != value) {
numericEditor.StringValue = value;
+ NotifyingValueChanged (EventArgs.Empty);
}
}
@@ -267,21 +277,40 @@ namespace Xamarin.PropertyEditing.Mac
SetValue (value.ToString ());
}
- protected double CoerceValue (double val)
+ protected void NotifyingValueChanged (EventArgs eventArgs)
+ {
+ ValueChanged?.Invoke (this, eventArgs);
+ }
+
+ public void IncrementNumericValue (bool shiftPressed = false)
+ {
+ if (!editing) {
+ editing = true;
+ SetIncrementOrDecrementValue (shiftPressed ? 10 * incrementValue : incrementValue);
+ editing = false;
+ }
+ }
+
+ public void DecrementNumericValue (bool shiftPressed = false)
{
- return FieldValidation.CoerceValue (val, MinimumValue, MaximumValue);
+ if (!editing) {
+ editing = true;
+ SetIncrementOrDecrementValue (-(shiftPressed ? 10 * incrementValue : incrementValue));
+ editing = false;
+ }
}
- public void IncrementNumericValue ()
+ virtual protected void SetIncrementOrDecrementValue (double incDevValue)
{
- SetValue (stepper.DoubleValue + IncrementValue);
- OnStepperActivated (stepper, EventArgs.Empty);
+ // Constrain our value to our Min/Max before we set it
+ var newValue = Clamp (numericEditor.DoubleValue + incDevValue);
+
+ SetValue (newValue);
}
- public void DecrementNumericValue ()
+ public double Clamp (double value)
{
- SetValue (stepper.DoubleValue - IncrementValue);
- OnStepperActivated (stepper, EventArgs.Empty);
+ return (double)Decimal.Round ((decimal)(value < MinimumValue ? MinimumValue : value > MaximumValue ? MaximumValue : value), Digits);
}
}
}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericTextField.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericTextField.cs
index bd3a045..f324c9b 100644
--- a/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericTextField.cs
+++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/NumericTextField.cs
@@ -25,8 +25,8 @@ namespace Xamarin.PropertyEditing.Mac
get; set;
}
- public event EventHandler KeyArrowUp;
- public event EventHandler KeyArrowDown;
+ public event EventHandler<bool> KeyArrowUp;
+ public event EventHandler<bool> KeyArrowDown;
public event EventHandler ValidatedEditingEnded;
public NumericTextField ()
@@ -34,15 +34,15 @@ namespace Xamarin.PropertyEditing.Mac
AllowNegativeValues = true;
var keyUpDownDelegate = new KeyUpDownDelegate ();
- keyUpDownDelegate.KeyArrowUp += (sender, e) => { OnKeyArrowUp (); };
- keyUpDownDelegate.KeyArrowDown += (sender, e) => { OnKeyArrowDown (); };
+ keyUpDownDelegate.KeyArrowUp += (sender, e) => { OnKeyArrowUp (e); };
+ keyUpDownDelegate.KeyArrowDown += (sender, e) => { OnKeyArrowDown (e); };
Delegate = keyUpDownDelegate;
}
- public override bool ShouldBeginEditing (NSText fieldEditor)
+ public override bool ShouldBeginEditing (NSText textObject)
{
- CachedCurrentEditor = fieldEditor;
- cachedValueString = fieldEditor.Value;
+ CachedCurrentEditor = textObject;
+ cachedValueString = textObject.Value;
if (AllowRatios)
CachedCurrentEditor.Delegate = new RatioValidateDelegate (this);
@@ -52,27 +52,19 @@ namespace Xamarin.PropertyEditing.Mac
return true;
}
- protected virtual void OnKeyArrowUp ()
+ protected virtual void OnKeyArrowUp (bool shiftPressed)
{
- var handler = KeyArrowUp;
- if (handler != null) {
- handler (this, EventArgs.Empty);
- }
+ KeyArrowUp?.Invoke (this, shiftPressed);
}
- protected virtual void OnKeyArrowDown ()
+ protected virtual void OnKeyArrowDown (bool shiftPressed)
{
- var handler = KeyArrowDown;
- if (handler != null) {
- handler (this, EventArgs.Empty);
- }
+ KeyArrowDown?.Invoke (this, shiftPressed);
}
- public virtual void RaiseValidatedEditingEnded ()
+ public virtual void NotifyValidatedEditingEnded ()
{
- var handler = ValidatedEditingEnded;
- if (handler != null)
- handler (this, EventArgs.Empty);
+ ValidatedEditingEnded?.Invoke (this, EventArgs.Empty);
}
public virtual void ResetInvalidInput ()
@@ -80,12 +72,66 @@ namespace Xamarin.PropertyEditing.Mac
this.StringValue = cachedValueString;
}
+ public static bool CheckIfNumber (string finalString, ValidationType mode, bool allowNegativeValues)
+ {
+ return mode == ValidationType.Decimal ?
+ ValidateDecimal (finalString, allowNegativeValues) :
+ ValidateInteger (finalString, allowNegativeValues);
+ }
+
+ public static bool ValidateDecimal (string finalString, bool allowNegativeValues)
+ {
+ double value;
+ //Checks parsing to number
+ if (!double.TryParse (finalString, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.CurrentUICulture, out value))
+ return false;
+ //Checks if needs to be possitive value
+ if (!allowNegativeValues && value < 0)
+ return false;
+ //Checks a common validation
+ return ViewModels.RatioViewModel.IsValidInput (finalString);
+ }
+
+ public static bool ValidateInteger (string finalString, bool allowNegativeValues)
+ {
+ int value;
+ //Checks parsing to number
+ if (!int.TryParse (finalString, out value))
+ return false;
+ //Checks if needs to be possitive value
+ if (!allowNegativeValues && value < 0)
+ return false;
+ //Checks a common validation
+ return ViewModels.RatioViewModel.IsValidInput (finalString);
+ }
+
+ public static bool CheckIfRatio (string finalString, ValidationType mode, bool allowNegativeValues)
+ {
+ var parts = finalString.Split (ViewModels.RatioViewModel.SplitSeparators, StringSplitOptions.RemoveEmptyEntries);
+ if (parts.Length == 2) {
+ bool parsed = true;
+
+ if (!CheckIfNumber (parts[0], mode, allowNegativeValues))
+ parsed = false;
+
+ if (!String.IsNullOrEmpty (parts[1]) && !CheckIfNumber (parts[1], mode, allowNegativeValues))
+ parsed = false;
+
+ if (parsed)
+ return true;
+ } else if (parts.Length == 1) { // We have a potential whole number, let's make sure
+ if (CheckIfNumber (parts[0], mode, allowNegativeValues)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
class KeyUpDownDelegate : NSTextFieldDelegate
{
- public event EventHandler KeyArrowUp;
- public event EventHandler KeyArrowDown;
+ public event EventHandler<bool> KeyArrowUp;
+ public event EventHandler<bool> KeyArrowDown;
public override bool DoCommandBySelector (NSControl control, NSTextView textView, Selector commandSelector)
{
@@ -96,27 +142,27 @@ namespace Xamarin.PropertyEditing.Mac
case "moveDown:":
OnKeyArrowDown ();
break;
+ case "moveUpAndModifySelection:":
+ OnKeyArrowUp (true);
+ break;
+ case "moveDownAndModifySelection:":
+ OnKeyArrowDown (true);
+ break;
default:
return false;
}
- return false;
+ return true;
}
- protected virtual void OnKeyArrowUp ()
+ protected virtual void OnKeyArrowUp (bool shiftPressed = false)
{
- var handler = KeyArrowUp;
- if (handler != null) {
- handler (this, EventArgs.Empty);
- }
+ KeyArrowUp?.Invoke (this, shiftPressed);
}
- protected virtual void OnKeyArrowDown ()
+ protected virtual void OnKeyArrowDown (bool shiftPressed = false)
{
- var handler = KeyArrowDown;
- if (handler != null) {
- handler (this, EventArgs.Empty);
- }
+ KeyArrowDown?.Invoke (this, shiftPressed);
}
}
@@ -138,17 +184,22 @@ namespace Xamarin.PropertyEditing.Mac
public override bool TextShouldEndEditing (NSText textObject)
{
- if (!ValidateFinalString (TextField.StringValue)) {
+ bool shouldEndEditing = false;
+ if (!ValidateFinalString (textObject.Value)) {
TextField.ResetInvalidInput ();
AppKitFramework.NSBeep ();
- return false;
+ TextField.ShouldEndEditing (textObject);
+ } else {
+ shouldEndEditing = TextField.ShouldEndEditing (textObject);
}
- return TextField.ShouldEndEditing (textObject);
+
+ return shouldEndEditing;
}
public override void TextDidEndEditing (NSNotification notification)
{
- TextField.RaiseValidatedEditingEnded ();
+ TextField.NotifyValidatedEditingEnded ();
+ TextField.DidEndEditing (notification);
}
protected abstract bool ValidateFinalString (string value);
@@ -165,8 +216,8 @@ namespace Xamarin.PropertyEditing.Mac
protected override bool ValidateFinalString (string value)
{
return TextField.NumericMode == ValidationType.Decimal ?
- FieldValidation.ValidateDecimal (value, TextField.AllowNegativeValues) :
- FieldValidation.ValidateInteger (value, TextField.AllowNegativeValues);
+ NumericTextField.ValidateDecimal (value, TextField.AllowNegativeValues) :
+ NumericTextField.ValidateInteger (value, TextField.AllowNegativeValues);
}
}
@@ -180,7 +231,9 @@ namespace Xamarin.PropertyEditing.Mac
protected override bool ValidateFinalString (string value)
{
- return FieldValidation.ValidateRatio (value, ValidationType.Decimal, TextField.AllowNegativeValues);
+ if (NumericTextField.CheckIfRatio (value, ValidationType.Decimal, false) || NumericTextField.CheckIfNumber (value, ValidationType.Decimal, false))
+ return true;
+ return false;
}
}
}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs
index a300e18..77a2cb3 100644
--- a/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs
+++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs
@@ -2,11 +2,12 @@
using AppKit;
using CoreGraphics;
using Xamarin.PropertyEditing.Mac.Resources;
+using Xamarin.PropertyEditing.Themes;
using Xamarin.PropertyEditing.ViewModels;
namespace Xamarin.PropertyEditing.Mac
{
- public class PropertyButton : NSImageView
+ public class PropertyButton : UnfocusableButton
{
NSMenu popUpContextMenu;
@@ -35,106 +36,101 @@ namespace Xamarin.PropertyEditing.Mac
AccessibilityHelp = LocalizationResources.AccessibilityPropertiesButtonDescription;
Enabled = true;
Image = PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-default-mac-10");
- ImageScaling = NSImageScale.AxesIndependently;
+ ImageScaling = NSImageScale.None;
ToolTip = Properties.Resources.Default;
TranslatesAutoresizingMaskIntoConstraints = false;
+
+ OnMouseEntered += (sender, e) => {
+ ToggleFocusImage (true);
+ };
+
+ OnMouseExited += (sender, e) => {
+ ToggleFocusImage ();
+ };
+
+ OnMouseLeftDown += (sender, e) => {
+ PopUpContextMenu ();
+ };
}
- public override void MouseDown (NSEvent theEvent)
+ private void PopUpContextMenu ()
{
- if (theEvent.Type == NSEventType.LeftMouseDown) {
- if (this.popUpContextMenu == null) {
- this.popUpContextMenu = new NSMenu ();
-
- if (this.viewModel.TargetPlatform.SupportsCustomExpressions) {
- var mi = new NSMenuItem (Properties.Resources.CustomExpressionEllipsis) {
- AttributedTitle = new Foundation.NSAttributedString (
- Properties.Resources.CustomExpressionEllipsis,
- new CoreText.CTStringAttributes () {
- Font = new CoreText.CTFont (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize + 1),
- })
- };
-
- mi.Activated += OnCustomExpression;
-
- this.popUpContextMenu.AddItem (mi);
- 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) {
+ if (this.popUpContextMenu == null) {
+ this.popUpContextMenu = new NSMenu ();
+
+ if (this.viewModel.TargetPlatform.SupportsCustomExpressions) {
+ var mi = new NSMenuItem (Properties.Resources.CustomExpressionEllipsis) {
AttributedTitle = new Foundation.NSAttributedString (
- Properties.Resources.Reset,
- new CoreText.CTStringAttributes () {
- Font = new CoreText.CTFont (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize + 1),
- })
- });
- }
+ Properties.Resources.CustomExpressionEllipsis,
+ new CoreText.CTStringAttributes () {
+ Font = new CoreText.CTFont (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize + 1),
+ })
+ };
- var menuOrigin = this.Superview.ConvertPointToView (new CGPoint (Frame.Location.X - 1, Frame.Location.Y + Frame.Size.Height + 4), null);
+ mi.Activated += OnCustomExpression;
- var popupMenuEvent = NSEvent.MouseEvent (NSEventType.LeftMouseDown, menuOrigin, (NSEventModifierMask)0x100, 0, this.Window.WindowNumber, this.Window.GraphicsContext, 0, 1, 1);
+ this.popUpContextMenu.AddItem (mi);
+ this.popUpContextMenu.AddItem (NSMenuItem.SeparatorItem);
+ }
- NSMenu.PopUpContextMenu (popUpContextMenu, popupMenuEvent, this);
+ // 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) {
+ AttributedTitle = new Foundation.NSAttributedString (
+ Properties.Resources.Reset,
+ new CoreText.CTStringAttributes () {
+ Font = new CoreText.CTFont (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize + 1),
+ })
+ });
}
- }
- public override void MouseEntered (NSEvent theEvent)
- {
- ChangeActiveImage (viewModel.ValueSource, true);
- }
+ var menuOrigin = this.Superview.ConvertPointToView (new CGPoint (Frame.Location.X - 1, Frame.Location.Y + Frame.Size.Height + 4), null);
- public override void MouseExited (NSEvent theEvent)
- {
- ChangeActiveImage (viewModel.ValueSource);
+ var popupMenuEvent = NSEvent.MouseEvent (NSEventType.LeftMouseDown, menuOrigin, (NSEventModifierMask)0x100, 0, this.Window.WindowNumber, this.Window.GraphicsContext, 0, 1, 1);
+
+ NSMenu.PopUpContextMenu (popUpContextMenu, popupMenuEvent, this);
}
- public override void UpdateTrackingAreas ()
+ protected override void UpdateTheme ()
{
- base.UpdateTrackingAreas ();
-
- foreach (var item in TrackingAreas ()) {
- RemoveTrackingArea (item);
- }
-
- var options = NSTrackingAreaOptions.MouseEnteredAndExited | NSTrackingAreaOptions.ActiveAlways;
+ base.UpdateTheme ();
- var trackingArea = new NSTrackingArea (this.Bounds, options, this, null);
-
- AddTrackingArea (trackingArea);
+ ToggleFocusImage ();
}
- private void ChangeActiveImage (ValueSource valueSource, bool activeImage = false)
+ private void ToggleFocusImage (bool focused = false)
{
- switch (valueSource) {
+ if (viewModel != null) {
+
+ switch (viewModel.ValueSource) {
case ValueSource.Binding:
- Image = activeImage ? PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-bound-mac-active-10") : PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-bound-mac-10");
+ Image = focused ? PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-bound-mac-active-10") : PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-bound-mac-10");
break;
case ValueSource.Default:
- Image = activeImage ? PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-default-mac-active-10") : PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-default-mac-10");
- return;
+ Image = focused ? PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-default-mac-active-10") : PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-default-mac-10");
+ break;
case ValueSource.Local:
- Image = activeImage ? PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-local-mac-active-10") : PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-local-mac-10");
+ Image = focused ? PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-local-mac-active-10") : PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-local-mac-10");
break;
case ValueSource.Inherited:
- Image = activeImage ? PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-inherited-mac-active-10") : PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-inherited-mac-10");
+ Image = focused ? PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-inherited-mac-active-10") : PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-inherited-mac-10");
break;
case ValueSource.Resource:
- Image = activeImage ? PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-inherited-mac-active-10") : PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-inherited-mac-10");
+ Image = focused ? PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-inherited-mac-active-10") : PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-inherited-mac-10");
break;
case ValueSource.Unset:
- Image = activeImage ? PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-default-mac-active-10") : PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-default-mac-10");
+ Image = focused ? PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-default-mac-active-10") : PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-default-mac-10");
break;
default:
// To Handle ValueSource.DefaultStyle, ValueSource.Style etc.
Image = null;
break;
+ }
}
}
@@ -171,7 +167,7 @@ namespace Xamarin.PropertyEditing.Mac
break;
}
- ChangeActiveImage (valueSource, false);
+ UpdateTheme ();
}
private void OnPropertyChanged (object sender, System.ComponentModel.PropertyChangedEventArgs e)
diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/RatioEditor.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/RatioEditor.cs
new file mode 100644
index 0000000..507eee3
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/RatioEditor.cs
@@ -0,0 +1,80 @@
+using System;
+using AppKit;
+using Foundation;
+using Xamarin.PropertyEditing.Drawing;
+using Xamarin.PropertyEditing.Mac;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class RatioEditor<T> : NumericSpinEditor<T>
+ {
+ private bool fullSelection;
+
+ public RatioEditor ()
+ {
+ AllowNegativeValues = false;
+ AllowRatios = true;
+ BackgroundColor = NSColor.Clear;
+ StringValue = string.Empty;
+ TranslatesAutoresizingMaskIntoConstraints = false;
+ }
+
+ protected override void OnEditingEnded (object sender, EventArgs e)
+ {
+ if (!editing) {
+ editing = true;
+ NotifyingValueChanged (new RatioEventArgs (0, 0, 0));
+ editing = false;
+ }
+ }
+
+ protected override void SetIncrementOrDecrementValue (double incDevValue)
+ {
+ nint caretLocation = 0;
+ nint selectionLength = 0;
+
+ GetEditorCaretLocationAndLength (out caretLocation, out selectionLength);
+
+ // Fire A Value change, so things are updated
+ NotifyingValueChanged (new RatioEventArgs ((int)caretLocation, (int)selectionLength, incDevValue));
+
+ // Resposition our caret so it doesn't jump around.
+ SetEditorCaretLocationAndLength (caretLocation, selectionLength);
+ }
+
+ private void SetEditorCaretLocationAndLength (nint caretLocation, nint selectionLength)
+ {
+ if (NumericEditor.CurrentEditor != null) {
+ if (fullSelection && (selectionLength != NumericEditor.StringValue.Length)) {
+ selectionLength = NumericEditor.StringValue.Length;
+ }
+ NumericEditor.CurrentEditor.SelectedRange = new NSRange (caretLocation, selectionLength);
+ }
+ }
+
+ private void GetEditorCaretLocationAndLength (out nint caretLocation, out nint selectionLength)
+ {
+ caretLocation = 0;
+ selectionLength = 0;
+ if (NumericEditor.CurrentEditor != null) {
+ caretLocation = NumericEditor.CurrentEditor.SelectedRange.Location;
+ selectionLength = NumericEditor.CurrentEditor.SelectedRange.Length;
+ fullSelection = NumericEditor.StringValue.Length == selectionLength;
+ }
+ }
+
+ public class RatioEventArgs : EventArgs
+ {
+ public RatioEventArgs (int caretPosition, int selectionLength, double incrementValue)
+ {
+ CaretPosition = caretPosition;
+ SelectionLength = selectionLength;
+ IncrementValue = incrementValue;
+ }
+
+ public int CaretPosition { get; }
+ public int SelectionLength { get; }
+ public double IncrementValue { get; }
+ }
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/SpinnerButton.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/SpinnerButton.cs
new file mode 100644
index 0000000..0ba72dc
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/SpinnerButton.cs
@@ -0,0 +1,49 @@
+using System;
+using AppKit;
+using ObjCRuntime;
+using Xamarin.PropertyEditing.Themes;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ public class UpSpinnerButton : UnfocusableButton
+ {
+ public UpSpinnerButton ()
+ {
+ OnMouseEntered += (sender, e) => {
+ Image = PropertyEditorPanel.ThemeManager.GetImageForTheme ("stepper-up-focus-blue");
+ };
+
+ OnMouseExited += (sender, e) => {
+ Image = PropertyEditorPanel.ThemeManager.GetImageForTheme ("stepper-up");
+ };
+ }
+
+ protected override void UpdateTheme ()
+ {
+ base.UpdateTheme ();
+
+ Image = PropertyEditorPanel.ThemeManager.GetImageForTheme ("stepper-up");
+ }
+ }
+
+ public class DownSpinnerButton : UnfocusableButton
+ {
+ public DownSpinnerButton ()
+ {
+ OnMouseEntered += (sender, e) => {
+ Image = PropertyEditorPanel.ThemeManager.GetImageForTheme ("stepper-down-focus-blue");
+ };
+
+ OnMouseExited += (sender, e) => {
+ Image = PropertyEditorPanel.ThemeManager.GetImageForTheme ("stepper-down");
+ };
+ }
+
+ protected override void UpdateTheme ()
+ {
+ base.UpdateTheme ();
+
+ Image = PropertyEditorPanel.ThemeManager.GetImageForTheme ("stepper-down");
+ }
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/UnfocusableButton.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/UnfocusableButton.cs
new file mode 100644
index 0000000..3a18805
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/UnfocusableButton.cs
@@ -0,0 +1,104 @@
+using System;
+using AppKit;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ public abstract class UnfocusableButton : NSImageView
+ {
+ public event EventHandler OnMouseEntered;
+ public event EventHandler OnMouseExited;
+ public event EventHandler OnMouseLeftDown;
+ public event EventHandler OnMouseRightDown;
+
+ public UnfocusableButton ()
+ {
+ Enabled = true;
+ ImageScaling = NSImageScale.AxesIndependently;
+ TranslatesAutoresizingMaskIntoConstraints = false;
+
+ PropertyEditorPanel.ThemeManager.ThemeChanged += ThemeManager_ThemeChanged;
+
+ UpdateTheme ();
+ }
+
+ #region Overridden Methods
+ protected override void Dispose (bool disposing)
+ {
+ if (disposing) {
+ PropertyEditorPanel.ThemeManager.ThemeChanged -= ThemeManager_ThemeChanged;
+ }
+ }
+
+ public override void MouseDown (NSEvent theEvent)
+ {
+ switch (theEvent.Type) {
+ case NSEventType.LeftMouseDown:
+ NotifyMouseLeftDown ();
+ break;
+
+ case NSEventType.RightMouseDown:
+ NotifyMouseRightDown ();
+ break;
+ }
+ }
+
+ public override void MouseEntered (NSEvent theEvent)
+ {
+ NotifyMouseEntered ();
+ }
+
+ public override void MouseExited (NSEvent theEvent)
+ {
+ NotifyMouseExited ();
+ }
+
+ public override void UpdateTrackingAreas ()
+ {
+ base.UpdateTrackingAreas ();
+
+ foreach (var item in TrackingAreas ()) {
+ RemoveTrackingArea (item);
+ }
+
+ var options = NSTrackingAreaOptions.MouseEnteredAndExited | NSTrackingAreaOptions.ActiveAlways;
+
+ var trackingArea = new NSTrackingArea (this.Bounds, options, this, null);
+
+ AddTrackingArea (trackingArea);
+ }
+ #endregion
+
+
+ #region Local Methods
+ private void NotifyMouseEntered ()
+ {
+ OnMouseEntered?.Invoke (this, EventArgs.Empty);
+ }
+
+ private void NotifyMouseExited ()
+ {
+ OnMouseExited?.Invoke (this, EventArgs.Empty);
+ }
+
+ private void NotifyMouseLeftDown ()
+ {
+ OnMouseLeftDown?.Invoke (this, EventArgs.Empty);
+ }
+
+ private void NotifyMouseRightDown ()
+ {
+ OnMouseRightDown?.Invoke (this, EventArgs.Empty);
+ }
+
+ void ThemeManager_ThemeChanged (object sender, EventArgs e)
+ {
+ UpdateTheme ();
+ }
+
+ protected virtual void UpdateTheme ()
+ {
+ this.Appearance = PropertyEditorPanel.ThemeManager.CurrentAppearance;
+ }
+ #endregion
+ }
+}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/NumericEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/NumericEditorControl.cs
index 916957a..b0ab2b9 100644
--- a/Xamarin.PropertyEditing.Mac/Controls/NumericEditorControl.cs
+++ b/Xamarin.PropertyEditing.Mac/Controls/NumericEditorControl.cs
@@ -57,7 +57,7 @@ namespace Xamarin.PropertyEditing.Mac
}
public override NSView FirstKeyView => NumericEditor;
- public override NSView LastKeyView => NumericEditor;
+ public override NSView LastKeyView => NumericEditor.DecrementButton;
protected NSNumberFormatterStyle NumberStyle {
get {
diff --git a/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs
index 04c7c48..d4cc0d6 100644
--- a/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs
+++ b/Xamarin.PropertyEditing.Mac/Controls/PropertyEditorControl.cs
@@ -54,7 +54,7 @@ namespace Xamarin.PropertyEditing.Mac
}
}
- public void UpdateKeyViews (bool backward = true, bool forward = true)
+ public void UpdateKeyViews ()
{
if (TableRow < 0)
return;
@@ -62,15 +62,17 @@ namespace Xamarin.PropertyEditing.Mac
PropertyEditorControl ctrl = null;
//FIXME: don't hardcode column
- if (backward && TableRow > 0 && (ctrl = TableView.GetView (1, TableRow - 1, false) as PropertyEditorControl) != null) {
- ctrl.LastKeyView.NextKeyView = FirstKeyView;
- ctrl.UpdateKeyViews (forward: false);
- }
-
- //FIXME: don't hardcode column
- if (forward && TableRow < TableView.RowCount - 1 && (ctrl = TableView.GetView (1, TableRow + 1, false) as PropertyEditorControl) != null) {
- LastKeyView.NextKeyView = ctrl.FirstKeyView;
- ctrl.UpdateKeyViews (backward: false);
+ var tr = TableRow;
+ if (tr > 0) {
+ do {
+ tr--;
+ ctrl = TableView.GetView (1, tr, false) as PropertyEditorControl;
+ } while (tr > 0 && ctrl == null);
+
+ if (ctrl != null) {
+ ctrl.LastKeyView.NextKeyView = FirstKeyView;
+ ctrl.UpdateKeyViews ();
+ }
}
}
diff --git a/Xamarin.PropertyEditing.Mac/Controls/RatioEditorControl.cs b/Xamarin.PropertyEditing.Mac/Controls/RatioEditorControl.cs
new file mode 100644
index 0000000..a859652
--- /dev/null
+++ b/Xamarin.PropertyEditing.Mac/Controls/RatioEditorControl.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections;
+using System.ComponentModel;
+using AppKit;
+using Xamarin.PropertyEditing.Mac.Resources;
+using Xamarin.PropertyEditing.ViewModels;
+
+namespace Xamarin.PropertyEditing.Mac
+{
+ internal class RatioEditorControl<T> : PropertyEditorControl<RatioViewModel>
+ {
+ RatioEditor<T> ratioEditor;
+
+ public RatioEditorControl ()
+ {
+ base.TranslatesAutoresizingMaskIntoConstraints = false;
+
+ ratioEditor = new RatioEditor<T> {
+ AllowNegativeValues = false,
+ AllowRatios = true,
+ BackgroundColor = NSColor.Clear,
+ StringValue = string.Empty,
+ TranslatesAutoresizingMaskIntoConstraints = false,
+ };
+
+ // update the value on keypress
+ ratioEditor.ValueChanged += (sender, e) => {
+ if (e is RatioEditor<T>.RatioEventArgs ratioEventArgs) {
+ ViewModel.ValueChanged (ratioEditor.StringValue, ratioEventArgs.CaretPosition, ratioEventArgs.SelectionLength, ratioEventArgs.IncrementValue);
+ }
+ };
+ AddSubview (ratioEditor);
+
+ this.DoConstraints (new[] {
+ ratioEditor.ConstraintTo (this, (re, c) => re.Top == c.Top - 2),
+ ratioEditor.ConstraintTo (this, (re, c) => re.Left == c.Left + 4),
+ ratioEditor.ConstraintTo (this, (re, c) => re.Width == c.Width - 33),
+ ratioEditor.ConstraintTo (this, (re, c) => re.Height == DefaultControlHeight),
+ });
+
+ UpdateTheme ();
+ }
+
+ public override NSView FirstKeyView => ratioEditor.NumericEditor;
+ public override NSView LastKeyView => ratioEditor.DecrementButton;
+
+ protected override void HandleErrorsChanged (object sender, DataErrorsChangedEventArgs e)
+ {
+ UpdateErrorsDisplayed (ViewModel.GetErrors (ViewModel.Property.Name));
+ }
+
+ protected override void SetEnabled ()
+ {
+ ratioEditor.Editable = ViewModel.Property.CanWrite;
+ }
+
+ protected override void UpdateAccessibilityValues ()
+ {
+ ratioEditor.AccessibilityEnabled = ratioEditor.Enabled;
+ ratioEditor.AccessibilityTitle = string.Format (LocalizationResources.AccessibilityNumeric, ViewModel.Property.Name);
+ }
+
+ protected override void UpdateErrorsDisplayed (IEnumerable errors)
+ {
+ if (ViewModel.HasErrors) {
+ SetErrors (errors);
+ } else {
+ SetErrors (null);
+ SetEnabled ();
+ }
+ }
+
+ protected override void UpdateValue ()
+ {
+ ratioEditor.StringValue = ViewModel.ValueString;
+ }
+ }
+}