void FlightStatusPanel::Refresh() { const NMEAInfo &basic = CommonInterface::Basic(); const DerivedInfo &calculated = CommonInterface::Calculated(); if (basic.location_available) SetText(Location, FormatGeoPoint(basic.location)); else ClearText(Location); if (basic.gps_altitude_available) SetText(Altitude, FormatUserAltitude(basic.gps_altitude)); else ClearText(Altitude); SetText(MaxHeightGain, FormatUserAltitude(calculated.max_height_gain)); if (nearest_waypoint) { GeoVector vec(basic.location, nearest_waypoint->location); SetText(Near, nearest_waypoint->name.c_str()); SetText(Bearing, FormatBearing(vec.bearing).c_str()); SetText(Distance, FormatUserDistanceSmart(vec.distance)); } else { SetText(Near, _T("-")); SetText(Bearing, _T("-")); SetText(Distance, _T("-")); } }
void RulesStatusPanel::Refresh() { TCHAR Temp[80]; const DerivedInfo &calculated = CommonInterface::Calculated(); const TaskStats &task_stats = calculated.ordered_task_stats; const StartStats &start_stats = task_stats.start; const ComputerSettings &settings = CommonInterface::GetComputerSettings(); /// @todo proper task validity check SetText(ValidStart, start_stats.task_started ? _("Yes") : _T("No")); SetText(ValidFinish, task_stats.task_finished ? _("Yes") : _T("No")); if (start_stats.task_started) { SetText(StartTime, FormatLocalTimeHHMM((int)start_stats.time, settings.utc_offset)); SetText(StartSpeed, FormatUserTaskSpeed(start_stats.ground_speed)); SetText(StartHeight, FormatUserAltitude(start_stats.altitude)); } else { ClearValue(StartTime); ClearValue(StartSpeed); ClearValue(StartHeight); } Temp[0] = _T('\0'); double finish_height(0); if (protected_task_manager != nullptr) { ProtectedTaskManager::Lease task_manager(*protected_task_manager); const OrderedTask &task = task_manager->GetOrderedTask(); const unsigned task_size = task.TaskSize(); if (task_size > 0) { CopyString(Temp, task.GetTaskPoint(0).GetWaypoint().name.c_str(), ARRAY_SIZE(Temp)); finish_height = task.GetTaskPoint(task_size - 1).GetElevation(); } } SetText(StartPoint, Temp); SetText(FinishAlt, FormatUserAltitude(finish_height)); }
void InputEvents::eventTaskTransition(const TCHAR *misc) { if (protected_task_manager == NULL) return; if (StringIsEqual(misc, _T("start"))) { AircraftState start_state = protected_task_manager->GetStartState(); TCHAR TempTime[40]; TCHAR TempAlt[40]; TCHAR TempSpeed[40]; FormatSignedTimeHHMM(TempTime, (int)TimeLocal((int)start_state.time)); FormatUserAltitude(start_state.altitude, TempAlt, true); FormatUserSpeed(start_state.ground_speed,TempSpeed, true); TCHAR TempAll[120]; _stprintf(TempAll, _T("\r\nAltitude: %s\r\nSpeed:%s\r\nTime: %s"), TempAlt, TempSpeed, TempTime); Message::AddMessage(_("Task start"), TempAll); } else if (StringIsEqual(misc, _T("tp"))) { Message::AddMessage(_("Next turnpoint")); } else if (StringIsEqual(misc, _T("finish"))) { Message::AddMessage(_("Task finished")); } else if (StringIsEqual(misc, _T("ready"))) { Message::AddMessage(_("In sector, arm advance when ready")); } }
void InputEvents::eventTaskTransition(const TCHAR *misc) { if (protected_task_manager == NULL) return; if (StringIsEqual(misc, _T("start"))) { const StartStats &start_stats = CommonInterface::Calculated().ordered_task_stats.start; if (!start_stats.task_started) return; TCHAR TempAll[120]; _stprintf(TempAll, _T("\r\n%s: %s\r\n%s:%s\r\n%s: %s"), _("Altitude"), FormatUserAltitude(start_stats.altitude).c_str(), _("Speed"), FormatUserSpeed(start_stats.ground_speed, true).c_str(), _("Time"), FormatLocalTimeHHMM((int)start_stats.time, CommonInterface::GetComputerSettings().utc_offset).c_str()); Message::AddMessage(_("Task start"), TempAll); } else if (StringIsEqual(misc, _T("next"))) { Message::AddMessage(_("Next turnpoint")); } else if (StringIsEqual(misc, _T("finish"))) { Message::AddMessage(_("Task finished")); } }
void MapItemListRenderer::Draw(Canvas &canvas, const PixelRect rc, const TrafficMapItem &item, const DialogLook &dialog_look, const TrafficLook &traffic_look) { const PixelScalar line_height = rc.bottom - rc.top; const FlarmTraffic traffic = item.traffic; // Now render the text information const Font &name_font = *dialog_look.list.font; const Font &small_font = *dialog_look.small_font; PixelScalar left = rc.left + line_height + Layout::FastScale(2); const FlarmRecord *record = FlarmDetails::LookupRecord(item.traffic.id); StaticString<256> title_string; if (record && !StringIsEmpty(record->pilot)) title_string = record->pilot.c_str(); else title_string = _("FLARM Traffic"); // Append name to the title, if it exists if (traffic.HasName()) { title_string.append(_T(", ")); title_string.append(traffic.name); } canvas.Select(name_font); canvas.text_clipped(left, rc.top + Layout::FastScale(2), rc, title_string); StaticString<256> info_string; if (record && !StringIsEmpty(record->plane_type)) info_string = record->plane_type; else info_string = FlarmTraffic::GetTypeString(item.traffic.type); // Generate the line of info about the target, if it's available if (traffic.altitude_available) { TCHAR tmp[15]; FormatUserAltitude(traffic.altitude, tmp, 15); info_string.AppendFormat(_T(", %s: %s"), _("Altitude"), tmp); } if (traffic.climb_rate_avg30s_available) { TCHAR tmp[15]; FormatUserVerticalSpeed(traffic.climb_rate_avg30s, tmp, 15); info_string.AppendFormat(_T(", %s: %s"), _("Vario"), tmp); } canvas.Select(small_font); canvas.text_clipped(left, rc.top + name_font.GetHeight() + Layout::FastScale(4), rc, info_string); RasterPoint pt = { (PixelScalar)(rc.left + line_height / 2), (PixelScalar)(rc.top + line_height / 2) }; // Render the representation of the traffic icon TrafficRenderer::Draw(canvas, traffic_look, traffic, traffic.track, item.color, pt); }
gcc_const static inline StringBuffer<TCHAR, 32> FormatUserAltitude(double value) { StringBuffer<TCHAR, 32> buffer; FormatUserAltitude(value, buffer.data()); return buffer; }
void AltitudeInfoPanel::Refresh() { const DerivedInfo &calculated = CommonInterface::Calculated(); const NMEAInfo &basic = CommonInterface::Basic(); TCHAR sTmp[32]; RowFormWidget &first = (RowFormWidget &)GetFirst(); RowFormWidget &second = (RowFormWidget &)GetSecond(); if (!calculated.altitude_agl_valid) { second.SetText(0, _("N/A")); } else { // Set Value FormatUserAltitude(calculated.altitude_agl, sTmp, ARRAY_SIZE(sTmp)); second.SetText(0, sTmp); } if (!basic.baro_altitude_available) { first.SetText(1, _("N/A")); } else { // Set Value FormatUserAltitude(basic.baro_altitude, sTmp, ARRAY_SIZE(sTmp)); first.SetText(1, sTmp); } if (!basic.gps_altitude_available) { first.SetText(0, _("N/A")); } else { // Set Value FormatUserAltitude(basic.gps_altitude, sTmp, ARRAY_SIZE(sTmp)); first.SetText(0, sTmp); } if (!calculated.terrain_valid){ second.SetText(1, _("N/A")); } else { // Set Value FormatUserAltitude(calculated.terrain_altitude, sTmp, ARRAY_SIZE(sTmp)); second.SetText(1, sTmp); } }
void FlightStatusPanel::Refresh() { const NMEAInfo &basic = CommonInterface::Basic(); const DerivedInfo &calculated = CommonInterface::Calculated(); StaticString<32> buffer; if (basic.location_available) { FormatGeoPoint(basic.location, buffer.buffer(), buffer.MAX_SIZE); SetText(Location, buffer); } else SetText(Location, _T("")); if (basic.gps_altitude_available) { FormatUserAltitude(basic.gps_altitude, buffer.buffer(), buffer.MAX_SIZE); SetText(Altitude, buffer); } else SetText(Altitude, _T("")); FormatUserAltitude(calculated.max_height_gain, buffer.buffer(), buffer.MAX_SIZE); SetText(MaxHeightGain, buffer); if (nearest_waypoint) { GeoVector vec(basic.location, nearest_waypoint->location); SetText(Near, nearest_waypoint->name.c_str()); FormatBearing(buffer.buffer(), buffer.MAX_SIZE, vec.bearing, _T("")); SetText(Bearing, buffer); FormatUserDistanceSmart(vec.distance, buffer.buffer(), buffer.MAX_SIZE); SetText(Distance, buffer); } else { SetText(Near, _T("-")); SetText(Bearing, _T("-")); SetText(Distance, _T("-")); } }
void GlueMapWindow::DrawPanInfo(Canvas &canvas) const { GeoPoint location = render_projection.GetGeoLocation(); TextInBoxMode mode; mode.mode = RenderMode::RM_OUTLINED_INVERTED; mode.bold = true; mode.align = A_RIGHT; UPixelScalar padding = Layout::FastScale(4); UPixelScalar height = Fonts::map_bold.GetHeight(); PixelScalar y = 0 + padding; PixelScalar x = render_projection.GetScreenWidth() - padding; if (terrain) { short elevation = terrain->GetTerrainHeight(location); if (!RasterBuffer::IsSpecial(elevation)) { StaticString<64> elevation_short, elevation_long; FormatUserAltitude(fixed(elevation), elevation_short.buffer(), elevation_short.MAX_SIZE); elevation_long = _("Elevation: "); elevation_long += elevation_short; TextInBox(canvas, elevation_long, x, y, mode, render_projection.GetScreenWidth(), render_projection.GetScreenHeight()); y += height; } } TCHAR buffer[256]; FormatGeoPoint(location, buffer, ARRAY_SIZE(buffer), _T('\n')); TCHAR *start = buffer; while (true) { TCHAR *newline = _tcschr(start, _T('\n')); if (newline != NULL) *newline = _T('\0'); TextInBox(canvas, start, x, y, mode, render_projection.GetScreenWidth(), render_projection.GetScreenHeight()); y += height; if (newline == NULL) break; start = newline + 1; } }
/** * Updates all the dialogs fields, that are changing frequently. * e.g. climb speed, distance, height */ void FlarmTrafficDetailsWidget::UpdateChanging(const MoreData &basic) { TCHAR tmp[40]; const TCHAR *value; const FlarmTraffic* target = basic.flarm.traffic.FindTraffic(target_id); bool target_ok = target && target->IsDefined(); // Fill distance/direction field if (target_ok) { FormatUserDistanceSmart(target->distance, tmp, 20, fixed(1000)); TCHAR *p = tmp + _tcslen(tmp); *p++ = _T(' '); FormatAngleDelta(p, 20, target->Bearing() - basic.track); value = tmp; } else value = _T("--"); SetText(DISTANCE, value); // Fill altitude field if (target_ok) { TCHAR *p = tmp; if (target->altitude_available) { FormatUserAltitude(target->altitude, p, 20); p += _tcslen(p); *p++ = _T(' '); } Angle dir = Angle::FromXY(target->distance, target->relative_altitude); FormatVerticalAngleDelta(p, 20, dir); value = tmp; } else value = _T("--"); SetText(ALTITUDE, value); // Fill climb speed field if (target_ok && target->climb_rate_avg30s_available) { FormatUserVerticalSpeed(target->climb_rate_avg30s, tmp, 20); value = tmp; } else value = _T("--"); SetText(VARIO, value); }
void InfoBoxContentBarogram::Update(InfoBoxData &data) { const MoreData &basic = CommonInterface::Basic(); TCHAR sTmp[32]; if (basic.NavAltitudeAvailable()) { FormatUserAltitude(basic.nav_altitude, sTmp, ARRAY_SIZE(sTmp)); data.SetComment(sTmp); } else data.SetCommentInvalid(); data.SetCustom(); }
bool Units::FormatAlternateUserAltitude(double Altitude, TCHAR *Buffer, size_t size){ Units_t saveUnit = UserAltitudeUnit; bool res; if (saveUnit == unMeter) UserAltitudeUnit = unFeet; if (saveUnit == unFeet) UserAltitudeUnit = unMeter; res = FormatUserAltitude(Altitude, Buffer, size); UserAltitudeUnit = saveUnit; return(res); }
/** * Updates all the dialogs fields, that are changing frequently. * e.g. climb speed, distance, height */ static void UpdateChanging() { TCHAR tmp[20]; const FlarmTraffic* target = XCSoarInterface::Basic().flarm.traffic.FindTraffic(target_id); bool target_ok = target && target->IsDefined(); // Fill distance field if (target_ok) FormatUserDistanceSmart(target->distance, tmp, 20, fixed(1000)); else _tcscpy(tmp, _T("--")); SetFormValue(*wf, _T("prpDistance"), tmp); // Fill horizontal direction field if (target_ok) FormatAngleDelta(tmp, ARRAY_SIZE(tmp), target->Bearing() - CommonInterface::Basic().track); else _tcscpy(tmp, _T("--")); SetFormValue(*wf, _T("prpDirectionH"), tmp); // Fill altitude field if (target_ok && target->altitude_available) FormatUserAltitude(target->altitude, tmp, 20); else _tcscpy(tmp, _T("--")); SetFormValue(*wf, _T("prpAltitude"), tmp); // Fill vertical direction field if (target_ok) { Angle dir = Angle::Radians((fixed)atan2(target->relative_altitude, target->distance)).AsDelta(); FormatVerticalAngleDelta(tmp, ARRAY_SIZE(tmp), dir); } else _tcscpy(tmp, _T("--")); SetFormValue(*wf, _T("prpDirectionV"), tmp); // Fill climb speed field if (target_ok && target->climb_rate_avg30s_available) FormatUserVerticalSpeed(target->climb_rate_avg30s, tmp, 20); else _tcscpy(tmp, _T("--")); SetFormValue(*wf, _T("prpVSpeed"), tmp); }
static void FormatWaypointDetails(Buffer &buffer, const Waypoint &waypoint) { TCHAR alt[16]; FormatUserAltitude(waypoint.elevation, alt, 16); buffer.Format(_T("%s: %s"), _("Elevation"), alt); if (waypoint.radio_frequency.IsDefined()) { TCHAR radio[16]; waypoint.radio_frequency.Format(radio, 16); buffer.AppendFormat(_T(" - %s MHz"), radio); } if (!waypoint.comment.empty()) { buffer.AppendFormat(_T(" - %s"), waypoint.comment.c_str()); } }
static void Draw(Canvas &canvas, PixelRect rc, const SkyLinesTrafficMapItem &item, const TwoTextRowsRenderer &row_renderer) { rc.right = row_renderer.DrawRightFirstRow(canvas, rc, FormatUserAltitude(item.altitude)); row_renderer.DrawFirstRow(canvas, rc, item.name); if (CommonInterface::Basic().time_available) { StaticString<64> buffer; buffer.UnsafeFormat(_("%u minutes ago"), SinceInMinutes(CommonInterface::Basic().time, item.time_of_day_ms)); row_renderer.DrawSecondRow(canvas, rc, buffer); } }
bool Units::FormatAlternateUserAltitude(fixed Altitude, TCHAR *Buffer, size_t size, bool IncludeUnit) { Units_t saveUnit = AltitudeUnit; bool res; if (saveUnit == unMeter) AltitudeUnit = unFeet; if (saveUnit == unFeet) AltitudeUnit = unMeter; res = FormatUserAltitude(Altitude, Buffer, size, IncludeUnit); AltitudeUnit = saveUnit; return res; }
void MapItemListRenderer::Draw(Canvas &canvas, const PixelRect rc, const LocationMapItem &item, const DialogLook &dialog_look) { const Font &name_font = *dialog_look.list.font_bold; const Font &small_font = *dialog_look.small_font; PixelScalar left = rc.left + Layout::FastScale(2); TCHAR info_buffer[256], distance_buffer[32], direction_buffer[32]; if (item.vector.IsValid()) { FormatUserDistanceSmart(item.vector.distance, distance_buffer, 32); FormatBearing(direction_buffer, ARRAY_SIZE(direction_buffer), item.vector.bearing); _stprintf(info_buffer, _T("%s: %s, %s: %s"), _("Distance"), distance_buffer, _("Direction"), direction_buffer); } else { _stprintf(info_buffer, _T("%s: %s, %s: %s"), _("Distance"), _T("???"), _("Direction"), _T("???")); } canvas.Select(name_font); canvas.DrawClippedText(left, rc.top + Layout::FastScale(2), rc, info_buffer); TCHAR elevation_buffer[32]; if (!RasterBuffer::IsSpecial(item.elevation)) { FormatUserAltitude(fixed(item.elevation), elevation_buffer, 32); _stprintf(info_buffer, _T("%s: %s"), _("Elevation"), elevation_buffer); } else { _stprintf(info_buffer, _T("%s: %s"), _("Elevation"), _T("???")); } canvas.Select(small_font); canvas.DrawClippedText(left, rc.top + name_font.GetHeight() + Layout::FastScale(4), rc, info_buffer); }
static void Draw(Canvas &canvas, const PixelRect rc, const LocationMapItem &item, const TwoTextRowsRenderer &row_renderer) { TCHAR info_buffer[256]; if (item.vector.IsValid()) StringFormatUnsafe(info_buffer, _T("%s: %s, %s: %s"), _("Distance"), FormatUserDistanceSmart(item.vector.distance).c_str(), _("Direction"), FormatBearing(item.vector.bearing).c_str()); else StringFormatUnsafe(info_buffer, _T("%s: %s, %s: %s"), _("Distance"), _T("???"), _("Direction"), _T("???")); row_renderer.DrawFirstRow(canvas, rc, info_buffer); StringFormatUnsafe(info_buffer, _T("%s: %s"), _("Elevation"), item.HasElevation() ? FormatUserAltitude(item.elevation).c_str() : _T("???")); row_renderer.DrawSecondRow(canvas, rc, info_buffer); }
void WaypointInfoWidget::Prepare(ContainerWindow &parent, const PixelRect &rc) { RowFormWidget::Prepare(parent, rc); const MoreData &basic = CommonInterface::Basic(); const DerivedInfo &calculated = CommonInterface::Calculated(); const ComputerSettings &settings = CommonInterface::GetComputerSettings(); StaticString<64> buffer; if (!waypoint.comment.empty()) AddMultiLine(waypoint.comment.c_str()); if (waypoint.radio_frequency.IsDefined() && waypoint.radio_frequency.Format(buffer.buffer(), buffer.MAX_SIZE) != NULL) { buffer += _T(" MHz"); AddReadOnly(_("Radio frequency"), NULL, buffer); } if (waypoint.runway.IsDirectionDefined()) buffer.UnsafeFormat(_T("%02u"), waypoint.runway.GetDirectionName()); else buffer.clear(); if (waypoint.runway.IsLengthDefined()) { if (!buffer.empty()) buffer += _T("; "); TCHAR length_buffer[16]; FormatSmallUserDistance(length_buffer, fixed(waypoint.runway.GetLength())); buffer += length_buffer; } if (!buffer.empty()) AddReadOnly(_("Runway"), NULL, buffer); if (FormatGeoPoint(waypoint.location, buffer.buffer(), buffer.MAX_SIZE) != NULL) AddReadOnly(_("Location"), NULL, buffer); FormatUserAltitude(waypoint.elevation, buffer.buffer(), buffer.MAX_SIZE); AddReadOnly(_("Elevation"), NULL, buffer); if (basic.time_available) { const SunEphemeris::Result sun = SunEphemeris::CalcSunTimes(waypoint.location, basic.date_time_utc, fixed(GetUTCOffset()) / 3600); const unsigned sunrisehours = (int)sun.time_of_sunrise; const unsigned sunrisemins = (int)((sun.time_of_sunrise - fixed(sunrisehours)) * 60); const unsigned sunset_hour = (int)sun.time_of_sunset; const unsigned sunset_minute = (int)((sun.time_of_sunset - fixed(sunset_hour)) * 60); buffer.UnsafeFormat(_T("%02u:%02u - %02u:%02u"), sunrisehours, sunrisemins, sunset_hour, sunset_minute); AddReadOnly(_("Daylight time"), NULL, buffer); } if (basic.location_available) { const GeoVector vector = basic.location.DistanceBearing(waypoint.location); TCHAR distance_buffer[32]; FormatUserDistanceSmart(vector.distance, distance_buffer, ARRAY_SIZE(distance_buffer)); FormatBearing(buffer.buffer(), buffer.MAX_SIZE, vector.bearing, distance_buffer); AddReadOnly(_("Bearing and Distance"), NULL, buffer); } if (basic.location_available && basic.NavAltitudeAvailable() && settings.polar.glide_polar_task.IsValid()) { const GlideState glide_state(basic.location.DistanceBearing(waypoint.location), waypoint.elevation + settings.task.safety_height_arrival, basic.nav_altitude, calculated.GetWindOrZero()); GlidePolar gp0 = settings.polar.glide_polar_task; gp0.SetMC(fixed(0)); AddGlideResult(_("Alt. diff. MC 0"), MacCready::Solve(settings.task.glide, gp0, glide_state)); AddGlideResult(_("Alt. diff. MC safety"), MacCready::Solve(settings.task.glide, calculated.glide_polar_safety, glide_state)); AddGlideResult(_("Alt. diff. MC current"), MacCready::Solve(settings.task.glide, settings.polar.glide_polar_task, glide_state)); } }
void InfoBoxData::SetValueFromAltitude(fixed new_value) { FormatUserAltitude(new_value, value.buffer(), false); SetValueUnit(Units::current.altitude_unit); }
static void Draw(Canvas &canvas, PixelRect rc, const ArrivalAltitudeMapItem &item, const TwoTextRowsRenderer &row_renderer, const FinalGlideBarLook &look) { const unsigned line_height = rc.GetHeight(); bool reach_relevant = item.reach.IsReachRelevant(); int arrival_altitude = item.reach.terrain_valid == ReachResult::Validity::VALID ? item.reach.terrain : item.reach.direct; if (item.HasElevation()) arrival_altitude -= item.elevation; bool reachable = item.reach.terrain_valid != ReachResult::Validity::UNREACHABLE && arrival_altitude >= 0; // Draw final glide arrow icon const PixelPoint pt(rc.left + line_height / 2, rc.top + line_height / 2); BulkPixelPoint arrow[] = { { -7, -3 }, { 0, 4 }, { 7, -3 } }; Angle arrow_angle = reachable ? Angle::HalfCircle() : Angle::Zero(); PolygonRotateShift(arrow, ARRAY_SIZE(arrow), pt, arrow_angle); if (reachable) { canvas.Select(look.brush_above); canvas.Select(look.pen_above); } else { canvas.Select(look.brush_below); canvas.Select(look.pen_below); } canvas.DrawPolygon(arrow, ARRAY_SIZE(arrow)); const unsigned text_padding = Layout::GetTextPadding(); rc.left += line_height + text_padding; // Format title row TCHAR altitude_buffer[32]; StaticString<256> buffer; buffer.clear(); if (item.HasElevation()) { int relative_arrival_altitude = item.reach.direct - item.elevation; FormatRelativeUserAltitude(relative_arrival_altitude, altitude_buffer, ARRAY_SIZE(altitude_buffer)); buffer.AppendFormat(_T("%s %s, "), altitude_buffer, _("AGL")); } buffer.AppendFormat(_T("%s %s"), FormatUserAltitude(item.reach.direct).c_str(), _("MSL")); // Draw title row row_renderer.DrawFirstRow(canvas, rc, buffer); // Format comment row if (reach_relevant) { buffer.Format(_T("%s: "), _("around terrain")); if (item.HasElevation()) { int relative_arrival_altitude = item.reach.terrain - item.elevation; FormatRelativeUserAltitude(relative_arrival_altitude, altitude_buffer, ARRAY_SIZE(altitude_buffer)); buffer.AppendFormat(_T("%s %s, "), altitude_buffer, _("AGL")); } buffer.AppendFormat(_T("%s %s, "), FormatUserAltitude(item.reach.terrain).c_str(), _("MSL")); } else if (item.HasElevation() && item.reach.direct >= item.elevation && item.reach.terrain_valid == ReachResult::Validity::UNREACHABLE) { buffer.UnsafeFormat(_T("%s "), _("Unreachable due to terrain.")); } else { buffer.clear(); } buffer += _("Arrival altitude incl. safety height"); // Draw comment row row_renderer.DrawSecondRow(canvas, rc, buffer); }
static void Draw(Canvas &canvas, PixelRect rc, const TrafficMapItem &item, const TwoTextRowsRenderer &row_renderer, const TrafficLook &traffic_look, const TrafficList *traffic_list) { const unsigned line_height = rc.GetHeight(); const unsigned text_padding = Layout::GetTextPadding(); const FlarmTraffic *traffic = traffic_list == nullptr ? nullptr : traffic_list->FindTraffic(item.id); const PixelPoint pt(rc.left + line_height / 2, rc.top + line_height / 2); // Render the representation of the traffic icon if (traffic != nullptr) TrafficRenderer::Draw(canvas, traffic_look, *traffic, traffic->track, item.color, pt); rc.left += line_height + text_padding; // Now render the text information const FlarmNetRecord *record = FlarmDetails::LookupRecord(item.id); StaticString<256> title_string; if (record && !StringIsEmpty(record->pilot)) title_string = record->pilot.c_str(); else title_string = _("FLARM Traffic"); // Append name to the title, if it exists const TCHAR *callsign = FlarmDetails::LookupCallsign(item.id); if (callsign != nullptr && !StringIsEmpty(callsign)) { title_string.append(_T(", ")); title_string.append(callsign); } row_renderer.DrawFirstRow(canvas, rc, title_string); StaticString<256> info_string; if (record && !StringIsEmpty(record->plane_type)) info_string = record->plane_type; else if (traffic != nullptr) info_string = FlarmTraffic::GetTypeString(traffic->type); else info_string = _("Unknown"); // Generate the line of info about the target, if it's available if (traffic != nullptr) { if (traffic->altitude_available) info_string.AppendFormat(_T(", %s: %s"), _("Altitude"), FormatUserAltitude(traffic->altitude).c_str()); if (traffic->climb_rate_avg30s_available) { TCHAR tmp[15]; FormatUserVerticalSpeed(traffic->climb_rate_avg30s, tmp, 15); info_string.AppendFormat(_T(", %s: %s"), _("Vario"), tmp); } } row_renderer.DrawSecondRow(canvas, rc, info_string); }
void WaypointInfoWidget::Prepare(ContainerWindow &parent, const PixelRect &rc) { RowFormWidget::Prepare(parent, rc); const MoreData &basic = CommonInterface::Basic(); const DerivedInfo &calculated = CommonInterface::Calculated(); const ComputerSettings &settings = CommonInterface::GetComputerSettings(); StaticString<64> buffer; if (!waypoint.comment.empty()) AddMultiLine(waypoint.comment.c_str()); if (waypoint.radio_frequency.IsDefined() && waypoint.radio_frequency.Format(buffer.buffer(), buffer.MAX_SIZE) != nullptr) { buffer += _T(" MHz"); AddReadOnly(_("Radio frequency"), nullptr, buffer); } if (waypoint.runway.IsDirectionDefined()) buffer.UnsafeFormat(_T("%02u"), waypoint.runway.GetDirectionName()); else buffer.clear(); if (waypoint.runway.IsLengthDefined()) { if (!buffer.empty()) buffer += _T("; "); TCHAR length_buffer[16]; FormatSmallUserDistance(length_buffer, fixed(waypoint.runway.GetLength())); buffer += length_buffer; } if (!buffer.empty()) AddReadOnly(_("Runway"), nullptr, buffer); if (FormatGeoPoint(waypoint.location, buffer.buffer(), buffer.MAX_SIZE) != nullptr) AddReadOnly(_("Location"), nullptr, buffer); FormatUserAltitude(waypoint.elevation, buffer.buffer(), buffer.MAX_SIZE); AddReadOnly(_("Elevation"), nullptr, buffer); if (basic.time_available && basic.date_time_utc.IsDatePlausible()) { const SunEphemeris::Result sun = SunEphemeris::CalcSunTimes(waypoint.location, basic.date_time_utc, settings.utc_offset); const BrokenTime sunrise = BreakHourOfDay(sun.time_of_sunrise); const BrokenTime sunset = BreakHourOfDay(sun.time_of_sunset); buffer.UnsafeFormat(_T("%02u:%02u - %02u:%02u"), sunrise.hour, sunrise.minute, sunset.hour, sunset.minute); AddReadOnly(_("Daylight time"), nullptr, buffer); } if (basic.location_available) { const GeoVector vector = basic.location.DistanceBearing(waypoint.location); TCHAR distance_buffer[32]; FormatUserDistanceSmart(vector.distance, distance_buffer, ARRAY_SIZE(distance_buffer)); FormatBearing(buffer.buffer(), buffer.MAX_SIZE, vector.bearing, distance_buffer); AddReadOnly(_("Bearing and Distance"), nullptr, buffer); } if (basic.location_available && basic.NavAltitudeAvailable() && settings.polar.glide_polar_task.IsValid()) { const GlideState glide_state(basic.location.DistanceBearing(waypoint.location), waypoint.elevation + settings.task.safety_height_arrival, basic.nav_altitude, calculated.GetWindOrZero()); GlidePolar gp0 = settings.polar.glide_polar_task; gp0.SetMC(fixed(0)); AddGlideResult(_("Alt. diff. MC 0"), MacCready::Solve(settings.task.glide, gp0, glide_state)); AddGlideResult(_("Alt. diff. MC safety"), MacCready::Solve(settings.task.glide, calculated.glide_polar_safety, glide_state)); AddGlideResult(_("Alt. diff. MC current"), MacCready::Solve(settings.task.glide, settings.polar.glide_polar_task, glide_state)); } if (basic.location_available && basic.NavAltitudeAvailable()) { const TaskBehaviour &task_behaviour = CommonInterface::GetComputerSettings().task; const fixed safety_height = task_behaviour.safety_height_arrival; const fixed target_altitude = waypoint.elevation + safety_height; const fixed delta_h = basic.nav_altitude - target_altitude; if (positive(delta_h)) { const fixed distance = basic.location.Distance(waypoint.location); const fixed gr = distance / delta_h; if (GradientValid(gr)) { buffer.UnsafeFormat(_T("%.1f"), (double)gr); AddReadOnly(_("Required glide ratio"), nullptr, buffer); } } } }
void GlueMapWindow::DrawPanInfo(Canvas &canvas) const { if (!render_projection.IsValid()) return; GeoPoint location = render_projection.GetGeoLocation(); TextInBoxMode mode; mode.shape = LabelShape::OUTLINED; mode.align = TextInBoxMode::Alignment::RIGHT; const Font &font = *look.overlay_font; canvas.Select(font); UPixelScalar padding = Layout::FastScale(4); UPixelScalar height = font.GetHeight(); PixelScalar y = 0 + padding; PixelScalar x = render_projection.GetScreenWidth() - padding; if (compass_visible) /* don't obscure the north arrow */ /* TODO: obtain offset from CompassRenderer */ y += Layout::Scale(19) + Layout::FastScale(13); if (terrain) { short elevation = terrain->GetTerrainHeight(location); if (!RasterBuffer::IsSpecial(elevation)) { StaticString<64> elevation_short, elevation_long; FormatUserAltitude(fixed(elevation), elevation_short.buffer(), elevation_short.MAX_SIZE); elevation_long = _("Elevation: "); elevation_long += elevation_short; TextInBox(canvas, elevation_long, x, y, mode, render_projection.GetScreenWidth(), render_projection.GetScreenHeight()); y += height; } } TCHAR buffer[256]; FormatGeoPoint(location, buffer, ARRAY_SIZE(buffer), _T('\n')); TCHAR *start = buffer; while (true) { TCHAR *newline = _tcschr(start, _T('\n')); if (newline != nullptr) *newline = _T('\0'); TextInBox(canvas, start, x, y, mode, render_projection.GetScreenWidth(), render_projection.GetScreenHeight()); y += height; if (newline == nullptr) break; start = newline + 1; } }
void MapItemListRenderer::Draw(Canvas &canvas, const PixelRect rc, const ArrivalAltitudeMapItem &item, const DialogLook &dialog_look, const FinalGlideBarLook &look) { const UPixelScalar line_height = rc.bottom - rc.top; bool elevation_available = !RasterBuffer::IsSpecial((short)item.elevation); bool reach_relevant = item.reach.IsReachRelevant(); RoughAltitude arrival_altitude = item.reach.terrain_valid == ReachResult::Validity::VALID ? item.reach.terrain : item.reach.direct; if (elevation_available) arrival_altitude -= item.elevation; bool reachable = item.reach.terrain_valid != ReachResult::Validity::UNREACHABLE && arrival_altitude.IsPositive(); // Draw final glide arrow icon RasterPoint pt = { (PixelScalar)(rc.left + line_height / 2), (PixelScalar)(rc.top + line_height / 2) }; RasterPoint arrow[] = { { -7, -3 }, { 0, 4 }, { 7, -3 } }; Angle arrow_angle = reachable ? Angle::HalfCircle() : Angle::Zero(); PolygonRotateShift(arrow, ARRAY_SIZE(arrow), pt.x, pt.y, arrow_angle, 100); if (reachable) { canvas.Select(look.brush_above); canvas.Select(look.pen_above); } else { canvas.Select(look.brush_below); canvas.Select(look.pen_below); } canvas.DrawPolygon(arrow, ARRAY_SIZE(arrow)); const Font &name_font = *dialog_look.list.font_bold; const Font &small_font = *dialog_look.small_font; PixelScalar left = rc.left + line_height + Layout::FastScale(2); // Format title row TCHAR altitude_buffer[32]; StaticString<256> buffer; buffer.clear(); if (elevation_available) { RoughAltitude relative_arrival_altitude = item.reach.direct - item.elevation; FormatRelativeUserAltitude(fixed((short)relative_arrival_altitude), altitude_buffer, ARRAY_SIZE(altitude_buffer)); buffer.AppendFormat(_T("%s %s, "), altitude_buffer, _("AGL")); } FormatUserAltitude(fixed(item.reach.direct), altitude_buffer, ARRAY_SIZE(altitude_buffer)); buffer.AppendFormat(_T("%s %s"), altitude_buffer, _("MSL")); // Draw title row canvas.Select(name_font); canvas.DrawClippedText(left, rc.top + Layout::FastScale(2), rc, buffer); // Format comment row if (reach_relevant) { buffer.Format(_T("%s: "), _("around terrain")); if (elevation_available) { RoughAltitude relative_arrival_altitude = item.reach.terrain - item.elevation; FormatRelativeUserAltitude(fixed((short)relative_arrival_altitude), altitude_buffer, ARRAY_SIZE(altitude_buffer)); buffer.AppendFormat(_T("%s %s, "), altitude_buffer, _("AGL")); } FormatUserAltitude(fixed(item.reach.terrain), altitude_buffer, ARRAY_SIZE(altitude_buffer)); buffer.AppendFormat(_T("%s %s, "), altitude_buffer, _("MSL")); } else if (elevation_available && (int)item.reach.direct >= (int)item.elevation && item.reach.terrain_valid == ReachResult::Validity::UNREACHABLE) { buffer.UnsafeFormat(_T("%s "), _("Unreachable due to terrain.")); } else { buffer.clear(); } buffer += _("Arrival altitude incl. safety height"); // Draw comment row canvas.Select(small_font); canvas.DrawClippedText(left, rc.top + name_font.GetHeight() + Layout::FastScale(4), rc, buffer); }
void FinalGlideBarRenderer::Draw(Canvas &canvas, const PixelRect &rc, const DerivedInfo &calculated, const GlideSettings &glide_settings, const bool final_glide_bar_mc0_enabled) const { #ifdef ENABLE_OPENGL const ScopeAlphaBlend alpha_blend; #endif BulkPixelPoint GlideBar[6] = { { 0, 0 }, { 9, -9 }, { 18, 0 }, { 18, 0 }, { 9, 0 }, { 0, 0 } }; BulkPixelPoint GlideBar0[4] = { { 0, 0 }, { 9, -9 }, { 9, 0 }, { 0, 0 } }; BulkPixelPoint clipping_arrow[6] = { { 0, 0 }, { 9, 9 }, { 18, 0 }, { 18, 6 }, { 9, 15 }, { 0, 6 } }; BulkPixelPoint clipping_arrow0[4] = { { 0, 0 }, { 9, 9 }, { 9, 15 }, { 0, 6 } }; TCHAR Value[10]; const TaskStats &task_stats = calculated.task_stats; const ElementStat &total = task_stats.total; const GlideResult &solution = total.solution_remaining; const GlideResult &solution_mc0 = total.solution_mc0; if (!task_stats.task_valid || !solution.IsOk() || !solution_mc0.IsDefined()) return; const int y0 = (rc.bottom + rc.top) / 2; /* NOTE: size_divisor replaces the fixed value 9 that was used throughout * the code below which caused fixed size rendering regardless of * map size (except the effects of Layout::Scale()). This method * is not usable with variable map sizes (e.g. because of the cross-section * area). size_divisor is used to introduce a screen size dependent scaling. * That workaround is an ugly hack and needs a rework. */ const int size_divisor = std::max(Layout::Scale(3000u / rc.GetHeight()), 4u); int dy_glidebar = 0; int dy_glidebar0 = 0; FormatUserAltitude(solution.SelectAltitudeDifference(glide_settings), Value, false); canvas.Select(*look.font); const PixelSize text_size = canvas.CalcTextSize(Value); int clipping_arrow_offset = Layout::Scale(4); int clipping_arrow0_offset = Layout::Scale(4); // 468 meters is it's size. Will be divided by 9 to fit screen resolution. int altitude_difference = (int) solution.SelectAltitudeDifference(glide_settings); int altitude_difference0 = (int) solution_mc0.SelectAltitudeDifference(glide_settings); // TODO feature: should be an angle if in final glide mode // cut altitude_difference at +- 468 meters (55 units) if (altitude_difference > 468) altitude_difference = 468; if (altitude_difference < -468) altitude_difference = -468; // 55 units is size, 468 meters div by 9 means 55. int Offset = altitude_difference / size_divisor; Offset = Layout::Scale(Offset); if (altitude_difference <= 0) { GlideBar[1].y = Layout::Scale(9); dy_glidebar = text_size.cy + 2; } else { GlideBar[1].y = -Layout::Scale(9); clipping_arrow[1].y = -clipping_arrow[1].y; clipping_arrow[3].y = -clipping_arrow[3].y; clipping_arrow[4].y = -clipping_arrow[4].y; clipping_arrow[5].y = -clipping_arrow[5].y; clipping_arrow_offset = -clipping_arrow_offset; dy_glidebar = -1; } // cut altitude_difference0 at +- 468 meters (55 units) if (altitude_difference0 > 468) altitude_difference0 = 468; if (altitude_difference0 < -468) altitude_difference0 = -468; // 55 units is size, therefore div by 9. int Offset0 = altitude_difference0 / size_divisor; Offset0 = Layout::Scale(Offset0); if (altitude_difference0 <= 0) { GlideBar0[1].y = Layout::Scale(9); dy_glidebar0 = text_size.cy + 2; } else { GlideBar0[1].y = -Layout::Scale(9); clipping_arrow0[1].y = -clipping_arrow0[1].y; clipping_arrow0[2].y = -clipping_arrow0[2].y; clipping_arrow0[3].y = -clipping_arrow0[3].y; clipping_arrow0_offset = -clipping_arrow0_offset; dy_glidebar0 = -1; } for (unsigned i = 0; i < 6; i++) { GlideBar[i].y += y0 + dy_glidebar; GlideBar[i].x = Layout::Scale(GlideBar[i].x) + rc.left; } GlideBar[0].y -= Offset; GlideBar[1].y -= Offset; GlideBar[2].y -= Offset; for (unsigned i = 0; i < 4; i++) { GlideBar0[i].y += y0 + dy_glidebar0; GlideBar0[i].x = Layout::Scale(GlideBar0[i].x) + rc.left; } GlideBar0[0].y -= Offset0; GlideBar0[1].y -= Offset0; if ((altitude_difference0 >= altitude_difference) && (altitude_difference > 0)) { // both above and mc0 arrow larger than mc arrow GlideBar0[2].y = GlideBar[1].y; // both below GlideBar0[3].y = GlideBar[0].y; } // prepare clipping arrow for (unsigned i = 0; i < 6; i++) { clipping_arrow[i].y = Layout::Scale(clipping_arrow[i].y) + y0 - Offset + clipping_arrow_offset + dy_glidebar; clipping_arrow[i].x = Layout::Scale(clipping_arrow[i].x) + rc.left; } // prepare clipping arrow mc0 for (unsigned i = 0; i < 4; i++) { clipping_arrow0[i].y = Layout::Scale(clipping_arrow0[i].y) + y0 - Offset0 + clipping_arrow0_offset + dy_glidebar0; clipping_arrow0[i].x = Layout::Scale(clipping_arrow0[i].x) + rc.left; } // draw actual glide bar if (altitude_difference <= 0) { if (calculated.common_stats.landable_reachable) { canvas.Select(look.pen_below_landable); canvas.Select(look.brush_below_landable); } else { canvas.Select(look.pen_below); canvas.Select(look.brush_below); } } else { canvas.Select(look.pen_above); canvas.Select(look.brush_above); } canvas.DrawPolygon(GlideBar, 6); // draw clipping arrow if ((altitude_difference <= -468 ) || (altitude_difference >= 468)) canvas.DrawPolygon(clipping_arrow, 6); // draw glide bar at mc 0 if (altitude_difference0 <= 0 && final_glide_bar_mc0_enabled) { if (calculated.common_stats.landable_reachable) { canvas.Select(look.pen_below_landable); canvas.Select(look.brush_below_landable_mc0); } else { canvas.Select(look.pen_below); canvas.Select(look.brush_below_mc0); } } else { canvas.Select(look.pen_above); canvas.Select(look.brush_above_mc0); } if ( ( (altitude_difference != altitude_difference0) || (altitude_difference0 < 0) ) && final_glide_bar_mc0_enabled) { canvas.DrawPolygon(GlideBar0, 4); if ((altitude_difference0 <= -468 ) || (altitude_difference0 >= 468)) canvas.DrawPolygon(clipping_arrow0, 4); } // draw cross (x) on final glide bar if unreachable at current Mc // or above final glide but impeded by obstacle int cross_sign = 0; if (!total.IsAchievable()) cross_sign = 1; if (calculated.terrain_warning_location.IsValid() && altitude_difference > 0 ) cross_sign = -1; if (cross_sign != 0) { canvas.Select(task_look.bearing_pen); canvas.DrawLine(Layout::Scale(9 - 5), y0 + cross_sign * Layout::Scale(9 - 5), Layout::Scale(9 + 5), y0 + cross_sign * Layout::Scale(9 + 5)); canvas.DrawLine(Layout::Scale(9 - 5), y0 + cross_sign * Layout::Scale(9 + 5), Layout::Scale(9 + 5), y0 + cross_sign * Layout::Scale(9 - 5)); } canvas.SetTextColor(COLOR_BLACK); canvas.SetBackgroundColor(COLOR_WHITE); TextInBoxMode style; style.shape = LabelShape::ROUNDED_BLACK; style.move_in_view = true; if (text_size.cx < Layout::Scale(18)) { style.align = TextInBoxMode::Alignment::RIGHT; TextInBox(canvas, Value, Layout::Scale(18), y0, style, rc); } else TextInBox(canvas, Value, 0, y0, style, rc); }
void FinalGlideBarRenderer::Draw(Canvas &canvas, const PixelRect &rc, const DerivedInfo &calculated, const GlideSettings &glide_settings, const bool final_glide_bar_mc0_enabled) const { #ifdef ENABLE_OPENGL const GLEnable blend(GL_BLEND); #endif RasterPoint GlideBar[6] = { { 0, 0 }, { 9, -9 }, { 18, 0 }, { 18, 0 }, { 9, 0 }, { 0, 0 } }; RasterPoint GlideBar0[4] = { { 0, 0 }, { 9, -9 }, { 9, 0 }, { 0, 0 } }; RasterPoint clipping_arrow[6] = { { 0, 0 }, { 9, 9 }, { 18, 0 }, { 18, 6 }, { 9, 15 }, { 0, 6 } }; RasterPoint clipping_arrow0[4] = { { 0, 0 }, { 9, 9 }, { 9, 15 }, { 0, 6 } }; TCHAR Value[10]; const TaskStats &task_stats = calculated.task_stats; const ElementStat &total = task_stats.total; const GlideResult &solution = total.solution_remaining; const GlideResult &solution_mc0 = total.solution_mc0; if (!task_stats.task_valid || !solution.IsOk() || !solution_mc0.IsDefined()) return; const int y0 = (rc.bottom + rc.top) / 2; PixelScalar dy_glidebar = 0; PixelScalar dy_glidebar0 = 0; FormatUserAltitude(solution.SelectAltitudeDifference(glide_settings), Value, false); canvas.Select(*look.font); const PixelSize text_size = canvas.CalcTextSize(Value); PixelScalar clipping_arrow_offset = Layout::Scale(4); PixelScalar clipping_arrow0_offset = Layout::Scale(4); // 468 meters is it's size. Will be divided by 9 to fit screen resolution. int altitude_difference = (int) solution.SelectAltitudeDifference(glide_settings); int altitude_difference0 = (int) solution_mc0.SelectAltitudeDifference(glide_settings); // TODO feature: should be an angle if in final glide mode // cut altitude_difference at +- 468 meters (55 units) if (altitude_difference > 468) altitude_difference = 468; if (altitude_difference < -468) altitude_difference = -468; // 55 units is size, 468 meters div by 9 means 55. int Offset = altitude_difference / 9; Offset = Layout::Scale(Offset); if (altitude_difference <= 0) { GlideBar[1].y = Layout::Scale(9); dy_glidebar = text_size.cy + 2; } else { GlideBar[1].y = -Layout::Scale(9); clipping_arrow[1].y = -clipping_arrow[1].y; clipping_arrow[3].y = -clipping_arrow[3].y; clipping_arrow[4].y = -clipping_arrow[4].y; clipping_arrow[5].y = -clipping_arrow[5].y; clipping_arrow_offset = -clipping_arrow_offset; dy_glidebar = -1; } // cut altitude_difference0 at +- 468 meters (55 units) if (altitude_difference0 > 468) altitude_difference0 = 468; if (altitude_difference0 < -468) altitude_difference0 = -468; // 55 units is size, therefore div by 9. int Offset0 = altitude_difference0 / 9; Offset0 = Layout::Scale(Offset0); if (altitude_difference0 <= 0) { GlideBar0[1].y = Layout::Scale(9); dy_glidebar0 = text_size.cy + 2; } else { GlideBar0[1].y = -Layout::Scale(9); clipping_arrow0[1].y = -clipping_arrow0[1].y; clipping_arrow0[2].y = -clipping_arrow0[2].y; clipping_arrow0[3].y = -clipping_arrow0[3].y; clipping_arrow0_offset = -clipping_arrow0_offset; dy_glidebar0 = -1; } for (unsigned i = 0; i < 6; i++) { GlideBar[i].y += y0 + dy_glidebar; GlideBar[i].x = Layout::Scale(GlideBar[i].x) + rc.left; } GlideBar[0].y -= Offset; GlideBar[1].y -= Offset; GlideBar[2].y -= Offset; for (unsigned i = 0; i < 4; i++) { GlideBar0[i].y += y0 + dy_glidebar0; GlideBar0[i].x = Layout::Scale(GlideBar0[i].x) + rc.left; } GlideBar0[0].y -= Offset0; GlideBar0[1].y -= Offset0; if ((altitude_difference0 >= altitude_difference) && (altitude_difference > 0)) { // both above and mc0 arrow larger than mc arrow GlideBar0[2].y = GlideBar[1].y; // both below GlideBar0[3].y = GlideBar[0].y; } // prepare clipping arrow for (unsigned i = 0; i < 6; i++) { clipping_arrow[i].y = Layout::Scale(clipping_arrow[i].y) + y0 - Offset + clipping_arrow_offset + dy_glidebar; clipping_arrow[i].x = Layout::Scale(clipping_arrow[i].x) + rc.left; } // prepare clipping arrow mc0 for (unsigned i = 0; i < 4; i++) { clipping_arrow0[i].y = Layout::Scale(clipping_arrow0[i].y) + y0 - Offset0 + clipping_arrow0_offset + dy_glidebar0; clipping_arrow0[i].x = Layout::Scale(clipping_arrow0[i].x) + rc.left; } // draw actual glide bar if (altitude_difference <= 0) { if (calculated.common_stats.landable_reachable) { canvas.Select(look.pen_below_landable); canvas.Select(look.brush_below_landable); } else { canvas.Select(look.pen_below); canvas.Select(look.brush_below); } } else { canvas.Select(look.pen_above); canvas.Select(look.brush_above); } canvas.DrawPolygon(GlideBar, 6); // draw clipping arrow if ((altitude_difference <= -468 ) || (altitude_difference >= 468)) canvas.DrawPolygon(clipping_arrow, 6); // draw glide bar at mc 0 if (altitude_difference0 <= 0 && final_glide_bar_mc0_enabled) { if (calculated.common_stats.landable_reachable) { canvas.Select(look.pen_below_landable); canvas.Select(look.brush_below_landable_mc0); } else { canvas.Select(look.pen_below); canvas.Select(look.brush_below_mc0); } } else { canvas.Select(look.pen_above); canvas.Select(look.brush_above_mc0); } if ( ( (altitude_difference != altitude_difference0) || (altitude_difference0 < 0) ) && final_glide_bar_mc0_enabled) { canvas.DrawPolygon(GlideBar0, 4); if ((altitude_difference0 <= -468 ) || (altitude_difference0 >= 468)) canvas.DrawPolygon(clipping_arrow0, 4); } // draw cross (x) on final glide bar if unreachable at current Mc // or above final glide but impeded by obstacle int cross_sign = 0; if (!total.IsAchievable()) cross_sign = 1; if (calculated.terrain_warning && (altitude_difference>0)) cross_sign = -1; if (cross_sign != 0) { canvas.Select(task_look.bearing_pen); canvas.DrawLine(Layout::Scale(9 - 5), y0 + cross_sign * Layout::Scale(9 - 5), Layout::Scale(9 + 5), y0 + cross_sign * Layout::Scale(9 + 5)); canvas.DrawLine(Layout::Scale(9 - 5), y0 + cross_sign * Layout::Scale(9 + 5), Layout::Scale(9 + 5), y0 + cross_sign * Layout::Scale(9 - 5)); } canvas.SetTextColor(COLOR_BLACK); canvas.SetBackgroundColor(COLOR_WHITE); TextInBoxMode style; style.shape = LabelShape::ROUNDED_BLACK; style.move_in_view = true; if (text_size.cx < Layout::Scale(18)) { style.align = TextInBoxMode::Alignment::RIGHT; TextInBox(canvas, Value, Layout::Scale(18), y0, style, rc); } else TextInBox(canvas, Value, 0, y0, style, rc); }
void TrafficListWidget::OnPaintItem(Canvas &canvas, PixelRect rc, unsigned index) { assert(index < items.size()); Item &item = items[index]; assert(item.IsFlarm() #ifdef HAVE_SKYLINES_TRACKING_HANDLER || item.IsSkyLines() #endif ); item.AutoLoad(); const FlarmNetRecord *record = item.record; const TCHAR *callsign = item.callsign; const DialogLook &look = UIGlobals::GetDialogLook(); const Font &name_font = *look.list.font_bold; const Font &small_font = look.small_font; const unsigned text_padding = Layout::GetTextPadding(); const unsigned frame_padding = text_padding / 2; TCHAR tmp_id[10]; item.id.Format(tmp_id); canvas.Select(name_font); StaticString<256> tmp; if (item.IsFlarm()) { if (record != nullptr) tmp.Format(_T("%s - %s - %s"), callsign, record->registration.c_str(), tmp_id); else if (callsign != nullptr) tmp.Format(_T("%s - %s"), callsign, tmp_id); else tmp.Format(_T("%s"), tmp_id); #ifdef HAVE_SKYLINES_TRACKING_HANDLER } else if (item.IsSkyLines()) { if (!item.name.empty()) tmp = item.name.c_str(); else tmp.UnsafeFormat(_T("SkyLines %u"), item.skylines_id); #endif } else { tmp = _T("?"); } if (item.color != FlarmColor::NONE) { const TrafficLook &traffic_look = UIGlobals::GetLook().traffic; switch (item.color) { case FlarmColor::NONE: case FlarmColor::COUNT: gcc_unreachable(); case FlarmColor::GREEN: canvas.Select(traffic_look.team_pen_green); break; case FlarmColor::BLUE: canvas.Select(traffic_look.team_pen_blue); break; case FlarmColor::YELLOW: canvas.Select(traffic_look.team_pen_yellow); break; case FlarmColor::MAGENTA: canvas.Select(traffic_look.team_pen_magenta); break; } canvas.SelectHollowBrush(); const PixelSize size = canvas.CalcTextSize(tmp); canvas.Rectangle(rc.left + row_renderer.GetX() - frame_padding, rc.top + row_renderer.GetFirstY() - frame_padding, rc.left + row_renderer.GetX() + size.cx + frame_padding, rc.top + row_renderer.GetFirstY() + size.cy + frame_padding); } row_renderer.DrawFirstRow(canvas, rc, tmp); canvas.Select(small_font); /* draw bearing and distance on the right */ if (item.vector.IsValid()) { row_renderer.DrawRightFirstRow(canvas, rc, FormatUserDistanceSmart(item.vector.distance).c_str()); // Draw leg bearing rc.right = row_renderer.DrawRightSecondRow(canvas, rc, FormatBearing(item.vector.bearing).c_str()); } if (record != nullptr) { tmp.clear(); if (!record->pilot.empty()) tmp = record->pilot.c_str(); if (!record->plane_type.empty()) { if (!tmp.empty()) tmp.append(_T(" - ")); tmp.append(record->plane_type); } if (!record->airfield.empty()) { if (!tmp.empty()) tmp.append(_T(" - ")); tmp.append(record->airfield); } if (!tmp.empty()) row_renderer.DrawSecondRow(canvas, rc, tmp); #ifdef HAVE_SKYLINES_TRACKING_HANDLER } else if (item.IsSkyLines()) { if (CommonInterface::Basic().time_available) { tmp.UnsafeFormat(_("%u minutes ago"), SinceInMinutes(CommonInterface::Basic().time, item.time_of_day_ms)); } else tmp.clear(); if (!item.near_name.empty()) tmp.AppendFormat(_T(" near %s (%s)"), item.near_name.c_str(), FormatUserDistanceSmart(item.near_distance).c_str()); if (!tmp.empty()) tmp.append(_T("; ")); tmp.append(FormatUserAltitude(item.altitude)); if (!tmp.empty()) row_renderer.DrawSecondRow(canvas, rc, tmp); #endif } }