agrobot_base/AgroBase/OperationControl/Controls/HeadingIndicator.xaml.cs

118 lines
4.5 KiB
C#

using System.Windows;
using System.ComponentModel;
using System.Windows.Media;
using UserControl = System.Windows.Controls.UserControl;
using Color = System.Windows.Media.Color;
namespace OperationControl.Controls
{
/// <summary>
/// Interaction logic for HeadingIndicator.xaml
/// </summary>
public partial class HeadingIndicator : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
void Raise(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
public HeadingIndicator()
{
InitializeComponent();
DataContext = this;
MinorAngles = Enumerable.Range(0, 36).Select(i => i * 10.0).ToList(); // 0..350
MajorAngles = Enumerable.Range(0, 12).Select(i => i * 30.0).ToList(); // 0..330
}
public List<double> MinorAngles { get; }
public List<double> MajorAngles { get; }
// Mostra/oculta rótulos 0°,30°... (padrão: false)
public bool ShowDegreeLabels
{
get => (bool)GetValue(ShowDegreeLabelsProperty);
set => SetValue(ShowDegreeLabelsProperty, value);
}
public static readonly DependencyProperty ShowDegreeLabelsProperty = DependencyProperty.Register(nameof(ShowDegreeLabels), typeof(bool), typeof(HeadingIndicator), new PropertyMetadata(false));
public double Heading
{
get => (double)GetValue(HeadingProperty);
set => SetValue(HeadingProperty, value);
}
public double CourseHeading
{
get => (double)GetValue(CourseHeadingProperty);
set => SetValue(CourseHeadingProperty, value);
}
public double DifHeading { get; set; }
public static readonly DependencyProperty HeadingProperty = DependencyProperty.Register(nameof(Heading), typeof(double), typeof(HeadingIndicator), new PropertyMetadata(0.0, OnHeadingOrCourseChanged));
public static readonly DependencyProperty CourseHeadingProperty = DependencyProperty.Register(nameof(CourseHeading), typeof(double), typeof(HeadingIndicator), new PropertyMetadata(double.NaN, OnHeadingOrCourseChanged));
private static void OnHeadingOrCourseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctrl = (HeadingIndicator)d;
// já faz o giro do dial, como antes
if (ctrl.DialRotation != null)
ctrl.DialRotation.Angle = -ctrl.Heading;
ctrl.UpdateCourseArrow();
// **importante**: avisa que DifHeading mudou
ctrl.Raise(nameof(DifHeading));
}
private static double NormalizeDelta(double deg)
{
deg %= 360.0;
if (deg >= 180.0) deg -= 360.0;
if (deg < -180.0) deg += 360.0;
return deg;
}
private void UpdateCourseArrow()
{
if (CourseArrow == null || CourseRotation == null)
return;
if (double.IsNaN(CourseHeading))
{
CourseArrow.Visibility = Visibility.Collapsed;
txtHeading.Visibility = Visibility.Collapsed;
txtHeadingCourse.Visibility = Visibility.Collapsed;
DifHeading = Heading;
UpdateChrome();
return;
}
// mostra a seta e gira pelo delta (curso - heading atual)
CourseArrow.Visibility = Visibility.Visible;
txtHeading.Visibility = Visibility.Visible;
txtHeadingCourse.Visibility = Visibility.Visible;
double delta = NormalizeDelta(CourseHeading - Heading);
CourseRotation.Angle = delta;
DifHeading = NormalizeDelta(Heading - CourseHeading);
UpdateChrome();
}
private void UpdateChrome()
{
if (Chrome == null) return;
bool no_course = double.IsNaN(CourseHeading);
var a = no_course ? 0 : Math.Abs(DifHeading);
var cor = new SolidColorBrush(Color.FromRgb(0x2E, 0xCC, 0x71)); // verde
if (a >= 10)
cor = new SolidColorBrush(Color.FromRgb(0xE7, 0x4C, 0x3C)); // vermelho
else if (a >= 5)
cor = new SolidColorBrush(Color.FromRgb(0xF1, 0xC4, 0x0F)); // amarelo
Chrome.BorderBrush = cor;
txtHeadingDif.Foreground = no_course ? new SolidColorBrush(Colors.White) : cor;
}
}
}