4 using System.Collections.Generic;
5 using System.Globalization;
7 using System.Windows.Input;
8 using System.Windows.Media;
10 namespace SiliconStudio.Presentation.Controls
16 public DrawingContext DrawingContext {
get;
private set; }
20 RoutedEvent = routedEvent;
21 DrawingContext = drawingContext;
29 public object OldValue {
get;
private set; }
30 public object NewValue {
get;
private set; }
31 public DependencyProperty DependencyProperty {
get;
private set; }
35 RoutedEvent = routedEvent;
36 DependencyProperty = dependencyProperty;
44 public static readonly DependencyProperty CustomDrawingContextProperty = DependencyProperty.Register(
45 "CustomDrawingContext",
46 typeof(DrawingContext),
48 new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
50 public static readonly DependencyProperty BackgroundProperty = DependencyProperty.Register(
54 new FrameworkPropertyMetadata(Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender));
56 public static readonly DependencyProperty LargeTickPenProperty = DependencyProperty.Register(
60 new FrameworkPropertyMetadata(
new Pen(Brushes.Black, 1.0), FrameworkPropertyMetadataOptions.AffectsRender));
62 public static readonly DependencyProperty SmallTickPenProperty = DependencyProperty.Register(
66 new FrameworkPropertyMetadata(
new Pen(Brushes.Gray, 1.0), FrameworkPropertyMetadataOptions.AffectsRender));
68 public static readonly DependencyProperty LargeTickTopProperty = DependencyProperty.Register(
72 new FrameworkPropertyMetadata(0.625, FrameworkPropertyMetadataOptions.AffectsRender));
74 public static readonly DependencyProperty LargeTickBottomProperty = DependencyProperty.Register(
78 new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.AffectsRender));
80 public static readonly DependencyProperty SmallTickTopProperty = DependencyProperty.Register(
84 new FrameworkPropertyMetadata(0.75, FrameworkPropertyMetadataOptions.AffectsRender));
86 public static readonly DependencyProperty SmallTickBottomProperty = DependencyProperty.Register(
90 new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.AffectsRender));
92 public static readonly DependencyProperty DecimalCountRoundingProperty = DependencyProperty.Register(
93 "DecimalCountRounding",
96 new FrameworkPropertyMetadata(6, null, CoerceDecimalCountRoundingPropertyValue));
98 public static readonly DependencyProperty TextPositionOriginProperty = DependencyProperty.Register(
102 new FrameworkPropertyMetadata(
new Point(0.5, 0.0), FrameworkPropertyMetadataOptions.AffectsRender));
104 public static readonly DependencyProperty TextPositionProperty = DependencyProperty.Register(
108 new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender));
110 public static readonly DependencyProperty ForegroundProperty = DependencyProperty.Register(
114 new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender));
116 public static readonly DependencyProperty FontProperty = DependencyProperty.Register(
120 new FrameworkPropertyMetadata(
new Typeface(
"Meiryo"), FrameworkPropertyMetadataOptions.AffectsRender));
122 public static readonly DependencyProperty FontSizeProperty = DependencyProperty.Register(
126 new FrameworkPropertyMetadata(9.0, FrameworkPropertyMetadataOptions.AffectsRender));
128 public static readonly DependencyProperty StartUnitProperty = DependencyProperty.Register(
132 new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender));
134 public static readonly DependencyProperty MinimumUnitsPerTickProperty = DependencyProperty.Register(
135 "MinimumUnitsPerTick",
138 new FrameworkPropertyMetadata(1e-12, FrameworkPropertyMetadataOptions.AffectsRender, OnUnitsPerTickPropertyChanged));
140 public static readonly DependencyProperty MaximumUnitsPerTickProperty = DependencyProperty.Register(
141 "MaximumUnitsPerTick",
144 new FrameworkPropertyMetadata(1e12, FrameworkPropertyMetadataOptions.AffectsRender, OnUnitsPerTickPropertyChanged));
146 public static readonly DependencyProperty UnitsPerTickProperty = DependencyProperty.Register(
150 new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.AffectsRender, OnUnitsPerTickPropertyChanged, CoerceUnitsPerTickPropertyValue));
152 public static readonly DependencyProperty PixelsPerTickProperty = DependencyProperty.Register(
156 new FrameworkPropertyMetadata(100.0, FrameworkPropertyMetadataOptions.AffectsRender, OnPixelsPerTickPropertyChanged, CoercePixelsPerTickPropertyValue));
158 private static readonly DependencyPropertyKey AdjustedUnitsPerTickPropertyKey = DependencyProperty.RegisterReadOnly(
159 "AdjustedUnitsPerTick",
162 new PropertyMetadata());
163 public static readonly DependencyProperty AdjustedUnitsPerTickProperty = AdjustedUnitsPerTickPropertyKey.DependencyProperty;
165 private static readonly DependencyPropertyKey AdjustedPixelsPerTickPropertyKey = DependencyProperty.RegisterReadOnly(
166 "AdjustedPixelsPerTick",
169 new PropertyMetadata());
170 public static readonly DependencyProperty AdjustedPixelsPerTickProperty = AdjustedPixelsPerTickPropertyKey.DependencyProperty;
172 private static readonly DependencyPropertyKey PixelsPerUnitPropertyKey = DependencyProperty.RegisterReadOnly(
176 new PropertyMetadata());
177 public static readonly DependencyProperty PixelsPerUnitProperty = PixelsPerUnitPropertyKey.DependencyProperty;
179 private static readonly DependencyPropertyKey AdjustedPixelsPerUnitPropertyKey = DependencyProperty.RegisterReadOnly(
180 "AdjustedPixelsPerUnit",
183 new PropertyMetadata());
184 public static readonly DependencyProperty AdjustedPixelsPerUnitProperty = AdjustedPixelsPerUnitPropertyKey.DependencyProperty;
186 public static readonly DependencyProperty IsAliasedProperty = DependencyProperty.Register(
190 new FrameworkPropertyMetadata(
true, FrameworkPropertyMetadataOptions.AffectsRender, OnIsAliasedPropertyChanged));
192 public static readonly DependencyProperty IsTextVisibleProperty = DependencyProperty.Register(
196 new FrameworkPropertyMetadata(
true, FrameworkPropertyMetadataOptions.AffectsRender));
198 public static readonly DependencyProperty IsSmallTickVisibleProperty = DependencyProperty.Register(
199 "IsSmallTickVisible",
202 new FrameworkPropertyMetadata(
true, FrameworkPropertyMetadataOptions.AffectsRender));
204 public static readonly DependencyProperty IsZoomingOnMouseWheelProperty = DependencyProperty.Register(
205 "IsZoomingOnMouseWheel",
208 new FrameworkPropertyMetadata(
false, FrameworkPropertyMetadataOptions.AffectsRender));
210 public static readonly DependencyProperty MouseWheelZoomCoeficientProperty = DependencyProperty.Register(
211 "MouseWheelZoomCoeficient",
214 new FrameworkPropertyMetadata(1.1, FrameworkPropertyMetadataOptions.AffectsRender));
216 public static readonly DependencyProperty IsDraggingOnLeftMouseButtonProperty = DependencyProperty.Register(
217 "IsDraggingOnLeftMouseButton",
220 new FrameworkPropertyMetadata(
false, FrameworkPropertyMetadataOptions.AffectsRender));
222 public static readonly DependencyProperty IsDraggingOnRightMouseButtonProperty = DependencyProperty.Register(
223 "IsDraggingOnRightMouseButton",
226 new FrameworkPropertyMetadata(
false, FrameworkPropertyMetadataOptions.AffectsRender));
228 public static readonly DependencyProperty UnitSystemProperty = DependencyProperty.Register(
232 new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, OnUnitSystemPropertyChanged));
234 public static readonly DependencyProperty SymbolProperty = DependencyProperty.Register(
238 new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
240 public static readonly DependencyProperty TickTextUnitDividerProperty = DependencyProperty.Register(
241 "TickTextUnitDivider",
244 new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.AffectsRender));
246 public static readonly RoutedEvent BeforeRenderEvent = EventManager.RegisterRoutedEvent(
248 RoutingStrategy.Bubble,
249 typeof(RoutedEventHandler),
252 public static readonly RoutedEvent AfterRenderEvent = EventManager.RegisterRoutedEvent(
254 RoutingStrategy.Bubble,
255 typeof(RoutedEventHandler),
258 public static readonly RoutedEvent BeforeTicksRenderEvent = EventManager.RegisterRoutedEvent(
260 RoutingStrategy.Bubble,
264 public static readonly RoutedEvent AfterTicksRenderEvent = EventManager.RegisterRoutedEvent(
266 RoutingStrategy.Bubble,
270 public static readonly RoutedEvent ScaleChangingEvent = EventManager.RegisterRoutedEvent(
272 RoutingStrategy.Bubble,
276 public static readonly RoutedEvent ScaleChangedEvent = EventManager.RegisterRoutedEvent(
278 RoutingStrategy.Bubble,
290 SetValue(AdjustedUnitsPerTickPropertyKey, UnitsPerTick);
291 SetValue(AdjustedPixelsPerTickPropertyKey, PixelsPerTick);
292 RenderOptions.SetEdgeMode(
this, IsAliased ? EdgeMode.Aliased : EdgeMode.Unspecified);
296 public event RoutedEventHandler BeforeRender
298 add { AddHandler(BeforeRenderEvent, value); }
299 remove { RemoveHandler(BeforeRenderEvent, value); }
302 public event RoutedEventHandler AfterRender
304 add { AddHandler(AfterRenderEvent, value); }
305 remove { RemoveHandler(AfterRenderEvent, value); }
310 add { AddHandler(BeforeTicksRenderEvent, value); }
311 remove { RemoveHandler(BeforeTicksRenderEvent, value); }
316 add { AddHandler(AfterTicksRenderEvent, value); }
317 remove { RemoveHandler(AfterTicksRenderEvent, value); }
322 add { AddHandler(ScaleChangingEvent, value); }
323 remove { RemoveHandler(ScaleChangingEvent, value); }
328 add { AddHandler(ScaleChangedEvent, value); }
329 remove { RemoveHandler(ScaleChangedEvent, value); }
332 private void RaiseBeforeRenderEvent()
337 private void RaiseAfterRenderEvent()
342 private void RaiseBeforeTicksRenderEvent(DrawingContext drawingContext)
344 RaiseEvent(
new CustomRenderRoutedEventArgs(BeforeTicksRenderEvent, drawingContext));
347 private void RaiseAfterTicksRenderEvent(DrawingContext drawingContext)
349 RaiseEvent(
new CustomRenderRoutedEventArgs(AfterTicksRenderEvent, drawingContext));
352 private void RaiseScaleChangingEvent(DependencyProperty dependencyProperty,
object oldValue,
object newValue)
354 RaiseEvent(
new RoutedDependencyPropertyChangedEventArgs(ScaleChangingEvent, dependencyProperty, oldValue, newValue));
357 private void RaiseScaleChangedEvent(DependencyProperty dependencyProperty,
object oldValue,
object newValue)
359 RaiseEvent(
new RoutedDependencyPropertyChangedEventArgs(ScaleChangedEvent, dependencyProperty, oldValue, newValue));
362 private void SetScaleChangingProperty(DependencyProperty dependencyProperty,
object value)
364 var oldValue = GetValue(dependencyProperty);
365 RaiseScaleChangingEvent(dependencyProperty, oldValue, value);
366 SetValue(dependencyProperty, value);
367 RaiseScaleChangedEvent(dependencyProperty, oldValue, value);
370 private void SetScaleChangingProperty(DependencyPropertyKey dependencyPropertyKey, DependencyProperty dependencyProperty,
object value)
372 var oldValue = GetValue(dependencyProperty);
373 RaiseScaleChangingEvent(dependencyProperty, oldValue, value);
374 SetValue(dependencyPropertyKey, value);
375 RaiseScaleChangedEvent(dependencyProperty, oldValue, value);
378 public DrawingContext CustomDrawingContext
380 get {
return (DrawingContext)GetValue(CustomDrawingContextProperty); }
381 set { SetValue(CustomDrawingContextProperty, value); }
384 public Brush Background
386 get {
return (Brush)GetValue(BackgroundProperty); }
387 set { SetValue(BackgroundProperty, value); }
390 public Pen LargeTickPen
392 get {
return (Pen)GetValue(LargeTickPenProperty); }
393 set { SetValue(LargeTickPenProperty, value); }
396 public Pen SmallTickPen
398 get {
return (Pen)GetValue(SmallTickPenProperty); }
399 set { SetValue(SmallTickPenProperty, value); }
407 public double LargeTickTop
409 get {
return (
double)GetValue(LargeTickTopProperty); }
410 set { SetValue(LargeTickTopProperty, value); }
418 public double LargeTickBottom
420 get {
return (
double)GetValue(LargeTickBottomProperty); }
421 set { SetValue(LargeTickBottomProperty, value); }
429 public double SmallTickTop
431 get {
return (
double)GetValue(SmallTickTopProperty); }
432 set { SetValue(SmallTickTopProperty, value); }
440 public double SmallTickBottom
442 get {
return (
double)GetValue(SmallTickBottomProperty); }
443 set { SetValue(SmallTickBottomProperty, value); }
446 public int DecimalCountRounding
448 get {
return (
int)GetValue(DecimalCountRoundingProperty); }
449 set { SetValue(DecimalCountRoundingProperty, value); }
456 public Point TextPositionOrigin
458 get {
return (
Point)GetValue(TextPositionOriginProperty); }
459 set { SetValue(TextPositionOriginProperty, value); }
467 public double TextPosition
469 get {
return (
double)GetValue(TextPositionProperty); }
470 set { SetValue(TextPositionProperty, value); }
473 public Brush Foreground
475 get {
return (Brush)GetValue(ForegroundProperty); }
476 set { SetValue(ForegroundProperty, value); }
481 get {
return (Typeface)GetValue(FontProperty); }
482 set { SetValue(FontProperty, value); }
485 public double FontSize
487 get {
return (
double)GetValue(FontSizeProperty); }
488 set { SetValue(FontSizeProperty, value); }
491 public double StartUnit
493 get {
return (
double)GetValue(StartUnitProperty); }
494 set { SetScaleChangingProperty(StartUnitProperty, value); }
497 public double MinimumUnitsPerTick
499 get {
return (
double)GetValue(MinimumUnitsPerTickProperty); }
500 set { SetScaleChangingProperty(MinimumUnitsPerTickProperty, value); }
503 public double MaximumUnitsPerTick
505 get {
return (
double)GetValue(MaximumUnitsPerTickProperty); }
506 set { SetScaleChangingProperty(MaximumUnitsPerTickProperty, value); }
509 public double UnitsPerTick
511 get {
return (
double)GetValue(UnitsPerTickProperty); }
512 set { SetScaleChangingProperty(UnitsPerTickProperty, value); }
515 public double AdjustedUnitsPerTick
517 get {
return (
double)GetValue(AdjustedUnitsPerTickProperty); }
518 private set { SetValue(AdjustedUnitsPerTickPropertyKey, value); }
521 public double PixelsPerTick
523 get {
return (
double)GetValue(PixelsPerTickProperty); }
524 set { SetScaleChangingProperty(PixelsPerTickProperty, value); }
527 public double AdjustedPixelsPerTick
529 get {
return (
double)GetValue(AdjustedPixelsPerTickProperty); }
530 private set { SetValue(AdjustedPixelsPerTickPropertyKey, value); }
533 public double PixelsPerUnit
535 get {
return (
double)GetValue(PixelsPerUnitProperty); }
536 private set { SetScaleChangingProperty(PixelsPerUnitPropertyKey, PixelsPerUnitProperty, value); }
539 public double AdjustedPixelsPerUnit
541 get {
return (
double)GetValue(AdjustedPixelsPerUnitProperty); }
542 private set { SetValue(AdjustedPixelsPerUnitPropertyKey, value); }
545 public bool IsAliased
547 get {
return (
bool)GetValue(IsAliasedProperty); }
548 set { SetValue(IsAliasedProperty, value); }
551 public bool IsTextVisible
553 get {
return (
bool)GetValue(IsTextVisibleProperty); }
554 set { SetValue(IsTextVisibleProperty, value); }
557 public bool IsSmallTickVisible
559 get {
return (
bool)GetValue(IsSmallTickVisibleProperty); }
560 set { SetValue(IsSmallTickVisibleProperty, value); }
563 public bool IsZoomingOnMouseWheel
565 get {
return (
bool)GetValue(IsZoomingOnMouseWheelProperty); }
566 set { SetValue(IsZoomingOnMouseWheelProperty, value); }
569 public double MouseWheelZoomCoeficient
571 get {
return (
double)GetValue(MouseWheelZoomCoeficientProperty); }
572 set { SetValue(MouseWheelZoomCoeficientProperty, value); }
575 public bool IsDraggingOnLeftMouseButton
577 get {
return (
bool)GetValue(IsDraggingOnLeftMouseButtonProperty); }
578 set { SetValue(IsDraggingOnLeftMouseButtonProperty, value); }
581 public bool IsDraggingOnRightMouseButton
583 get {
return (
bool)GetValue(IsDraggingOnRightMouseButtonProperty); }
584 set { SetValue(IsDraggingOnRightMouseButtonProperty, value); }
589 get {
return (
UnitSystem)GetValue(UnitSystemProperty); }
590 set { SetValue(UnitSystemProperty, value); }
593 public string UnitSymbol
595 get {
return (
string)GetValue(SymbolProperty); }
596 set { SetValue(SymbolProperty, value); }
599 public double TickTextUnitDivider
601 get {
return (
double)GetValue(TickTextUnitDividerProperty); }
602 set { SetValue(TickTextUnitDividerProperty, value); }
605 private void UpdatePixelInfo()
607 AdjustedPixelsPerTick = PixelsPerTick * AdjustedUnitsPerTick / UnitsPerTick;
608 AdjustedPixelsPerUnit = AdjustedPixelsPerTick / AdjustedUnitsPerTick;
609 PixelsPerUnit = PixelsPerTick / UnitsPerTick;
612 private static void OnUnitSystemPropertyChanged(
DependencyObject sender, DependencyPropertyChangedEventArgs e)
614 var scalebar = (ScaleBar)sender;
615 scalebar.AdjustUnitIntervalWithUnitSystem(scalebar.UnitsPerTick);
616 scalebar.UpdatePixelInfo();
619 private static void OnUnitsPerTickPropertyChanged(
DependencyObject sender, DependencyPropertyChangedEventArgs e)
621 var scalebar = (ScaleBar)sender;
622 scalebar.AdjustUnitIntervalWithUnitSystem((double)e.NewValue);
623 scalebar.UpdatePixelInfo();
626 private static void OnPixelsPerTickPropertyChanged(
DependencyObject sender, DependencyPropertyChangedEventArgs e)
628 var scalebar = (ScaleBar)sender;
629 scalebar.UpdatePixelInfo();
632 private static void OnIsAliasedPropertyChanged(
DependencyObject sender, DependencyPropertyChangedEventArgs e)
634 RenderOptions.SetEdgeMode(sender, (bool)e.NewValue ? EdgeMode.Aliased : EdgeMode.Unspecified);
637 private static object CoerceUnitsPerTickPropertyValue(
DependencyObject sender,
object value)
639 var scalebar = (ScaleBar)sender;
640 return scalebar.MinimumUnitsPerTick < scalebar.MaximumUnitsPerTick ? Math.Min(scalebar.MaximumUnitsPerTick, Math.Max(scalebar.MinimumUnitsPerTick, (double)value)) : value;
643 private static object CoercePixelsPerTickPropertyValue(
DependencyObject sender,
object value)
645 return Math.Max(10.0, (double)value);
648 private static object CoerceDecimalCountRoundingPropertyValue(
DependencyObject sender,
object value)
650 return Math.Max(0, 12);
655 return ((unit - StartUnit) * AdjustedPixelsPerTick) / AdjustedUnitsPerTick;
660 return StartUnit + (pixel * AdjustedUnitsPerTick) / AdjustedPixelsPerTick;
665 StartUnit = unit - (pixel * AdjustedUnitsPerTick) / AdjustedPixelsPerTick;
671 double unit = GetUnitAt(pixel);
672 UnitsPerTick = unitsPerTick;
673 SetUnitAt(unit, pixel);
678 double unit = GetUnitAt(pixel);
679 PixelsPerTick = pixelsPerTick;
680 SetUnitAt(unit, pixel);
683 private Pen largeTickPen;
684 private Pen smallTickPen;
686 private Point textPositionOrigin;
687 private double textPosition;
688 private bool isTextVisible;
689 private Brush foreground;
690 private Typeface font;
691 private double fontSize;
693 private double actualWidth;
694 private double actualHeight;
696 private double largeTickTopPosition;
697 private double largeTickBottomPosition;
698 private double smallTickTopPosition;
699 private double smallTickBottomPosition;
701 private int adjustedSmallIntervalPerTick = 10;
703 protected override void OnRender(DrawingContext localDrawingContext)
705 DrawingContext drawingContext = CustomDrawingContext ?? localDrawingContext;
707 if (AdjustedPixelsPerTick.Equals(0.0))
708 SetValue(AdjustedPixelsPerTickPropertyKey, PixelsPerTick);
710 actualWidth = ActualWidth;
711 actualHeight = ActualHeight;
713 largeTickTopPosition = actualHeight * LargeTickTop;
714 largeTickBottomPosition = actualHeight * LargeTickBottom;
715 smallTickTopPosition = actualHeight * SmallTickTop;
716 smallTickBottomPosition = actualHeight * SmallTickBottom;
718 largeTickPen = LargeTickPen;
719 smallTickPen = SmallTickPen;
721 bool isSmallTickVisible = IsSmallTickVisible;
723 textPositionOrigin = TextPositionOrigin;
724 textPosition = TextPosition;
726 isTextVisible = IsTextVisible;
729 foreground = Foreground;
734 double adjustedUnitsPerTick = AdjustedUnitsPerTick;
735 double adjustedPixelsPerTick = AdjustedPixelsPerTick;
736 int decimalCountRounding = DecimalCountRounding;
738 double currentUnit = (int)(StartUnit / adjustedUnitsPerTick) * adjustedUnitsPerTick;
739 double currentPixel = ((currentUnit - StartUnit) / adjustedUnitsPerTick) * adjustedPixelsPerTick;
741 double smallIntevalLength = (1.0 / adjustedSmallIntervalPerTick);
743 if (StartUnit >= 0.0)
745 currentPixel += adjustedPixelsPerTick;
746 currentUnit += adjustedUnitsPerTick;
747 currentUnit = Math.Round(currentUnit, decimalCountRounding);
750 RaiseBeforeRenderEvent();
752 drawingContext.DrawRectangle(Background, null,
new Rect(0.0, 0.0, actualWidth, actualHeight));
754 RaiseBeforeTicksRenderEvent(drawingContext);
756 if (isSmallTickVisible)
758 for (
int i = 0; i < adjustedSmallIntervalPerTick - 1; i++)
760 double smallLeft = currentPixel - ((i + 1) * adjustedPixelsPerTick) * smallIntevalLength;
763 DrawSmallTick(drawingContext, smallLeft);
767 if (currentPixel < 0.0)
769 currentPixel += adjustedPixelsPerTick * Math.Ceiling(Math.Abs(currentPixel) / adjustedPixelsPerTick);
772 while (currentPixel < actualWidth)
774 DrawLargeTick(drawingContext, currentUnit, currentPixel + 1.0);
776 if (isSmallTickVisible)
778 for (
int i = 0; i < adjustedSmallIntervalPerTick - 1; i++)
780 double smallLeft = currentPixel + ((i + 1) * adjustedPixelsPerTick) * smallIntevalLength;
781 if (smallLeft > actualWidth)
783 DrawSmallTick(drawingContext, smallLeft + 1.0);
787 currentPixel += adjustedPixelsPerTick;
788 currentUnit += adjustedUnitsPerTick;
791 RaiseAfterTicksRenderEvent(drawingContext);
793 RaiseAfterRenderEvent();
796 private static double AdjustUnitInterval(
double value)
799 bool negative = (value <= 0.0f);
803 double log = Math.Log10(value);
804 double log0 = Math.Pow(10.0, Math.Floor(log));
809 if (log < (1.0f + 2.0f) * 0.5f) result = log0;
810 else if (log < (2.0f + 5.0f) * 0.5f) result = log0 * 2.0f;
811 else if (log < (5.0f + 10.0f) * 0.5f) result = log0 * 5.0f;
812 else result = log0 * 10.0f;
820 private static bool IsCloser(
double value,
double other,
double reference)
822 return Math.Abs(value - reference) < Math.Abs(other - reference);
825 private static bool IsCloseEnoughToMultiply(List<double> sortedGroupings,
double value,
double target)
828 int index = sortedGroupings.FindIndex(x => x.Equals(value));
830 if (index > 0 && sortedGroupings[index - 1] > target)
833 if (index < sortedGroupings.Count - 1 && sortedGroupings[index + 1] < target)
839 private void AdjustUnitIntervalWithUnitSystem(
double value)
841 TickTextUnitDivider = 1.0;
843 if (UnitSystem == null)
845 AdjustedUnitsPerTick = AdjustUnitInterval(value);
849 UnitSymbol = UnitSystem.Symbol;
851 double scaledValue = value * 1.5;
852 double referenceUnitsPerTick = AdjustedUnitsPerTick;
853 bool hasResult =
false;
854 var allGrouping =
new List<double>();
855 UnitSystem.GetAllGroupingValues(ref allGrouping);
859 foreach (UnitGrouping grouping
in UnitSystem.GroupingValues)
861 if (!hasResult || IsCloser(grouping.LargeIntervalSize, referenceUnitsPerTick, scaledValue))
863 AdjustedUnitsPerTick = grouping.LargeIntervalSize;
864 referenceUnitsPerTick = AdjustedUnitsPerTick;
865 adjustedSmallIntervalPerTick = grouping.SmallIntervalCount;
870 if (grouping.IsMultipliable)
872 double val = AdjustUnitInterval(scaledValue / grouping.LargeIntervalSize) * grouping.LargeIntervalSize;
874 if (IsCloseEnoughToMultiply(allGrouping, grouping.LargeIntervalSize, scaledValue) && IsCloser(val, referenceUnitsPerTick, scaledValue))
876 AdjustedUnitsPerTick = val;
877 referenceUnitsPerTick = grouping.LargeIntervalSize;
878 adjustedSmallIntervalPerTick = grouping.SmallIntervalCount;
884 if (UnitSystem.GroupingValues.Count == 0)
886 AdjustedUnitsPerTick = AdjustUnitInterval(scaledValue);
887 referenceUnitsPerTick = 1;
888 adjustedSmallIntervalPerTick = 10;
892 foreach (UnitConversion conversion
in UnitSystem.Conversions)
895 foreach (UnitGrouping grouping
in conversion.GroupingValues)
897 double groupingValue = grouping.LargeIntervalSize * conversion.Value;
899 if (IsCloser(groupingValue, referenceUnitsPerTick, scaledValue))
901 AdjustedUnitsPerTick = groupingValue;
902 referenceUnitsPerTick = groupingValue;
903 adjustedSmallIntervalPerTick = grouping.SmallIntervalCount;
904 TickTextUnitDivider = conversion.Value;
905 UnitSymbol = conversion.Symbol;
909 if (grouping.IsMultipliable)
911 double val = AdjustUnitInterval(scaledValue / groupingValue) * groupingValue;
913 if (IsCloseEnoughToMultiply(allGrouping, groupingValue, scaledValue) && IsCloser(val, referenceUnitsPerTick, scaledValue))
915 AdjustedUnitsPerTick = val;
916 referenceUnitsPerTick = groupingValue;
917 adjustedSmallIntervalPerTick = grouping.SmallIntervalCount;
918 TickTextUnitDivider = conversion.Value;
919 UnitSymbol = conversion.Symbol;
925 if (conversion.GroupingValues.Count == 0)
927 double val = conversion.Value;
928 bool canMultiply =
true;
929 if (conversion.IsMultipliable)
931 canMultiply = IsCloseEnoughToMultiply(allGrouping, conversion.Value, scaledValue);
932 val *= AdjustUnitInterval(scaledValue / conversion.Value);
934 if (canMultiply && IsCloser(val, referenceUnitsPerTick, scaledValue))
936 AdjustedUnitsPerTick = val;
937 referenceUnitsPerTick = conversion.Value;
938 adjustedSmallIntervalPerTick = 10;
939 TickTextUnitDivider = conversion.Value;
940 UnitSymbol = conversion.Symbol;
946 protected virtual void DrawLargeTick(DrawingContext drawingContext,
double unit,
double position)
950 string symbol = UnitSymbol ??
"";
951 double dividedUnit = !TickTextUnitDivider.Equals(0.0) ? unit / TickTextUnitDivider : unit;
952 dividedUnit = Math.Round(dividedUnit, 6);
954 var ft =
new FormattedText(dividedUnit + symbol, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, font, fontSize, foreground);
955 drawingContext.DrawText(ft,
new Point(position - ft.Width * textPositionOrigin.X, (textPosition * actualHeight) - (ft.Height * textPositionOrigin.Y)));
958 drawingContext.DrawLine(largeTickPen,
new Point(position, largeTickTopPosition),
new Point(position, largeTickBottomPosition));
961 protected virtual void DrawSmallTick(DrawingContext drawingContext,
double position)
963 drawingContext.DrawLine(smallTickPen,
new Point(position, smallTickTopPosition),
new Point(position, smallTickBottomPosition));
968 base.OnMouseWheel(e);
970 if (IsZoomingOnMouseWheel)
972 double coeficient = e.Delta >= 0.0 ? MouseWheelZoomCoeficient : 1.0 / MouseWheelZoomCoeficient;
973 Point pos = e.GetPosition(
this);
975 ZoomAtPosition(pos.X, coeficient, Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift));
981 public void ZoomAtPosition(
double position,
double coeficient,
bool affectPixelsPerTick)
983 if (affectPixelsPerTick)
984 SetPixelsPerTickAt(PixelsPerTick * coeficient, position);
986 SetUnitsPerTickAt(UnitsPerTick / coeficient, position);
989 private bool isDraggingScale;
996 isDraggingScale = CaptureMouse();
998 mouseDelta = Mouse.GetPosition(
this);
999 return isDraggingScale;
1004 if (!isDraggingScale)
1007 isDraggingScale = !Mouse.Capture(null);
1008 return !isDraggingScale;
1011 private Point mouseDelta;
1015 if (isDraggingScale)
1017 Vector delta = e.GetPosition(
this) - mouseDelta;
1018 mouseDelta = e.GetPosition(
this);
1019 StartUnit -= delta.X / PixelsPerUnit;
1025 if (IsDraggingOnLeftMouseButton)
1027 StartDraggingScale();
1033 if (IsDraggingOnLeftMouseButton)
1041 if (IsDraggingOnRightMouseButton)
1043 StartDraggingScale();
1049 if (IsDraggingOnRightMouseButton)
double GetUnitAt(double pixel)
void SetPixelsPerTickAt(double pixelsPerTick, double pixel)
delegate void CustomRenderRoutedEventHandler(object sender, CustomRenderRoutedEventArgs e)
override void OnMouseRightButtonDown(MouseButtonEventArgs e)
virtual void DrawSmallTick(DrawingContext drawingContext, double position)
void ZoomAtPosition(double position, double coeficient, bool affectPixelsPerTick)
override void OnMouseWheel(MouseWheelEventArgs e)
SharpDX.DirectWrite.Font Font
override void OnRender(DrawingContext localDrawingContext)
bool StartDraggingScale()
CustomRenderRoutedEventArgs(RoutedEvent routedEvent, DrawingContext drawingContext)
override void OnMouseRightButtonUp(MouseButtonEventArgs e)
override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
delegate void RoutedDependencyPropertyChangedEventHandler(object sender, RoutedDependencyPropertyChangedEventArgs e)
Represent an unit system that can be used with a ScaleBar
virtual void DrawLargeTick(DrawingContext drawingContext, double unit, double position)
override void OnMouseMove(MouseEventArgs e)
RoutedDependencyPropertyChangedEventArgs(RoutedEvent routedEvent, DependencyProperty dependencyProperty, object oldValue, object newValue)
double GetPixelAt(double unit)
void SetUnitAt(double unit, double pixel)
override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
System.Windows.Point Point
void SetUnitsPerTickAt(double unitsPerTick, double pixel)