#include "tools/jotpluggler/common.h" #include #include #include namespace { std::string format_coord(const GpsPoint &point) { return util::string_format("%.5f,%.5f", point.lat, point.lon); } } // namespace const CameraViewSpec &camera_view_spec(CameraViewKind view) { auto it = std::find_if(kCameraViewSpecs.begin(), kCameraViewSpecs.end(), [&](const CameraViewSpec &spec) { return spec.view == view; }); return it != kCameraViewSpecs.end() ? *it : kCameraViewSpecs.front(); } const CameraViewSpec *camera_view_spec_from_special_item(std::string_view item_id) { auto it = std::find_if(kCameraViewSpecs.begin(), kCameraViewSpecs.end(), [&](const CameraViewSpec &spec) { return item_id == spec.special_item_id; }); return it != kCameraViewSpecs.end() ? &*it : nullptr; } const CameraViewSpec *camera_view_spec_from_layout_name(std::string_view layout_name) { auto it = std::find_if(kCameraViewSpecs.begin(), kCameraViewSpecs.end(), [&](const CameraViewSpec &spec) { return layout_name == spec.layout_name; }); return it != kCameraViewSpecs.end() ? &*it : nullptr; } const SpecialItemSpec *special_item_spec(std::string_view item_id) { auto it = std::find_if(kSpecialItemSpecs.begin(), kSpecialItemSpecs.end(), [&](const SpecialItemSpec &spec) { return item_id == spec.id; }); return it != kSpecialItemSpecs.end() ? &*it : nullptr; } const char *special_item_label(std::string_view item_id) { const SpecialItemSpec *spec = special_item_spec(item_id); return spec != nullptr ? spec->label : "Item"; } bool pane_kind_is_special(PaneKind kind) { return kind == PaneKind::Map || kind == PaneKind::Camera; } bool is_default_special_title(std::string_view title) { if (title == "Map") return true; return std::any_of(kCameraViewSpecs.begin(), kCameraViewSpecs.end(), [&](const CameraViewSpec &spec) { return title == spec.label; }); } CameraViewKind sidebar_preview_camera_view(const AppSession &session) { return session.route_data.road_camera.entries.empty() && !session.route_data.qroad_camera.entries.empty() ? CameraViewKind::QRoad : CameraViewKind::Road; } const std::filesystem::path &repo_root() { static const std::filesystem::path root(JOTP_REPO_ROOT); return root; } ImU32 timeline_entry_color(TimelineEntry::Type type, float alpha) { return timeline_entry_color(type, alpha, {111, 143, 175}); } ImU32 timeline_entry_color(TimelineEntry::Type type, float alpha, std::array none_color) { switch (type) { case TimelineEntry::Type::Engaged: return ImGui::GetColorU32(color_rgb(0, 163, 108, alpha)); case TimelineEntry::Type::AlertInfo: return ImGui::GetColorU32(color_rgb(255, 195, 0, alpha)); case TimelineEntry::Type::AlertWarning: case TimelineEntry::Type::AlertCritical: return ImGui::GetColorU32(color_rgb(199, 0, 57, alpha)); case TimelineEntry::Type::None: default: return ImGui::GetColorU32(color_rgb(none_color, alpha)); } } const char *timeline_entry_label(TimelineEntry::Type type) { static constexpr const char *kLabels[] = { "disengaged", "engaged", "alert info", "alert warning", "alert critical", }; const size_t index = static_cast(type); return index < std::size(kLabels) ? kLabels[index] : kLabels[0]; } TimelineEntry::Type timeline_type_at_time(const std::vector &timeline, double time_value) { for (const TimelineEntry &entry : timeline) { if (time_value >= entry.start_time && time_value <= entry.end_time) { return entry.type; } } return TimelineEntry::Type::None; } std::string normalize_stream_address(std::string address) { return is_local_stream_address(address) ? "127.0.0.1" : address; } const char *stream_source_kind_label(StreamSourceKind kind) { static constexpr const char *kLabels[] = { "Local (MSGQ)", "Remote (ZMQ)", }; const size_t index = static_cast(kind); return index < std::size(kLabels) ? kLabels[index] : kLabels[0]; } std::string stream_source_target_label(const StreamSourceConfig &source) { switch (source.kind) { case StreamSourceKind::CerealRemote: return normalize_stream_address(source.address); case StreamSourceKind::CerealLocal: default: return "127.0.0.1"; } } bool env_flag_enabled(const char *name, bool default_value) { const char *raw = std::getenv(name); if (raw == nullptr || raw[0] == '\0') { return default_value; } const std::string value = lowercase_copy(util::strip(raw)); return !(value == "0" || value == "false" || value == "no" || value == "off"); } bool app_begin_popup(const char *str_id, ImGuiWindowFlags flags) { return ImGui::BeginPopup(str_id, flags | ImGuiWindowFlags_NoMove); } bool app_begin_popup_modal(const char *name, bool *p_open, ImGuiWindowFlags flags) { return ImGui::BeginPopupModal(name, p_open, flags | ImGuiWindowFlags_NoMove); } void open_external_url(std::string_view url) { #ifdef __APPLE__ const std::string command = "open " + shell_quote(url) + " &"; #else const std::string command = "xdg-open " + shell_quote(url) + " >/dev/null 2>&1 &"; #endif util::check_system(command); } std::string route_useradmin_url(const RouteIdentifier &route_id) { return route_id.empty() ? std::string() : "https://useradmin.comma.ai/?onebox=" + route_id.dongle_id + "%7C" + route_id.log_id; } std::string route_connect_url(const RouteIdentifier &route_id) { return route_id.empty() ? std::string() : "https://connect.comma.ai/" + route_id.canonical(); } std::string route_google_maps_url(const GpsTrace &trace) { if (trace.points.size() < 2) { return {}; } const std::string prefix = "https://www.google.com/maps/dir/?api=1&travelmode=driving&origin=" + format_coord(trace.points.front()) + "&destination=" + format_coord(trace.points.back()); for (size_t n = std::min(9, trace.points.size() > 2 ? trace.points.size() - 2 : 0); ; --n) { std::string url = prefix; if (n > 0) { url += "&waypoints="; for (size_t i = 0; i < n; ++i) { if (i) url += "%7C"; url += format_coord(trace.points[1 + ((trace.points.size() - 2) * (i + 1)) / (n + 1)]); } } if (url.size() <= 1900 || n == 0) return url; } }