static void
CopyList()
{
  const ProtectedAirspaceWarningManager::Lease lease(*airspace_warnings);

  warning_list.clear();
  for (auto i = lease->begin(), end = lease->end();
       i != end && !warning_list.full(); ++i)
    warning_list.push_back(*i);
}
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();
}
Example #3
0
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();
}
static void
AirspaceWarningCursorCallback(unsigned i)
{
  selected_airspace = i < warning_list.size()
    ? warning_list[i].airspace
    : NULL;

  UpdateButtons();
}
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
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);
  }
}