diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor.cs
deleted file mode 100644
index 881b243f97..0000000000
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-//
-//
-//
-//
-// $Revision$
-//
-
-using System;
-using System.Diagnostics;
-using System.Windows;
-using System.Windows.Data;
-using System.Windows.Controls;
-using System.Windows.Documents;
-using System.Windows.Media;
-using ICSharpCode.WpfDesign.PropertyEditor;
-
-namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors
-{
- ///
- /// Type editor used to edit Brush properties.
- ///
- [TypeEditor(typeof(Brush))]
- public sealed class BrushEditor : DockPanel
- {
- readonly IPropertyEditorDataProperty property;
-
- Border brushShowingBorder = new Border {
- SnapsToDevicePixels = true,
- BorderThickness = new Thickness(1)
- };
- DropDownButton ddb = new DropDownButton {
- HorizontalAlignment = HorizontalAlignment.Right
- };
-
- ///
- /// Creates a new BooleanEditor instance.
- ///
- public BrushEditor(IPropertyEditorDataProperty property)
- {
- this.property = property;
-
- PropertyEditorBindingHelper.AddValueChangedEventHandler(this, property, OnValueChanged);
- OnValueChanged(null, null);
-
- ddb.Click += new RoutedEventHandler(DropDownButtonClick);
- SetDock(ddb, Dock.Right);
- this.Children.Add(ddb);
- this.Children.Add(brushShowingBorder);
-
- this.Unloaded += delegate {
- if (dlg != null)
- dlg.Close();
- };
- }
-
- BrushEditorDialog dlg;
-
- void DropDownButtonClick(object sender, RoutedEventArgs e)
- {
- dlg = new BrushEditorDialog(property);
- Point pos = ddb.PointToScreen(new Point(ddb.ActualWidth, ddb.ActualHeight));
- dlg.Left = pos.X - dlg.Width;
- dlg.Top = pos.Y;
- dlg.SelectedBrush = property.Value as Brush;
- dlg.SelectedBrushChanged += delegate {
- property.Value = dlg.SelectedBrush;
- };
- dlg.Show();
- }
-
- void OnValueChanged(object sender, EventArgs e)
- {
- Brush val = property.Value as Brush;
- brushShowingBorder.Background = val;
- if (val == null) {
- brushShowingBorder.BorderBrush = null;
- } else if (property.IsSet) {
- brushShowingBorder.BorderBrush = Brushes.Black;
- } else {
- brushShowingBorder.BorderBrush = Brushes.Gray;
- }
- }
- }
-}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushEditor.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushEditor.cs
new file mode 100644
index 0000000000..b6a3fa2abd
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushEditor.cs
@@ -0,0 +1,234 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.ComponentModel;
+using ICSharpCode.WpfDesign.PropertyEditor;
+using System.Windows.Media;
+using System.Reflection;
+using System.Windows;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ public enum BrushEditorKind
+ {
+ None,
+ Solid,
+ Linear,
+ Radial,
+ List
+ }
+
+ public class BrushItem
+ {
+ public string Name { get; set; }
+ public Brush Brush { get; set; }
+ }
+
+ public class BrushEditor : INotifyPropertyChanged
+ {
+ public BrushEditor()
+ {
+ GradientStopCollection stops = new GradientStopCollection();
+ stops.Add(new GradientStop(Colors.Black, 0));
+ stops.Add(new GradientStop(Colors.White, 1));
+
+ linearGradientBrush = new LinearGradientBrush(stops);
+ linearGradientBrush.EndPoint = new Point(1, 0);
+ radialGradientBrush = new RadialGradientBrush(stops);
+ }
+
+ public static BrushEditor Instance = new BrushEditor();
+
+ public static BrushItem[] SystemBrushes = typeof(SystemColors)
+ .GetProperties(BindingFlags.Static | BindingFlags.Public)
+ .Where(p => p.PropertyType == typeof(SolidColorBrush))
+ .Select(p => new BrushItem() { Name = p.Name, Brush = (Brush)p.GetValue(null, null) })
+ .ToArray();
+
+ public static BrushItem[] SystemColors = typeof(SystemColors)
+ .GetProperties(BindingFlags.Static | BindingFlags.Public)
+ .Where(p => p.PropertyType == typeof(Color))
+ .Select(p => new BrushItem()
+ {
+ Name = p.Name,
+ Brush = new SolidColorBrush((Color)p.GetValue(null, null))
+ })
+ .ToArray();
+
+ SolidColorBrush solidColorBrush = new SolidColorBrush(Colors.White);
+ LinearGradientBrush linearGradientBrush;
+ RadialGradientBrush radialGradientBrush;
+
+ IPropertyEditorDataProperty property;
+
+ public IPropertyEditorDataProperty Property
+ {
+ get
+ {
+ return property;
+ }
+ set
+ {
+ property = value;
+ if (property != null)
+ {
+ var f = property.Value as Freezable;
+ if (f != null && f.IsFrozen) property.Value = f.Clone();
+ }
+ DetermineCurrentKind();
+ RaisePropertyChanged("Property");
+ RaisePropertyChanged("Brush");
+ }
+ }
+
+ public Brush Brush
+ {
+ get
+ {
+ if (property != null)
+ {
+ return property.Value as Brush;
+ }
+ return null;
+ }
+ set
+ {
+ if (property != null && property.Value != value)
+ {
+ if (value != null && value.IsFrozen)
+ {
+ value = value.Clone();
+ }
+ property.Value = value;
+ DetermineCurrentKind();
+ RaisePropertyChanged("Brush");
+ }
+ }
+ }
+
+ void DetermineCurrentKind()
+ {
+ if (Brush == null)
+ {
+ CurrentKind = BrushEditorKind.None;
+ }
+ else if (Brush is SolidColorBrush)
+ {
+ solidColorBrush = Brush as SolidColorBrush;
+ CurrentKind = BrushEditorKind.Solid;
+ }
+ else if (Brush is LinearGradientBrush)
+ {
+ linearGradientBrush = Brush as LinearGradientBrush;
+ radialGradientBrush.GradientStops = linearGradientBrush.GradientStops;
+ CurrentKind = BrushEditorKind.Linear;
+ }
+ else if (Brush is RadialGradientBrush)
+ {
+ radialGradientBrush = Brush as RadialGradientBrush;
+ linearGradientBrush.GradientStops = linearGradientBrush.GradientStops;
+ CurrentKind = BrushEditorKind.Radial;
+ }
+ }
+
+ BrushEditorKind currentKind;
+
+ public BrushEditorKind CurrentKind
+ {
+ get
+ {
+ return currentKind;
+ }
+ set
+ {
+ currentKind = value;
+ RaisePropertyChanged("CurrentKind");
+
+ switch (CurrentKind)
+ {
+ case BrushEditorKind.None:
+ Brush = null;
+ break;
+
+ case BrushEditorKind.Solid:
+ Brush = solidColorBrush;
+ break;
+
+ case BrushEditorKind.Linear:
+ Brush = linearGradientBrush;
+ break;
+
+ case BrushEditorKind.Radial:
+ Brush = radialGradientBrush;
+ break;
+
+ case BrushEditorKind.List:
+ Brush = solidColorBrush;
+ break;
+ }
+ }
+ }
+
+ public double GradientAngle
+ {
+ get
+ {
+ var x = linearGradientBrush.EndPoint.X - linearGradientBrush.StartPoint.X;
+ var y = linearGradientBrush.EndPoint.Y - linearGradientBrush.StartPoint.Y;
+ return Vector.AngleBetween(new Vector(1, 0), new Vector(x, -y));
+ }
+ set
+ {
+ var d = value * Math.PI / 180;
+ var p = new Point(Math.Cos(d), -Math.Sin(d));
+ var k = 1 / Math.Max(Math.Abs(p.X), Math.Abs(p.Y));
+ p.X *= k;
+ p.Y *= k;
+ var p2 = new Point(-p.X, -p.Y);
+ linearGradientBrush.StartPoint = new Point((p2.X + 1) / 2, (p2.Y + 1) / 2);
+ linearGradientBrush.EndPoint = new Point((p.X + 1) / 2, (p.Y + 1) / 2);
+ RaisePropertyChanged("GradientAngle");
+ }
+ }
+
+ public IEnumerable AvailableColors
+ {
+ get { return SystemColors; }
+ }
+
+ public IEnumerable AvailableBrushes
+ {
+ get { return SystemBrushes; }
+ }
+
+ public void MakeGradientHorizontal()
+ {
+ GradientAngle = 0;
+ }
+
+ public void MakeGradientVertical()
+ {
+ GradientAngle = -90;
+ }
+
+ public void Commit()
+ {
+ Property.Value = Property.Value;
+ }
+
+ #region INotifyPropertyChanged Members
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ void RaisePropertyChanged(string name)
+ {
+ if (PropertyChanged != null)
+ {
+ PropertyChanged(this, new PropertyChangedEventArgs(name));
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushEditorPopup.xaml b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushEditorPopup.xaml
new file mode 100644
index 0000000000..ca14c05174
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushEditorPopup.xaml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushEditorPopup.xaml.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushEditorPopup.xaml.cs
new file mode 100644
index 0000000000..cb67d876c8
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushEditorPopup.xaml.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Diagnostics;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ public partial class BrushEditorPopup
+ {
+ public BrushEditorPopup()
+ {
+ InitializeComponent();
+ }
+
+ public static BrushEditorPopup Instance = new BrushEditorPopup();
+
+ protected override void OnClosed(EventArgs e)
+ {
+ base.OnClosed(e);
+ BrushEditor.Instance.Commit();
+ }
+
+ protected override void OnKeyDown(KeyEventArgs e)
+ {
+ if (e.Key == Key.Escape) IsOpen = false;
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushEditorView.xaml b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushEditorView.xaml
new file mode 100644
index 0000000000..ad30afbf41
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushEditorView.xaml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushEditorView.xaml.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushEditorView.xaml.cs
new file mode 100644
index 0000000000..47b2ca69e3
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushEditorView.xaml.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Diagnostics;
+using System.Globalization;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ public partial class BrushEditorView
+ {
+ public BrushEditorView()
+ {
+ InitializeComponent();
+
+ SetBinding(HeightProperty, new Binding("Brush")
+ {
+ Converter = HeightConverter.Instance
+ });
+ }
+
+ class HeightConverter : IValueConverter
+ {
+ public static HeightConverter Instance = new HeightConverter();
+
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (value is GradientBrush) return double.NaN;
+ return 315;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushTypeEditor.xaml b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushTypeEditor.xaml
new file mode 100644
index 0000000000..b1ed3ca2ed
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushTypeEditor.xaml
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushTypeEditor.xaml.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushTypeEditor.xaml.cs
new file mode 100644
index 0000000000..e43b28ea24
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/BrushTypeEditor.xaml.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using ICSharpCode.WpfDesign.PropertyEditor;
+using System.Windows.Controls.Primitives;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ [TypeEditor(typeof(Brush))]
+ public partial class BrushTypeEditor
+ {
+ public BrushTypeEditor(IPropertyEditorDataProperty property)
+ {
+ this.property = property;
+ DataContext = property;
+ InitializeComponent();
+ }
+
+ IPropertyEditorDataProperty property;
+
+ protected override void OnMouseUp(MouseButtonEventArgs e)
+ {
+ BrushEditor.Instance.Property = property;
+ BrushEditorPopup.Instance.PlacementTarget = this;
+ BrushEditorPopup.Instance.IsOpen = true;
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/CallExtension.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/CallExtension.cs
new file mode 100644
index 0000000000..8f8c447987
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/CallExtension.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows.Markup;
+using System.Windows;
+using System.Windows.Data;
+using System.Windows.Input;
+using System.Reflection;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ public class CallExtension : MarkupExtension
+ {
+ public CallExtension(string methodName)
+ {
+ this.methodName = methodName;
+ }
+
+ string methodName;
+
+ public override object ProvideValue(IServiceProvider sp)
+ {
+ var t = (IProvideValueTarget)sp.GetService(typeof(IProvideValueTarget));
+ return new CallCommand(t.TargetObject as FrameworkElement, methodName);
+ }
+ }
+
+ public class CallCommand : DependencyObject, ICommand
+ {
+ public CallCommand(FrameworkElement element, string methodName)
+ {
+ this.element = element;
+ this.methodName = methodName;
+ element.DataContextChanged += target_DataContextChanged;
+
+ BindingOperations.SetBinding(this, CanCallProperty, new Binding("DataContext.Can" + methodName)
+ {
+ Source = element
+ });
+
+ GetMethod();
+ }
+
+ FrameworkElement element;
+ string methodName;
+ MethodInfo method;
+
+ public static readonly DependencyProperty CanCallProperty =
+ DependencyProperty.Register("CanCall", typeof(bool), typeof(CallCommand),
+ new PropertyMetadata(true));
+
+ public bool CanCall
+ {
+ get { return (bool)GetValue(CanCallProperty); }
+ set { SetValue(CanCallProperty, value); }
+ }
+
+ public object DataContext
+ {
+ get { return element.DataContext; }
+ }
+
+ protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
+ {
+ base.OnPropertyChanged(e);
+
+ if (e.Property == CanCallProperty)
+ {
+ RaiseCanExecuteChanged();
+ }
+ }
+
+ void GetMethod()
+ {
+ if (DataContext == null)
+ {
+ method = null;
+ }
+ else
+ {
+ method = DataContext.GetType().GetMethod(methodName, Type.EmptyTypes);
+ }
+ }
+
+ void target_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
+ {
+ GetMethod();
+ RaiseCanExecuteChanged();
+ }
+
+ void RaiseCanExecuteChanged()
+ {
+ if (CanExecuteChanged != null)
+ {
+ CanExecuteChanged(this, EventArgs.Empty);
+ }
+ }
+
+ #region ICommand Members
+
+ public event EventHandler CanExecuteChanged;
+
+ public bool CanExecute(object parameter)
+ {
+ return method != null && CanCall;
+ }
+
+ public void Execute(object parameter)
+ {
+ method.Invoke(DataContext, null);
+ }
+
+ #endregion
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/ColorHelper.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/ColorHelper.cs
new file mode 100644
index 0000000000..28122b56b7
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/ColorHelper.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows.Media;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ public static class ColorHelper
+ {
+ public static Color ColorFromString(string s)
+ {
+ if (string.IsNullOrEmpty(s))
+ {
+ return Colors.White;
+ }
+ if (s[0] != '#') s = "#" + s;
+ try
+ {
+ return (Color)ColorConverter.ConvertFromString(s);
+ }
+ catch
+ {
+ return Colors.White;
+ }
+ }
+
+ public static string StringFromColor(Color c)
+ {
+ return c.ToString().Substring(1);
+ }
+
+ public static Color ColorFromHsv(double h, double s, double v)
+ {
+ double r, g, b;
+ RgbFromHsv(h, s, v, out r, out g, out b);
+ return Color.FromRgb((byte)(r * 255), (byte)(g * 255), (byte)(b * 255));
+
+ }
+
+ public static void HsvFromColor(Color c, out double h, out double s, out double v)
+ {
+ HsvFromRgb(c.R / 255, c.G / 255, c.B / 255, out h, out s, out v);
+ }
+
+ // http://en.wikipedia.org/wiki/HSV_color_space
+ public static void HsvFromRgb(double r, double g, double b, out double h, out double s, out double v)
+ {
+ var max = Math.Max(r, Math.Max(g, b));
+ var min = Math.Min(r, Math.Min(g, b));
+
+ if (max == min)
+ {
+ h = 0;
+ }
+ else if (max == r)
+ {
+ h = (60 * (g - b) / (max - min)) % 360;
+ }
+ else if (max == g)
+ {
+ h = 60 * (b - r) / (max - min) + 120;
+ }
+ else // if (max == b)
+ {
+ h = 60 * (r - g) / (max - min) + 240;
+ }
+
+ if (max == 0)
+ {
+ s = 0;
+ }
+ else
+ {
+ s = 1 - min / max;
+ }
+
+ v = max;
+ }
+
+ // http://en.wikipedia.org/wiki/HSV_color_space
+ public static void RgbFromHsv(double h, double s, double v, out double r, out double g, out double b)
+ {
+ h = h % 360;
+ int hi = (int)(h / 60) % 6;
+ var f = h / 60 - (int)(h / 60);
+ var p = v * (1 - s);
+ var q = v * (1 - f * s);
+ var t = v * (1 - (1 - f) * s);
+
+ switch (hi)
+ {
+ case 0: r = v; g = t; b = p; break;
+ case 1: r = q; g = v; b = p; break;
+ case 2: r = p; g = v; b = t; break;
+ case 3: r = p; g = q; b = v; break;
+ case 4: r = t; g = p; b = v; break;
+ default: r = v; g = p; b = q; break;
+ }
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/ColorPicker.xaml b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/ColorPicker.xaml
new file mode 100644
index 0000000000..ebcfb36896
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/ColorPicker.xaml
@@ -0,0 +1,232 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/ColorPicker.xaml.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/ColorPicker.xaml.cs
new file mode 100644
index 0000000000..d129c94747
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/ColorPicker.xaml.cs
@@ -0,0 +1,203 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.ComponentModel;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ public partial class ColorPicker
+ {
+ public ColorPicker()
+ {
+ InitializeComponent();
+ }
+
+ public static readonly DependencyProperty ColorProperty =
+ DependencyProperty.Register("Color", typeof(Color), typeof(ColorPicker),
+ new FrameworkPropertyMetadata(new Color(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
+
+ public Color Color
+ {
+ get { return (Color)GetValue(ColorProperty); }
+ set { SetValue(ColorProperty, value); }
+ }
+
+ public static readonly DependencyProperty HProperty =
+ DependencyProperty.Register("H", typeof(int), typeof(ColorPicker));
+
+ public int H
+ {
+ get { return (int)GetValue(HProperty); }
+ set { SetValue(HProperty, value); }
+ }
+
+ public static readonly DependencyProperty SProperty =
+ DependencyProperty.Register("S", typeof(int), typeof(ColorPicker));
+
+ public int S
+ {
+ get { return (int)GetValue(SProperty); }
+ set { SetValue(SProperty, value); }
+ }
+
+ public static readonly DependencyProperty VProperty =
+ DependencyProperty.Register("V", typeof(int), typeof(ColorPicker));
+
+ public int V
+ {
+ get { return (int)GetValue(VProperty); }
+ set { SetValue(VProperty, value); }
+ }
+
+ public static readonly DependencyProperty RProperty =
+ DependencyProperty.Register("R", typeof(byte), typeof(ColorPicker));
+
+ public byte R
+ {
+ get { return (byte)GetValue(RProperty); }
+ set { SetValue(RProperty, value); }
+ }
+
+ public static readonly DependencyProperty GProperty =
+ DependencyProperty.Register("G", typeof(byte), typeof(ColorPicker));
+
+ public byte G
+ {
+ get { return (byte)GetValue(GProperty); }
+ set { SetValue(GProperty, value); }
+ }
+
+ public static readonly DependencyProperty BProperty =
+ DependencyProperty.Register("B", typeof(byte), typeof(ColorPicker));
+
+ public byte B
+ {
+ get { return (byte)GetValue(BProperty); }
+ set { SetValue(BProperty, value); }
+ }
+
+ public static readonly DependencyProperty AProperty =
+ DependencyProperty.Register("A", typeof(byte), typeof(ColorPicker));
+
+ public byte A
+ {
+ get { return (byte)GetValue(AProperty); }
+ set { SetValue(AProperty, value); }
+ }
+
+ public static readonly DependencyProperty HexProperty =
+ DependencyProperty.Register("Hex", typeof(string), typeof(ColorPicker));
+
+ public string Hex
+ {
+ get { return (string)GetValue(HexProperty); }
+ set { SetValue(HexProperty, value); }
+ }
+
+ public static readonly DependencyProperty HueColorProperty =
+ DependencyProperty.Register("HueColor", typeof(Color), typeof(ColorPicker));
+
+ public Color HueColor
+ {
+ get { return (Color)GetValue(HueColorProperty); }
+ set { SetValue(HueColorProperty, value); }
+ }
+
+ bool updating;
+
+ protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
+ {
+ base.OnPropertyChanged(e);
+
+ if (updating) return;
+ updating = true;
+
+ if (e.Property == ColorProperty)
+ {
+ UpdateSource(ColorSource.Hsv);
+ UpdateRest(ColorSource.Hsv);
+ }
+ else if (e.Property == HProperty || e.Property == SProperty || e.Property == VProperty)
+ {
+ var c = ColorHelper.ColorFromHsv(H, S / 100.0, V / 100.0);
+ c.A = A;
+ Color = c;
+ UpdateRest(ColorSource.Hsv);
+ }
+ else if (e.Property == RProperty || e.Property == GProperty || e.Property == BProperty || e.Property == AProperty)
+ {
+ Color = Color.FromArgb(A, R, G, B);
+ UpdateRest(ColorSource.Rgba);
+ }
+ else if (e.Property == HexProperty)
+ {
+ Color = ColorHelper.ColorFromString(Hex);
+ UpdateRest(ColorSource.Hex);
+ }
+
+ updating = false;
+ }
+
+ void UpdateRest(ColorSource source)
+ {
+ HueColor = ColorHelper.ColorFromHsv(H, 1, 1);
+ UpdateSource((ColorSource)(((int)source + 1) % 3));
+ UpdateSource((ColorSource)(((int)source + 2) % 3));
+ }
+
+ void UpdateSource(ColorSource source)
+ {
+ if (source == ColorSource.Hsv)
+ {
+ double h, s, v;
+ ColorHelper.HsvFromColor(Color, out h, out s, out v);
+
+ H = (int)h;
+ S = (int)(s * 100);
+ V = (int)(v * 100);
+ }
+ else if (source == ColorSource.Rgba)
+ {
+ R = Color.R;
+ G = Color.G;
+ B = Color.B;
+ A = Color.A;
+ }
+ else
+ {
+ Hex = ColorHelper.StringFromColor(Color);
+ }
+ }
+
+ enum ColorSource
+ {
+ Hsv, Rgba, Hex
+ }
+ }
+
+ public class EnterTextBox : TextBox
+ {
+ protected override void OnKeyDown(KeyEventArgs e)
+ {
+ if (e.Key == Key.Enter)
+ {
+ SelectAll();
+ var b = BindingOperations.GetBindingExpressionBase(this, TextProperty);
+ if (b != null)
+ {
+ b.UpdateTarget();
+ }
+ }
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/Converters.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/Converters.cs
new file mode 100644
index 0000000000..ac3c1e5b9e
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/Converters.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows.Data;
+using System.Globalization;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ public class IntFromEnumConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return (int)value;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return Enum.ToObject(targetType, (int)value);
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/DragListener.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/DragListener.cs
new file mode 100644
index 0000000000..74688f1e0c
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/DragListener.cs
@@ -0,0 +1,118 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Input;
+using System.Diagnostics;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ public delegate void DragHandler(DragListener drag);
+
+ public class DragListener
+ {
+ static DragListener()
+ {
+ InputManager.Current.PostProcessInput += new ProcessInputEventHandler(PostProcessInput);
+ }
+
+ public DragListener(IInputElement target)
+ {
+ Target = target;
+
+ Target.PreviewMouseLeftButtonDown += Target_MouseDown;
+ Target.PreviewMouseMove += Target_MouseMove;
+ Target.PreviewMouseLeftButtonUp += Target_MouseUp;
+ }
+
+ static DragListener CurrentListener;
+
+ static void PostProcessInput(object sender, ProcessInputEventArgs e)
+ {
+ if (CurrentListener != null)
+ {
+ var a = e.StagingItem.Input as KeyEventArgs;
+ if (a != null && a.Key == Key.Escape)
+ {
+ Mouse.Capture(null);
+ CurrentListener.IsDown = false;
+ CurrentListener.Complete();
+ }
+ }
+ }
+
+ void Target_MouseDown(object sender, MouseButtonEventArgs e)
+ {
+ StartPoint = Mouse.GetPosition(null);
+ CurrentPoint = StartPoint;
+ DeltaDelta = new Vector();
+ IsDown = true;
+
+ if (Started != null)
+ {
+ Started(this);
+ }
+ }
+
+ void Target_MouseMove(object sender, MouseEventArgs e)
+ {
+ if (IsDown)
+ {
+ DeltaDelta = e.GetPosition(null) - CurrentPoint;
+ CurrentPoint += DeltaDelta;
+
+ if (!IsActive)
+ {
+ if (Math.Abs(Delta.X) >= SystemParameters.MinimumHorizontalDragDistance ||
+ Math.Abs(Delta.Y) >= SystemParameters.MinimumVerticalDragDistance)
+ {
+ IsActive = true;
+ CurrentListener = this;
+ }
+ }
+
+ if (IsActive && Changed != null)
+ {
+ Changed(this);
+ }
+ }
+ }
+
+ void Target_MouseUp(object sender, MouseButtonEventArgs e)
+ {
+ IsDown = false;
+ if (IsActive)
+ {
+ Complete();
+ }
+ }
+
+ void Complete()
+ {
+ IsActive = false;
+ CurrentListener = null;
+
+ if (Completed != null)
+ {
+ Completed(this);
+ }
+ }
+
+ public event DragHandler Started;
+ public event DragHandler Changed;
+ public event DragHandler Completed;
+
+ public IInputElement Target { get; private set; }
+ public Point StartPoint { get; private set; }
+ public Point CurrentPoint { get; private set; }
+ public Vector DeltaDelta { get; private set; }
+ public bool IsActive { get; private set; }
+ public bool IsDown { get; private set; }
+
+ public Vector Delta
+ {
+ get { return CurrentPoint - StartPoint; }
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/ExtensionMethods.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/ExtensionMethods.cs
new file mode 100644
index 0000000000..247113e3ba
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/ExtensionMethods.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Reflection;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ public static class ExtensionMethods
+ {
+ //public static T[] GetValues(this Type type)
+ //{
+ // return type
+ // .GetProperties(BindingFlags.Static | BindingFlags.Public)
+ // .Select(p => p.GetValue(null, null)).OfType().ToArray();
+ //}
+
+ public static double Coerce(this double d, double min, double max)
+ {
+ return Math.Max(Math.Min(d, max), min);
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/GradientBrushEditor.xaml b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/GradientBrushEditor.xaml
new file mode 100644
index 0000000000..e1208909e9
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/GradientBrushEditor.xaml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/GradientBrushEditor.xaml.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/GradientBrushEditor.xaml.cs
new file mode 100644
index 0000000000..03d88b68ca
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/GradientBrushEditor.xaml.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ public partial class GradientBrushEditor
+ {
+ public GradientBrushEditor()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/GradientSlider.xaml b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/GradientSlider.xaml
new file mode 100644
index 0000000000..a5e81ccd6f
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/GradientSlider.xaml
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/GradientSlider.xaml.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/GradientSlider.xaml.cs
new file mode 100644
index 0000000000..9041ee48d5
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/GradientSlider.xaml.cs
@@ -0,0 +1,169 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Windows.Controls.Primitives;
+using System.ComponentModel;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ public partial class GradientSlider
+ {
+ public GradientSlider()
+ {
+ InitializeComponent();
+
+ BindingOperations.SetBinding(this, SelectedStopProperty, new Binding("SelectedItem")
+ {
+ Source = itemsControl,
+ Mode = BindingMode.TwoWay
+ });
+
+ strip.DragStarted += new DragStartedEventHandler(strip_DragStarted);
+ strip.DragDelta += new DragDeltaEventHandler(strip_DragDelta);
+ }
+
+ static GradientSlider()
+ {
+ EventManager.RegisterClassHandler(typeof(GradientSlider),
+ Thumb.DragDeltaEvent, new DragDeltaEventHandler(ClassDragDelta));
+ }
+
+ GradientStop newStop;
+ double startOffset;
+
+ public static readonly DependencyProperty BrushProperty =
+ DependencyProperty.Register("Brush", typeof(GradientBrush), typeof(GradientSlider));
+
+ public GradientBrush Brush
+ {
+ get { return (GradientBrush)GetValue(BrushProperty); }
+ set { SetValue(BrushProperty, value); }
+ }
+
+ public static readonly DependencyProperty SelectedStopProperty =
+ DependencyProperty.Register("SelectedStop", typeof(GradientStop), typeof(GradientSlider));
+
+ public GradientStop SelectedStop
+ {
+ get { return (GradientStop)GetValue(SelectedStopProperty); }
+ set { SetValue(SelectedStopProperty, value); }
+ }
+
+ public static readonly DependencyProperty GradientStopsProperty =
+ DependencyProperty.Register("GradientStops", typeof(BindingList), typeof(GradientSlider));
+
+ public BindingList GradientStops
+ {
+ get { return (BindingList)GetValue(GradientStopsProperty); }
+ set { SetValue(GradientStopsProperty, value); }
+ }
+
+ public static Color GetColorAtOffset(IList stops, double offset)
+ {
+ GradientStop s1 = stops[0], s2 = stops.Last();
+ foreach (var item in stops)
+ {
+ if (item.Offset < offset && item.Offset > s1.Offset) s1 = item;
+ if (item.Offset > offset && item.Offset < s2.Offset) s2 = item;
+ }
+ return Color.FromArgb(
+ (byte)((s1.Color.A + s2.Color.A) / 2),
+ (byte)((s1.Color.R + s2.Color.R) / 2),
+ (byte)((s1.Color.G + s2.Color.G) / 2),
+ (byte)((s1.Color.B + s2.Color.B) / 2)
+ );
+ }
+
+ static void ClassDragDelta(object sender, DragDeltaEventArgs e)
+ {
+ (sender as GradientSlider).thumb_DragDelta(sender, e);
+ }
+
+ protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
+ {
+ base.OnPropertyChanged(e);
+
+ if (e.Property == BrushProperty)
+ {
+ if (Brush != null)
+ {
+ GradientStops = new BindingList(Brush.GradientStops);
+ SelectedStop = GradientStops.FirstOrDefault();
+ }
+ else
+ {
+ GradientStops = null;
+ }
+ }
+ }
+
+ void strip_DragStarted(object sender, DragStartedEventArgs e)
+ {
+ startOffset = e.HorizontalOffset / strip.ActualWidth;
+ newStop = new GradientStop(GetColorAtOffset(GradientStops, startOffset), startOffset);
+ GradientStops.Add(newStop);
+ SelectedStop = newStop;
+ e.Handled = true;
+ }
+
+ void strip_DragDelta(object sender, DragDeltaEventArgs e)
+ {
+ MoveStop(newStop, startOffset, e);
+ e.Handled = true;
+ }
+
+ void thumb_DragDelta(object sender, DragDeltaEventArgs e)
+ {
+ var stop = (e.OriginalSource as GradientThumb).GradientStop;
+ MoveStop(stop, stop.Offset, e);
+ }
+
+ void MoveStop(GradientStop stop, double oldOffset, DragDeltaEventArgs e)
+ {
+ if (e.VerticalChange > 50 && GradientStops.Count > 2)
+ {
+ GradientStops.Remove(stop);
+ SelectedStop = GradientStops.FirstOrDefault();
+ return;
+ }
+ stop.Offset = (oldOffset + e.HorizontalChange / strip.ActualWidth).Coerce(0, 1);
+ }
+ }
+
+ public class GradientItemsControl : Selector
+ {
+ protected override DependencyObject GetContainerForItemOverride()
+ {
+ return new GradientThumb();
+ }
+ }
+
+ public class GradientThumb : Thumb
+ {
+ public GradientStop GradientStop
+ {
+ get { return DataContext as GradientStop; }
+ }
+
+ protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
+ {
+ base.OnPreviewMouseDown(e);
+ var itemsControl = ItemsControl.ItemsControlFromItemContainer(this) as GradientItemsControl;
+ itemsControl.SelectedItem = GradientStop;
+ }
+ }
+
+ public class Dragger : Thumb
+ {
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/NormalizedPanel.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/NormalizedPanel.cs
new file mode 100644
index 0000000000..3cc60cd2cc
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/NormalizedPanel.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Controls;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ public class NormalizedPanel : Panel
+ {
+ public static double GetX(DependencyObject obj)
+ {
+ return (double)obj.GetValue(XProperty);
+ }
+
+ public static void SetX(DependencyObject obj, double value)
+ {
+ obj.SetValue(XProperty, value);
+ }
+
+ public static readonly DependencyProperty XProperty =
+ DependencyProperty.RegisterAttached("X", typeof(double), typeof(NormalizedPanel),
+ new PropertyMetadata(OnPositioningChanged));
+
+ public static double GetY(DependencyObject obj)
+ {
+ return (double)obj.GetValue(YProperty);
+ }
+
+ public static void SetY(DependencyObject obj, double value)
+ {
+ obj.SetValue(YProperty, value);
+ }
+
+ public static readonly DependencyProperty YProperty =
+ DependencyProperty.RegisterAttached("Y", typeof(double), typeof(NormalizedPanel),
+ new PropertyMetadata(OnPositioningChanged));
+
+ static void OnPositioningChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ NormalizedPanel parent = VisualTreeHelper.GetParent(d) as NormalizedPanel;
+ if (parent != null)
+ {
+ parent.InvalidateArrange();
+ }
+ }
+
+ protected override Size MeasureOverride(Size availableSize)
+ {
+ foreach (UIElement item in Children)
+ {
+ item.Measure(availableSize);
+ }
+ return new Size();
+ }
+
+ protected override Size ArrangeOverride(Size finalSize)
+ {
+ foreach (UIElement item in Children)
+ {
+ Rect r = new Rect(item.DesiredSize);
+ r.X = GetX(item) * finalSize.Width - item.DesiredSize.Width / 2;
+ r.Y = GetY(item) * finalSize.Height - item.DesiredSize.Height / 2;
+ item.Arrange(r);
+ }
+ return finalSize;
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/NumericUpDown.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/NumericUpDown.cs
new file mode 100644
index 0000000000..d6792119cd
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/NumericUpDown.cs
@@ -0,0 +1,253 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Windows.Controls.Primitives;
+using System.Globalization;
+using System.Diagnostics;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ public class NumericUpDown : RangeBase
+ {
+ static NumericUpDown()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericUpDown),
+ new FrameworkPropertyMetadata(typeof(NumericUpDown)));
+ }
+
+ TextBox textBox;
+ DragRepeatButton upButton;
+ DragRepeatButton downButton;
+
+ bool IsDragging
+ {
+ get
+ {
+ return upButton.IsDragging;
+ }
+ set
+ {
+ upButton.IsDragging = value; downButton.IsDragging = value;
+ }
+ }
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ upButton = (DragRepeatButton)Template.FindName("PART_UpButton", this);
+ downButton = (DragRepeatButton)Template.FindName("PART_DownButton", this);
+ textBox = (TextBox)Template.FindName("PART_TextBox", this);
+
+ upButton.Click += new RoutedEventHandler(upButton_Click);
+ downButton.Click += new RoutedEventHandler(downButton_Click);
+
+ var upDrag = new DragListener(upButton);
+ var downDrag = new DragListener(downButton);
+
+ upDrag.Changed += drag_Changed;
+ downDrag.Changed += drag_Changed;
+ upDrag.Completed += drag_Completed;
+ downDrag.Completed += drag_Completed;
+
+ Print();
+ }
+
+ void drag_Changed(DragListener drag)
+ {
+ IsDragging = true;
+ UpdateValue(-drag.DeltaDelta.Y);
+ }
+
+ void drag_Completed(DragListener drag)
+ {
+ IsDragging = false;
+ }
+
+ void downButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (!IsDragging) SmallDown();
+ }
+
+ void upButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (!IsDragging) SmallUp();
+ }
+
+ public void SmallUp()
+ {
+ UpdateValue(SmallChange);
+ }
+
+ public void SmallDown()
+ {
+ UpdateValue(-SmallChange);
+ }
+
+ public void LargeUp()
+ {
+ UpdateValue(LargeChange);
+ }
+
+ public void LargeDown()
+ {
+ UpdateValue(-LargeChange);
+ }
+
+ public void Minimize()
+ {
+ Parse();
+ Value = Minimum;
+ }
+
+ public void Maximize()
+ {
+ Parse();
+ Value = Maximum;
+ }
+
+ void UpdateValue(double delta)
+ {
+ Parse();
+ SetValue(Value + delta);
+ }
+
+ void Parse()
+ {
+ double result;
+ if (double.TryParse(textBox.Text, out result))
+ {
+ SetValue(result);
+ }
+ else
+ {
+ Print();
+ }
+ }
+
+ void Print()
+ {
+ if (textBox != null)
+ {
+ textBox.Text = Value.ToString();
+ textBox.CaretIndex = int.MaxValue;
+ }
+ }
+
+ //wpf bug?: Value = -1 updates bindings without coercing
+ //workaround
+ void SetValue(double newValue)
+ {
+ newValue = (double)Math.Max(Minimum, Math.Min(newValue, Maximum));
+ if (Value != newValue)
+ {
+ Value = newValue;
+ }
+ }
+
+ protected override void OnValueChanged(double oldValue, double newValue)
+ {
+ base.OnValueChanged(oldValue, newValue);
+ Print();
+ }
+
+ protected override void OnPreviewKeyDown(KeyEventArgs e)
+ {
+ base.OnPreviewKeyDown(e);
+ if (e.Key == Key.Enter)
+ {
+ Parse();
+ textBox.SelectAll();
+ e.Handled = true;
+ }
+ else if (e.Key == Key.Up)
+ {
+ SmallUp();
+ e.Handled = true;
+ }
+ else if (e.Key == Key.Down)
+ {
+ SmallDown();
+ e.Handled = true;
+ }
+ else if (e.Key == Key.PageUp)
+ {
+ LargeUp();
+ e.Handled = true;
+ }
+ else if (e.Key == Key.PageDown)
+ {
+ LargeDown();
+ e.Handled = true;
+ }
+ else if (e.Key == Key.Home)
+ {
+ Maximize();
+ e.Handled = true;
+ }
+ else if (e.Key == Key.End)
+ {
+ Minimize();
+ e.Handled = true;
+ }
+ }
+
+ protected override void OnMouseWheel(MouseWheelEventArgs e)
+ {
+ if (e.Delta > 0)
+ {
+ if (Keyboard.IsKeyDown(Key.LeftShift))
+ {
+ LargeUp();
+ }
+ else
+ {
+ SmallUp();
+ }
+ }
+ else
+ {
+ if (Keyboard.IsKeyDown(Key.LeftShift))
+ {
+ LargeDown();
+ }
+ else
+ {
+ SmallDown();
+ }
+ }
+ }
+
+ protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
+ {
+ base.OnPropertyChanged(e);
+ if (e.Property == SmallChangeProperty &&
+ ReadLocalValue(LargeChangeProperty) == DependencyProperty.UnsetValue)
+ {
+ LargeChange = SmallChange * 10;
+ }
+ }
+ }
+
+ public class DragRepeatButton : RepeatButton
+ {
+ public static readonly DependencyProperty IsDraggingProperty =
+ DependencyProperty.Register("IsDragging", typeof(bool), typeof(DragRepeatButton));
+
+ public bool IsDragging
+ {
+ get { return (bool)GetValue(IsDraggingProperty); }
+ set { SetValue(IsDraggingProperty, value); }
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/NumericUpDown.xaml b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/NumericUpDown.xaml
new file mode 100644
index 0000000000..0c81ca99ec
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/NumericUpDown.xaml
@@ -0,0 +1,134 @@
+
+
+ #B6CEFB
+ #C7DFFF
+ #9CB1D8
+ #FF7F9DB9
+
+
+
+
+
+
+
+
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/Picker.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/Picker.cs
new file mode 100644
index 0000000000..d4b5f73e88
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/Picker.cs
@@ -0,0 +1,150 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows.Controls.Primitives;
+using System.Windows;
+using System.Windows.Input;
+using System.Windows.Controls;
+using System.Windows.Media;
+using System.Windows.Data;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ public class Picker : Grid
+ {
+ public Picker()
+ {
+ SizeChanged += delegate { UpdateValueOffset(); };
+ }
+
+ public static readonly DependencyProperty MarkerProperty =
+ DependencyProperty.Register("Marker", typeof(UIElement), typeof(Picker));
+
+ public UIElement Marker
+ {
+ get { return (UIElement)GetValue(MarkerProperty); }
+ set { SetValue(MarkerProperty, value); }
+ }
+
+ public static readonly DependencyProperty ValueProperty =
+ DependencyProperty.Register("Value", typeof(double), typeof(Picker),
+ new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
+
+ public double Value
+ {
+ get { return (double)GetValue(ValueProperty); }
+ set { SetValue(ValueProperty, value); }
+ }
+
+ public static readonly DependencyProperty ValueOffsetProperty =
+ DependencyProperty.Register("ValueOffset", typeof(double), typeof(Picker));
+
+ public double ValueOffset
+ {
+ get { return (double)GetValue(ValueOffsetProperty); }
+ set { SetValue(ValueOffsetProperty, value); }
+ }
+
+ public static readonly DependencyProperty OrientationProperty =
+ DependencyProperty.Register("Orientation", typeof(Orientation), typeof(Picker));
+
+ public Orientation Orientation
+ {
+ get { return (Orientation)GetValue(OrientationProperty); }
+ set { SetValue(OrientationProperty, value); }
+ }
+
+ public static readonly DependencyProperty MinimumProperty =
+ DependencyProperty.Register("Minimum", typeof(double), typeof(Picker));
+
+ public double Minimum
+ {
+ get { return (double)GetValue(MinimumProperty); }
+ set { SetValue(MinimumProperty, value); }
+ }
+
+ public static readonly DependencyProperty MaximumProperty =
+ DependencyProperty.Register("Maximum", typeof(double), typeof(Picker),
+ new FrameworkPropertyMetadata(100.0));
+
+ public double Maximum
+ {
+ get { return (double)GetValue(MaximumProperty); }
+ set { SetValue(MaximumProperty, value); }
+ }
+
+ protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
+ {
+ base.OnPropertyChanged(e);
+
+ if (e.Property == MarkerProperty)
+ {
+ TranslateTransform t = Marker.RenderTransform as TranslateTransform;
+ if (t == null)
+ {
+ t = new TranslateTransform();
+ Marker.RenderTransform = t;
+ }
+ var property = Orientation == Orientation.Horizontal ? TranslateTransform.XProperty : TranslateTransform.YProperty;
+ BindingOperations.SetBinding(t, property, new Binding("ValueOffset")
+ {
+ Source = this
+ });
+ }
+ else if (e.Property == ValueProperty)
+ {
+ UpdateValueOffset();
+ }
+ }
+
+ bool isMouseDown;
+
+ protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
+ {
+ isMouseDown = true;
+ CaptureMouse();
+ UpdateValue();
+ }
+
+ protected override void OnPreviewMouseMove(MouseEventArgs e)
+ {
+ if (isMouseDown)
+ {
+ UpdateValue();
+ }
+ }
+
+ protected override void OnPreviewMouseUp(MouseButtonEventArgs e)
+ {
+ isMouseDown = false;
+ ReleaseMouseCapture();
+ }
+
+ void UpdateValue()
+ {
+ Point p = Mouse.GetPosition(this);
+ double length = 0, pos = 0;
+
+ if (Orientation == Orientation.Horizontal)
+ {
+ length = ActualWidth;
+ pos = p.X;
+ }
+ else
+ {
+ length = ActualHeight;
+ pos = p.Y;
+ }
+
+ pos = Math.Max(0, Math.Min(length, pos));
+ Value = Minimum + (Maximum - Minimum) * pos / length;
+ }
+
+ void UpdateValueOffset()
+ {
+ var length = Orientation == Orientation.Horizontal ? ActualWidth : ActualHeight;
+ ValueOffset = length * (Value - Minimum) / (Maximum - Minimum);
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/SolidBrushEditor.xaml b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/SolidBrushEditor.xaml
new file mode 100644
index 0000000000..e5b97b1681
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/SolidBrushEditor.xaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/SolidBrushEditor.xaml.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/SolidBrushEditor.xaml.cs
new file mode 100644
index 0000000000..3eed39d1d6
--- /dev/null
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditor/SolidBrushEditor.xaml.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors.BrushEditor
+{
+ public partial class SolidBrushEditor
+ {
+ public SolidBrushEditor()
+ {
+ InitializeComponent();
+ }
+
+ public static readonly DependencyProperty ColorProperty =
+ DependencyProperty.Register("Color", typeof(Color), typeof(SolidBrushEditor),
+ new FrameworkPropertyMetadata(new Color(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
+
+ public Color Color
+ {
+ get { return (Color)GetValue(ColorProperty); }
+ set { SetValue(ColorProperty, value); }
+ }
+ }
+}
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditorDialog.xaml b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditorDialog.xaml
deleted file mode 100644
index 452ab0b51d..0000000000
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditorDialog.xaml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditorDialog.xaml.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditorDialog.xaml.cs
deleted file mode 100644
index f08112e90e..0000000000
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Controls/TypeEditors/BrushEditorDialog.xaml.cs
+++ /dev/null
@@ -1,184 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Shapes;
-
-using ICSharpCode.WpfDesign.PropertyEditor;
-using System.Windows.Threading;
-
-namespace ICSharpCode.WpfDesign.Designer.Controls.TypeEditors
-{
- ///
- /// Interaction logic for BrushEditorDialog.xaml
- ///
- public partial class BrushEditorDialog : Window
- {
- static readonly Brush[] specialBrushes = {
- Brushes.White, Brushes.Black, Brushes.Transparent, null
- };
-
- ControlTemplate RadioButtonTemplate;
-
- public BrushEditorDialog(IPropertyEditorDataProperty property)
- {
- InitializeComponent();
-
- RadioButtonTemplate = (ControlTemplate)FindResource("RadioButtonTemplate");
-
- const int bigColorSquareSize = 18;
- const int smallColorSquareSize = 12;
-
- // special brushes:
- AddColorSquare(null, null, "null", bigColorSquareSize).IsChecked = true;
- AddColorSquare(Brushes.Black, null, "Black", bigColorSquareSize);
- AddColorSquare(Brushes.White, null, "White", bigColorSquareSize);
- AddColorSquare(Brushes.Transparent, null, "Transparent", bigColorSquareSize);
- x = 0;
- y += bigColorSquareSize;
-
- AddSeparatorLine();
-
- foreach (PropertyInfo p in typeof(Brushes).GetProperties()) {
- Brush brush = (Brush)p.GetValue(null, null);
- if (!specialBrushes.Contains(brush))
- AddColorSquare(brush, null, p.Name, smallColorSquareSize);
- }
-
- y += smallColorSquareSize;
-
- if (property != null) {
- AddSeparatorLine();
- TextBoxEditor textBoxEditor = new TextBoxEditor(property);
- textBoxEditor.Width = 100;
- Canvas.SetTop(textBoxEditor, y);
- canvas.Children.Add(textBoxEditor);
- textBoxEditor.ValueSaved += delegate {
- this.SelectedBrush = textBoxEditor.Property.Value as Brush;
- };
- y += 21;
- }
- canvas.Height = y;
- }
-
- int x = 0;
- int y = 0;
-
- RadioButton AddColorSquare(Brush brush, UIElement content, string tooltip, int size)
- {
- RadioButton radioButton = new RadioButton {
- Background = brush,
- Width = size,
- Height = size
- };
- radioButton.ToolTip = tooltip;
- radioButton.Template = RadioButtonTemplate;
- Canvas.SetLeft(radioButton, x);
- Canvas.SetTop(radioButton, y);
- canvas.Children.Add(radioButton);
-
- radioButton.Checked += delegate {
- if (selectedBrush != radioButton.Background) {
- selectedBrush = radioButton.Background;
- if (SelectedBrushChanged != null) {
- SelectedBrushChanged(this, EventArgs.Empty);
- }
- }
- };
-
- x += size;
- if (x > 260) {
- x = 0;
- y += size;
- }
- return radioButton;
- }
-
- void AddSeparatorLine()
- {
- Line line = new Line {
- StrokeThickness = 1,
- Stroke = Brushes.Gray,
- Height = 1,
- X2 = 260,
- Y1 = 0.5,
- Y2 = 0.5
- };
- Canvas.SetTop(line, y + 1);
- canvas.Children.Add(line);
- y += 3;
- }
-
- Brush selectedBrush;
-
- public Brush SelectedBrush {
- get {
- return selectedBrush;
- }
- set {
- if (selectedBrush != value) {
- selectedBrush = value;
- foreach (RadioButton btn in canvas.Children.OfType()) {
- btn.IsChecked = BrushEquals(btn.Background, value);
- }
-
- if (SelectedBrushChanged != null) {
- SelectedBrushChanged(this, EventArgs.Empty);
- }
- }
- }
- }
-
- bool BrushEquals(Brush b1, Brush b2)
- {
- if (b1 == b2)
- return true;
- SolidColorBrush scb1 = b1 as SolidColorBrush;
- SolidColorBrush scb2 = b2 as SolidColorBrush;
- if (scb1 == null || scb2 == null)
- return false;
- return scb1.Color == scb2.Color;
- }
-
- public event EventHandler SelectedBrushChanged;
-
- protected override void OnDeactivated(EventArgs e)
- {
- base.OnDeactivated(e);
- CloseIfNotActive(null, null);
- }
-
- Window activeWindow;
-
- void CloseIfNotActive(object sender, EventArgs e)
- {
- if (activeWindow != null) {
- activeWindow.Deactivated -= CloseIfNotActive;
- activeWindow = null;
- }
- Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(
- delegate {
- if (IsActive)
- return;
- foreach (Window child in OwnedWindows) {
- Debug.WriteLine(child + " isActive=" + child.IsActive);
- if (child.IsActive) {
- activeWindow = child;
- child.Deactivated += CloseIfNotActive;
- return;
- }
- }
- Close();
- }));
- }
- }
-}
\ No newline at end of file
diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj
index 54a5c0a805..23f0996867 100644
--- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj
+++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj
@@ -75,11 +75,22 @@
-
-
- BrushEditorDialog.xaml
- Code
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -126,6 +137,7 @@
+
@@ -146,7 +158,14 @@
-
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+