cabana: misc UI tweaks (#38782)

This commit is contained in:
Trey Moen
2026-09-05 14:13:15 -07:00
committed by GitHub
parent f9dacd0d6b
commit a989bc0b50
9 changed files with 40 additions and 40 deletions
+3 -3
View File
@@ -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 {
+1 -1
View File
@@ -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);
}
+16 -16
View File
@@ -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
+2 -1
View File
@@ -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.
+6 -6
View File
@@ -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);
+3 -3
View File
@@ -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);
}