mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-09-18 10:23:43 +08:00
cabana: misc UI tweaks (#38782)
This commit is contained in:
@@ -195,10 +195,10 @@ void test_format_seconds() {
|
||||
REQUIRE(utils::formatSeconds(0) == "00:00");
|
||||
REQUIRE(utils::formatSeconds(59.4) == "00:59");
|
||||
REQUIRE(utils::formatSeconds(-1) == "00:00");
|
||||
REQUIRE(utils::formatSeconds(61.234, true) == "01:01.234");
|
||||
REQUIRE(utils::formatSeconds(61.234, true) == "01:01.23");
|
||||
REQUIRE(utils::formatSeconds(3599.9) == "59:59");
|
||||
REQUIRE(utils::formatSeconds(3601) == "01:00:01");
|
||||
REQUIRE(utils::formatSeconds(3601.5, true) == "01:00:01.500");
|
||||
REQUIRE(utils::formatSeconds(3601.5, true) == "01:00:01.50");
|
||||
|
||||
const char *tz = getenv("TZ");
|
||||
const bool had_tz = tz != nullptr;
|
||||
@@ -206,7 +206,7 @@ void test_format_seconds() {
|
||||
setenv("TZ", "UTC", 1);
|
||||
tzset();
|
||||
REQUIRE(utils::formatSeconds(0, false, true) == "1970-01-01 00:00:00");
|
||||
REQUIRE(utils::formatSeconds(1700000000.123, true, true) == "2023-11-14 22:13:20.123");
|
||||
REQUIRE(utils::formatSeconds(1700000000.123, true, true) == "2023-11-14 22:13:20.12");
|
||||
if (had_tz) {
|
||||
setenv("TZ", saved_tz.c_str(), 1);
|
||||
} else {
|
||||
|
||||
@@ -488,7 +488,7 @@ void ChartView::showTip(double sec) {
|
||||
x = tooltip_x_;
|
||||
}
|
||||
ImVec2 pt(x, layout_.plot_area.Min.y);
|
||||
text_list.insert(text_list.begin(), TipLine{.name = formatNumber(secondsAtPoint({x, 0}), 3)});
|
||||
text_list.insert(text_list.begin(), TipLine{.name = formatNumber(secondsAtPoint({x, 0}), 2)});
|
||||
tip_label_.showText(pt, text_list, visible_rect);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,37 +4,37 @@
|
||||
namespace icon {
|
||||
constexpr const char ARROW_CLOCKWISE[] = "\xef\x84\x96";
|
||||
constexpr const char ARROW_COUNTERCLOCKWISE[] = "\xef\x84\x97";
|
||||
constexpr const char ARROW_DOWN_LEFT_SQUARE[] = "\xef\x84\x9d";
|
||||
constexpr const char ARROW_UP_RIGHT_SQUARE[] = "\xef\x85\x83";
|
||||
constexpr const char ARROW_DOWN_LEFT_SQUARE[] = "\xef\x84\x9c";
|
||||
constexpr const char ARROW_UP_RIGHT_SQUARE[] = "\xef\x85\x82";
|
||||
constexpr const char CHEVRON_LEFT[] = "\xef\x8a\x84";
|
||||
constexpr const char CHEVRON_RIGHT[] = "\xef\x8a\x85";
|
||||
constexpr const char DASH[] = "\xef\x8b\xaa";
|
||||
constexpr const char DASH_SQUARE[] = "\xef\x8b\xa9";
|
||||
constexpr const char EXCLAMATION_TRIANGLE[] = "\xef\x8c\xbb";
|
||||
constexpr const char FAST_FORWARD[] = "\xef\x9f\xb4";
|
||||
constexpr const char DASH_SQUARE[] = "\xef\x8b\xa8";
|
||||
constexpr const char EXCLAMATION_TRIANGLE[] = "\xef\x8c\xba";
|
||||
constexpr const char FAST_FORWARD[] = "\xef\x9f\xb3";
|
||||
constexpr const char FILETYPE_CSV[] = "\xef\x9d\x83";
|
||||
constexpr const char FOLDER[] = "\xef\x8f\x99";
|
||||
constexpr const char FILE_EARMARK[] = "\xef\x8e\x92";
|
||||
constexpr const char FILE_EARMARK_RULED[] = "\xef\x8e\x85";
|
||||
constexpr const char PLUS_SQUARE[] = "\xef\x93\xbd";
|
||||
constexpr const char FOLDER[] = "\xef\x8f\x91";
|
||||
constexpr const char FILE_EARMARK[] = "\xef\x8d\xa9";
|
||||
constexpr const char FILE_EARMARK_RULED[] = "\xef\x8e\x84";
|
||||
constexpr const char PLUS_SQUARE[] = "\xef\x93\xbc";
|
||||
constexpr const char GRAPH_UP[] = "\xef\x8f\xb2";
|
||||
constexpr const char GRIP_HORIZONTAL[] = "\xef\x8f\xbd";
|
||||
constexpr const char INFO_CIRCLE[] = "\xef\x90\xb1";
|
||||
constexpr const char INFO_CIRCLE[] = "\xef\x90\xb0";
|
||||
constexpr const char LIST[] = "\xef\x91\xb9";
|
||||
constexpr const char PAUSE[] = "\xef\x93\x84";
|
||||
constexpr const char PAUSE[] = "\xef\x93\x83";
|
||||
constexpr const char PENCIL[] = "\xef\x93\x8b";
|
||||
constexpr const char PLAY[] = "\xef\x93\xb5";
|
||||
constexpr const char PLAY[] = "\xef\x93\xb4";
|
||||
constexpr const char PLUS[] = "\xef\x93\xbe";
|
||||
constexpr const char RAQUO[] = "\xc2\xbb"; // U+00BB, not a bootstrap icon: the toolbar extension button
|
||||
constexpr const char REPEAT[] = "\xef\xa0\x93";
|
||||
constexpr const char REPEAT_1[] = "\xef\xa0\x92";
|
||||
constexpr const char REWIND[] = "\xef\xa0\x99";
|
||||
constexpr const char SKIP_END[] = "\xef\x95\x98";
|
||||
constexpr const char STOPWATCH[] = "\xef\x96\x97";
|
||||
constexpr const char REWIND[] = "\xef\xa0\x98";
|
||||
constexpr const char SKIP_END[] = "\xef\x95\x97";
|
||||
constexpr const char STOPWATCH[] = "\xef\x96\x96";
|
||||
constexpr const char THREE_DOTS[] = "\xef\x97\x94";
|
||||
constexpr const char WINDOW_STACK[] = "\xef\x9b\x92";
|
||||
constexpr const char X[] = "\xef\x98\xaa";
|
||||
constexpr const char X_LG[] = "\xef\x99\x99";
|
||||
constexpr const char X_SQUARE[] = "\xef\x98\xa9";
|
||||
constexpr const char X_SQUARE[] = "\xef\x98\xa8";
|
||||
constexpr const char ZOOM_OUT[] = "\xef\x98\xad";
|
||||
} // namespace icon
|
||||
|
||||
@@ -835,7 +835,8 @@ void MainWindow::drawVideoPanel() {
|
||||
const bool live = can->liveStreaming();
|
||||
// the bordered child pads its content, so the heights the widget asks for grow by the padding
|
||||
const float video_padding = ImGui::GetStyle().WindowPadding.y * 2.0f;
|
||||
const float default_h = video_widget_->defaultHeight(avail.x) + video_padding;
|
||||
// the camera is as wide as the child's content region, not the panel
|
||||
const float default_h = video_widget_->defaultHeight(avail.x - ImGui::GetStyle().WindowPadding.x * 2.0f) + video_padding;
|
||||
const float video_hint = video_splitter_ratio_ >= 0.0f ? avail.y * video_splitter_ratio_ : default_h;
|
||||
float video_h = charts_floating_ ? avail.y : std::clamp(video_hint, 0.0f, avail.y - 1.0f);
|
||||
if (live) video_h = default_h; // display video at minimum size.
|
||||
|
||||
@@ -100,9 +100,9 @@ void applyTheme(int theme) {
|
||||
colors[ImGuiCol_FrameBg] = c(DarkTheme::base);
|
||||
colors[ImGuiCol_FrameBgHovered] = colorRgb(0x1f, 0x1f, 0x1f);
|
||||
colors[ImGuiCol_FrameBgActive] = colorRgb(0x24, 0x24, 0x24);
|
||||
colors[ImGuiCol_Button] = colorRgb(0x3a, 0x3a, 0x3a);
|
||||
colors[ImGuiCol_ButtonHovered] = colorRgb(0x42, 0x42, 0x42);
|
||||
colors[ImGuiCol_ButtonActive] = colorRgb(0x30, 0x30, 0x30);
|
||||
colors[ImGuiCol_Button] = colorRgb(0x5e, 0x5e, 0x5e);
|
||||
colors[ImGuiCol_ButtonHovered] = colorRgb(0x6a, 0x6a, 0x6a);
|
||||
colors[ImGuiCol_ButtonActive] = colorRgb(0x52, 0x52, 0x52);
|
||||
colors[ImGuiCol_Header] = highlight;
|
||||
colors[ImGuiCol_HeaderHovered] = c(DarkTheme::highlight, 0.8f);
|
||||
colors[ImGuiCol_HeaderActive] = highlight;
|
||||
@@ -157,9 +157,9 @@ void applyTheme(int theme) {
|
||||
colors[ImGuiCol_FrameBg] = base;
|
||||
colors[ImGuiCol_FrameBgHovered] = colorRgb(0xf7, 0xf7, 0xf7);
|
||||
colors[ImGuiCol_FrameBgActive] = colorRgb(0xef, 0xef, 0xef);
|
||||
colors[ImGuiCol_Button] = colorRgb(0xf5, 0xf5, 0xf5);
|
||||
colors[ImGuiCol_ButtonHovered] = colorRgb(0xfa, 0xfa, 0xfa);
|
||||
colors[ImGuiCol_ButtonActive] = colorRgb(0xd9, 0xd9, 0xd9);
|
||||
colors[ImGuiCol_Button] = colorRgb(0xe4, 0xe4, 0xe4);
|
||||
colors[ImGuiCol_ButtonHovered] = colorRgb(0xec, 0xec, 0xec);
|
||||
colors[ImGuiCol_ButtonActive] = colorRgb(0xd0, 0xd0, 0xd0);
|
||||
colors[ImGuiCol_Header] = highlight;
|
||||
colors[ImGuiCol_HeaderHovered] = colorRgb(0x30, 0x8c, 0xc6, 0.8f);
|
||||
colors[ImGuiCol_HeaderActive] = highlight;
|
||||
|
||||
@@ -22,7 +22,7 @@ constexpr float COMPARE_WIDTH = 50.0f;
|
||||
|
||||
std::string formatTime(uint64_t mono_time) {
|
||||
char buf[32] = {};
|
||||
snprintf(buf, sizeof(buf), "%.3f", can->toSeconds(mono_time));
|
||||
snprintf(buf, sizeof(buf), "%.2f", can->toSeconds(mono_time));
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ std::string LogsWidget::headerText(int column) const {
|
||||
}
|
||||
|
||||
ImVec2 LogsWidget::headerSize(int column, float viewport_width) const {
|
||||
const ImVec2 time_text_size = ImGui::CalcTextSize("000000.000");
|
||||
const ImVec2 time_text_size = ImGui::CalcTextSize("000000.00");
|
||||
const ImVec2 time_col_size(time_text_size.x + 10, time_text_size.y + 6);
|
||||
if (column == 0) return time_col_size;
|
||||
const int default_size = std::max(100, (int)((viewport_width - time_col_size.x) / (columnCount() - 1)));
|
||||
|
||||
@@ -534,20 +534,19 @@ void StreamCameraView::draw(const ImVec2 &size, double thumbnail_time) {
|
||||
}
|
||||
}
|
||||
|
||||
const RgbImage *StreamCameraView::thumbnailAt(double sec, uint64_t *mono_time) {
|
||||
const RgbImage *StreamCameraView::thumbnailAt(double sec) {
|
||||
auto it = big_thumbnails_.lower_bound(can->toMonoTime(sec));
|
||||
if (it == big_thumbnails_.end()) return nullptr;
|
||||
if (big_thumbnail_texture_.id == 0 || big_thumbnail_texture_.key != it->first) {
|
||||
big_thumbnail_texture_.upload(it->second);
|
||||
big_thumbnail_texture_.key = it->first;
|
||||
}
|
||||
if (mono_time) *mono_time = it->first;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
void StreamCameraView::drawScrubThumbnail(ImDrawList *p, double sec) {
|
||||
p->AddRectFilled(rect().Min, rect().Max, IM_COL32(0, 0, 0, 255));
|
||||
if (const RgbImage *image = thumbnailAt(sec, nullptr)) {
|
||||
if (const RgbImage *image = thumbnailAt(sec)) {
|
||||
// scale to the widget size, keeping the aspect ratio
|
||||
const float scale = std::min(width() / image->width, height() / image->height);
|
||||
const ImVec2 scaled_size(std::floor(image->width * scale), std::floor(image->height * scale));
|
||||
@@ -560,8 +559,7 @@ void StreamCameraView::drawScrubThumbnail(ImDrawList *p, double sec) {
|
||||
}
|
||||
|
||||
void StreamCameraView::drawThumbnail(ImDrawList *p, double sec) {
|
||||
uint64_t mono_time = 0;
|
||||
if (const RgbImage *image = thumbnailAt(sec, &mono_time)) {
|
||||
if (const RgbImage *image = thumbnailAt(sec)) {
|
||||
// AddImage scales the stored image to the thumbnail height, keeping the aspect ratio
|
||||
const int h = MIN_VIDEO_HEIGHT - THUMBNAIL_MARGIN * 2;
|
||||
const int w = std::max(1, (int)std::lround((double)image->width * h / image->height));
|
||||
@@ -574,7 +572,8 @@ void StreamCameraView::drawThumbnail(ImDrawList *p, double sec) {
|
||||
ImRect thumb_rect(ImVec2(rect().Min.x + x, rect().Min.y + y), ImVec2(rect().Min.x + x + w, rect().Min.y + y + h));
|
||||
p->AddImage(big_thumbnail_texture_.ref(), thumb_rect.Min, thumb_rect.Max);
|
||||
p->AddRect(thumb_rect.Min, thumb_rect.Max, paletteBrightText(), 0.0f, 0, 2.0f);
|
||||
if (auto alert = getReplay()->findAlertAtTime(can->toSeconds(mono_time))) {
|
||||
// look up the alert at the hovered time, the thumbnail frame itself can be seconds away
|
||||
if (auto alert = getReplay()->findAlertAtTime(sec)) {
|
||||
drawAlert(p, thumb_rect, *alert, POINT_10_FONT_SIZE);
|
||||
}
|
||||
drawTime(p, thumb_rect, sec);
|
||||
@@ -583,7 +582,7 @@ void StreamCameraView::drawThumbnail(ImDrawList *p, double sec) {
|
||||
|
||||
void StreamCameraView::drawTime(ImDrawList *p, const ImRect &rect, double seconds) {
|
||||
char text[32];
|
||||
snprintf(text, sizeof(text), "%.3f", seconds);
|
||||
snprintf(text, sizeof(text), "%.2f", seconds);
|
||||
ImFont *font = ImGui::GetFont();
|
||||
const ImVec2 text_size = font->CalcTextSizeA(POINT_10_FONT_SIZE, FLT_MAX, 0.0f, text);
|
||||
// centered horizontally, above the bottom margin
|
||||
|
||||
@@ -69,7 +69,7 @@ private:
|
||||
};
|
||||
void collectThumbnails(); // moves the decoded thumbnails in once a parseQLog task is done
|
||||
// the first thumbnail at or after sec, uploaded to big_thumbnail_texture_; nullptr when there is none
|
||||
const RgbImage *thumbnailAt(double sec, uint64_t *mono_time);
|
||||
const RgbImage *thumbnailAt(double sec);
|
||||
void drawAlert(ImDrawList *p, const ImRect &rect, const Timeline::Entry &alert, float font_size);
|
||||
void drawThumbnail(ImDrawList *p, double sec);
|
||||
void drawScrubThumbnail(ImDrawList *p, double sec);
|
||||
|
||||
@@ -21,7 +21,7 @@ std::string formatSeconds(double sec, bool include_milliseconds, bool absolute_t
|
||||
char buf[64] = {};
|
||||
std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
|
||||
if (!include_milliseconds) return buf;
|
||||
snprintf(out, sizeof(out), "%s.%03d", buf, millis);
|
||||
snprintf(out, sizeof(out), "%s.%02d", buf, millis / 10);
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -33,11 +33,11 @@ std::string formatSeconds(double sec, bool include_milliseconds, bool absolute_t
|
||||
const int seconds = (total_ms / 1000) % 60;
|
||||
const int millis = total_ms % 1000;
|
||||
if (show_hours && include_milliseconds) {
|
||||
snprintf(out, sizeof(out), "%02d:%02d:%02d.%03d", hours, minutes, seconds, millis);
|
||||
snprintf(out, sizeof(out), "%02d:%02d:%02d.%02d", hours, minutes, seconds, millis / 10);
|
||||
} else if (show_hours) {
|
||||
snprintf(out, sizeof(out), "%02d:%02d:%02d", hours, minutes, seconds);
|
||||
} else if (include_milliseconds) {
|
||||
snprintf(out, sizeof(out), "%02d:%02d.%03d", minutes, seconds, millis);
|
||||
snprintf(out, sizeof(out), "%02d:%02d.%02d", minutes, seconds, millis / 10);
|
||||
} else {
|
||||
snprintf(out, sizeof(out), "%02d:%02d", minutes, seconds);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user