using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using ErvDashboard.Model; namespace ErvDashboard { // 스마트수면 시간설정 팝업 (원형 다이얼). 시작/종료 시각을 설정 → 적용 시 메인이 종료 시각에 자동 해제 예약. // 대시보드 전용(ERV 프로토콜 무관). 시각은 자정 기준 분(0~1439, 30분 단위). public partial class SmartSleepWindow : Window { readonly MainWindow _owner; readonly DashboardState _state; const double CX = 130, CY = 130, R = 104; // DialCanvas(260x260) 중심/반지름 int _startMin, _endMin; bool _dragStart, _dragEnd, _updating; public SmartSleepWindow(MainWindow owner, DashboardState state) { InitializeComponent(); _owner = owner; _state = state; _startMin = state.SleepStartMin; _endMin = state.SleepEndMin; for (int m = 0; m < 1440; m += 30) { StartCombo.Items.Add(new ComboBoxItem { Content = DashboardState.FmtTime(m), Tag = m }); EndCombo.Items.Add(new ComboBoxItem { Content = DashboardState.FmtTime(m), Tag = m }); } StartCombo.SelectionChanged += StartCombo_Changed; EndCombo.SelectionChanged += EndCombo_Changed; UpdateDial(); } // ===== 다이얼/콤보 갱신 ===== void UpdateDial() { _updating = true; SleepArc.Data = BuildArc(_startMin, _endMin); PositionHandle(StartHandle, _startMin); PositionHandle(EndHandle, _endMin); StartRun.Text = DashboardState.FmtTime(_startMin); EndRun.Text = DashboardState.FmtTime(_endMin); StartCombo.SelectedIndex = _startMin / 30; EndCombo.SelectedIndex = _endMin / 30; _updating = false; } Geometry BuildArc(int s, int e) { Point p0 = Polar(s / 1440.0 * 360.0); Point p1 = Polar(e / 1440.0 * 360.0); double sweep = ((e - s + 1440) % 1440) / 1440.0 * 360.0; var fig = new System.Windows.Media.PathFigure { StartPoint = p0, IsClosed = false }; fig.Segments.Add(new ArcSegment(p1, new Size(R, R), 0, sweep > 180.0, SweepDirection.Clockwise, true)); var g = new PathGeometry(); g.Figures.Add(fig); return g; } static Point Polar(double angleDeg) // 0°=위, 시계방향 { double t = angleDeg * Math.PI / 180.0; return new Point(CX + R * Math.Sin(t), CY - R * Math.Cos(t)); } static void PositionHandle(FrameworkElement h, int min) { Point p = Polar(min / 1440.0 * 360.0); Canvas.SetLeft(h, p.X - h.Width / 2); Canvas.SetTop(h, p.Y - h.Height / 2); } static int AngleToMin(Point p) { double ang = Math.Atan2(p.X - CX, -(p.Y - CY)) * 180.0 / Math.PI; // 0=위, 시계방향 if (ang < 0) ang += 360; int min = (int)Math.Round(ang / 360.0 * 1440.0 / 30.0) * 30; return ((min % 1440) + 1440) % 1440; } // ===== 드래그 ===== void StartHandle_Down(object sender, MouseButtonEventArgs e) { _dragStart = true; StartHandle.CaptureMouse(); e.Handled = true; } void EndHandle_Down(object sender, MouseButtonEventArgs e) { _dragEnd = true; EndHandle.CaptureMouse(); e.Handled = true; } void Handle_Move(object sender, MouseEventArgs e) { if (!_dragStart && !_dragEnd) return; int min = AngleToMin(e.GetPosition(DialCanvas)); if (_dragStart) _startMin = min; else _endMin = min; UpdateDial(); } void Handle_Up(object sender, MouseButtonEventArgs e) { _dragStart = _dragEnd = false; (sender as UIElement)?.ReleaseMouseCapture(); } // ===== 콤보 ===== void StartCombo_Changed(object sender, SelectionChangedEventArgs e) { if (_updating || StartCombo.SelectedItem is not ComboBoxItem it) return; _startMin = (int)it.Tag; UpdateDial(); } void EndCombo_Changed(object sender, SelectionChangedEventArgs e) { if (_updating || EndCombo.SelectedItem is not ComboBoxItem it) return; _endMin = (int)it.Tag; UpdateDial(); } // ===== 버튼 ===== void Apply_Click(object sender, RoutedEventArgs e) { _state.SleepStartMin = _startMin; _state.SleepEndMin = _endMin; _owner.ApplySmartSleep(); Close(); } void Close_Click(object sender, RoutedEventArgs e) => Close(); } }