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 { /// /// Interaction logic for HeadingIndicator.xaml /// 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 MinorAngles { get; } public List 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; } } }