static void UpdateList() { CopyList(); if (!warning_list.empty()) { warning_list_frame->SetLength(warning_list.size()); int i = -1; if (selected_airspace != NULL) { auto it = std::find(warning_list.begin(), warning_list.end(), *selected_airspace); if (it != warning_list.end()) { i = it - warning_list.begin(); warning_list_frame->SetCursorIndex(i); } } if (i < 0) /* the selection may have changed, update CursorAirspace */ AirspaceWarningCursorCallback(warning_list_frame->GetCursorIndex()); } else { warning_list_frame->SetLength(1); selected_airspace = NULL; } warning_list_frame->Invalidate(); UpdateButtons(); AutoHide(); }
void dlgAirspaceWarningsShowModal(SingleWindow &parent, ProtectedAirspaceWarningManager &_warnings, bool _auto_close) { if (dlgAirspaceWarningVisible()) return; assert(warning_list.empty()); airspace_warnings = &_warnings; dialog = LoadDialog(CallBackTable, parent, _T("IDR_XML_AIRSPACEWARNINGS")); assert(dialog != NULL); ack_warn_button = (WndButton *)dialog->FindByName(_T("frmAck1")); ack_day_button = (WndButton *)dialog->FindByName(_T("frmAck2")); ack_space_button = (WndButton *)dialog->FindByName(_T("frmAck")); enable_button = (WndButton *)dialog->FindByName(_T("frmEnable")); assert(ack_warn_button != NULL); assert(ack_day_button != NULL); assert(ack_space_button != NULL); assert(enable_button != NULL); dialog->SetKeyDownFunction(OnKeyDown); warning_list_frame = (ListControl*)dialog->FindByName(_T("frmAirspaceWarningList")); assert(warning_list_frame != NULL); AirspaceWarningListHandler handler; warning_list_frame->SetHandler(&handler); auto_close = _auto_close; UpdateList(); // JMW need to deselect everything on new reopening of dialog selected_airspace = NULL; focused_airspace = NULL; auto update_timer = MakeLambdaTimer([](){ UpdateList(); }); update_timer.Schedule(500); warning_list_frame->SetCursorIndex(0); dialog->ShowModal(); update_timer.Cancel(); delete dialog; // Needed for dlgAirspaceWarningVisible() dialog = NULL; warning_list.clear(); }
void dlgAirspaceWarningsShowModal(SingleWindow &parent, ProtectedAirspaceWarningManager &_warnings, bool _auto_close) { if (dlgAirspaceWarningVisible()) return; assert(warning_list.empty()); airspace_warnings = &_warnings; dialog = LoadDialog(CallBackTable, parent, _T("IDR_XML_AIRSPACEWARNINGS")); assert(dialog != NULL); ack_warn_button = (WndButton *)dialog->FindByName(_T("frmAck1")); ack_day_button = (WndButton *)dialog->FindByName(_T("frmAck2")); ack_space_button = (WndButton *)dialog->FindByName(_T("frmAck")); enable_button = (WndButton *)dialog->FindByName(_T("frmEnable")); assert(ack_warn_button != NULL); assert(ack_day_button != NULL); assert(ack_space_button != NULL); assert(enable_button != NULL); dialog->SetKeyDownNotify(OnKeyDown); warning_list_frame = (ListControl*)dialog->FindByName(_T("frmAirspaceWarningList")); assert(warning_list_frame != NULL); warning_list_frame->SetPaintItemCallback(OnAirspaceListItemPaint); warning_list_frame->SetCursorCallback(AirspaceWarningCursorCallback); warning_list_frame->SetActivateCallback(OnAirspaceListEnter); auto_close = _auto_close; UpdateList(); // JMW need to deselect everything on new reopening of dialog selected_airspace = NULL; focused_airspace = NULL; dialog->SetTimerNotify(OnTimer); warning_list_frame->SetCursorIndex(0); dialog->ShowModal(); dialog->SetTimerNotify(NULL); delete dialog; // Needed for dlgAirspaceWarningVisible() dialog = NULL; warning_list.clear(); }
void AirspaceWarningListHandler::OnPaintItem(Canvas &canvas, const PixelRect paint_rc, unsigned i) { TCHAR buffer[128]; // This constant defines the margin that should be respected // for renderring within the paint_rc area. const int padding = 2; if (i == 0 && warning_list.empty()) { /* the warnings were emptied between the opening of the dialog and this refresh, so only need to display "No Warnings" for top item, otherwise exit immediately */ canvas.DrawText(paint_rc.left + Layout::Scale(padding), paint_rc.top + Layout::Scale(padding), _("No Warnings")); return; } assert(i < warning_list.size()); const WarningItem &warning = warning_list[i]; const AbstractAirspace &airspace = *warning.airspace; const AirspaceInterceptSolution &solution = warning.solution; const UPixelScalar text_height = 12, text_top = 1; // word "inside" is used as the etalon, because it is longer than "near" and // currently (9.4.2011) there is no other possibility for the status text. const int status_width = canvas.CalcTextWidth(_T("inside")); // "1888" is used in order to have enough space for 4-digit heights with "AGL" const int altitude_width = canvas.CalcTextWidth(_T("1888 m AGL")); // Dynamic columns scaling - "name" column is flexible, altitude and state // columns are fixed-width. const PixelScalar left0 = Layout::FastScale(padding), left2 = paint_rc.right - Layout::FastScale(padding) - (status_width + 2 * Layout::FastScale(padding)), left1 = left2 - Layout::FastScale(padding) - altitude_width; PixelRect rc_text_clip = paint_rc; rc_text_clip.right = left1 - Layout::FastScale(padding); if (!warning.ack_expired) canvas.SetTextColor(COLOR_GRAY); { // name, altitude info _sntprintf(buffer, 21, _T("%s %s"), airspace.GetName(), AirspaceFormatter::GetClass(airspace)); canvas.DrawClippedText(paint_rc.left + left0, paint_rc.top + Layout::Scale(text_top), rc_text_clip, buffer); AirspaceFormatter::FormatAltitudeShort(buffer, airspace.GetTop()); canvas.DrawText(paint_rc.left + left1, paint_rc.top + Layout::Scale(text_top), buffer); AirspaceFormatter::FormatAltitudeShort(buffer, airspace.GetBase()); canvas.DrawText(paint_rc.left + left1, paint_rc.top + Layout::Scale(text_top + text_height), buffer); } if (warning.state != AirspaceWarning::WARNING_INSIDE && warning.state > AirspaceWarning::WARNING_CLEAR && solution.IsValid()) { _stprintf(buffer, _T("%d secs"), (int)solution.elapsed_time); if (positive(solution.distance)) _stprintf(buffer + _tcslen(buffer), _T(" dist %d m"), (int)solution.distance); else { /* the airspace is right above or below us - show the vertical distance */ _tcscat(buffer, _T(" vertical ")); fixed delta = solution.altitude - CommonInterface::Basic().nav_altitude; FormatRelativeUserAltitude(delta, buffer + _tcslen(buffer), true); } canvas.DrawClippedText(paint_rc.left + left0, paint_rc.top + Layout::Scale(text_top + text_height), rc_text_clip, buffer); } /* draw the warning state indicator */ Color state_color; const TCHAR *state_text; if (warning.state == AirspaceWarning::WARNING_INSIDE) { state_color = warning.ack_expired ? inside_color : inside_ack_color; state_text = _T("inside"); } else if (warning.state > AirspaceWarning::WARNING_CLEAR) { state_color = warning.ack_expired ? near_color : near_ack_color; state_text = _T("near"); } else { state_color = COLOR_WHITE; state_text = NULL; } const PixelSize state_text_size = canvas.CalcTextSize(state_text != NULL ? state_text : _T("W")); if (state_color != COLOR_WHITE) { /* colored background */ PixelRect rc; rc.left = paint_rc.left + left2; rc.top = paint_rc.top + Layout::FastScale(padding); rc.right = paint_rc.right - Layout::FastScale(padding); rc.bottom = paint_rc.bottom - Layout::FastScale(padding); canvas.DrawFilledRectangle(rc, state_color); /* on this background we just painted, we must use black color for the state text; our caller might have selected a different color, override it here */ canvas.SetTextColor(COLOR_BLACK); } if (state_text != NULL) { // -- status text will be centered inside its table cell: canvas.DrawText(paint_rc.left + left2 + Layout::FastScale(padding) + (status_width / 2) - (canvas.CalcTextWidth(state_text) / 2), (paint_rc.bottom + paint_rc.top - state_text_size.cy) / 2, state_text); } }