mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-15 00:43:46 +08:00
cabana: improve theme contrast (#38965)
* cabana: centralize accessible theme and data colors * cabana: remove color contrast tests * cabana: simplify theme color helpers * cabana: soften inactive message rows in dark mode * cabana: retain original signal tooltip behavior
This commit is contained in:
@@ -475,7 +475,7 @@ void ChartView::showTip(double sec) {
|
||||
std::string name = s.sig->name;
|
||||
std::string min = s.min == std::numeric_limits<double>::max() ? "--" : utils::toString(s.min);
|
||||
std::string max = s.max == std::numeric_limits<double>::lowest() ? "--" : utils::toString(s.max);
|
||||
text_list.push_back({.has_marker = true, .marker = toImU32(s.color), .name = name, .value = value, .min = min, .max = max});
|
||||
text_list.push_back({.has_marker = true, .marker = toImU32(graphicColor(s.color)), .name = name, .value = value, .min = min, .max = max});
|
||||
}
|
||||
}
|
||||
if (x < 0) {
|
||||
@@ -620,9 +620,9 @@ void ChartView::drawLegend() {
|
||||
ImGui::PopID();
|
||||
|
||||
if (series_type_ == SeriesType::Scatter) {
|
||||
painter->AddCircleFilled(r.Min + ImVec2(marker_size / 2.0f, 2.0f + marker_size / 2.0f), marker_size / 2.0f, toImU32(s.color));
|
||||
painter->AddCircleFilled(r.Min + ImVec2(marker_size / 2.0f, 2.0f + marker_size / 2.0f), marker_size / 2.0f, toImU32(graphicColor(s.color)));
|
||||
} else {
|
||||
drawColorMarker(painter, r.Min, toImU32(s.color));
|
||||
drawColorMarker(painter, r.Min, toImU32(graphicColor(s.color)));
|
||||
}
|
||||
|
||||
float x = r.Min.x + marker_size + ImGui::GetStyle().ItemInnerSpacing.x;
|
||||
@@ -655,7 +655,7 @@ void ChartView::drawSeries() {
|
||||
|
||||
const std::string label = "##sig" + std::to_string(i);
|
||||
ImPlotSpec spec;
|
||||
spec.LineColor = toImVec4(s.color);
|
||||
spec.LineColor = toImVec4(graphicColor(s.color));
|
||||
spec.Stride = sizeof(ImPlotPoint);
|
||||
if (series_type_ == SeriesType::Scatter) {
|
||||
float radius = std::clamp(pixels_per_point / 2.0, 2.0, 8.0) / 2.0;
|
||||
@@ -682,7 +682,7 @@ void ChartView::drawSeries() {
|
||||
// show points when zoomed in enough
|
||||
if ((num_points == 1 || pixels_per_point > 20) && first != last) {
|
||||
ImPlotSpec dots;
|
||||
dots.LineColor = toImVec4(s.color);
|
||||
dots.LineColor = toImVec4(graphicColor(s.color));
|
||||
dots.Stride = sizeof(ImPlotPoint);
|
||||
dots.Marker = ImPlotMarker_Circle;
|
||||
dots.MarkerSize = 4;
|
||||
@@ -700,12 +700,12 @@ void ChartView::drawForeground() {
|
||||
for (auto &s : sigs_) {
|
||||
if (!isNull(s.track_pt) && s.visible) {
|
||||
ImVec2 pos(xPos(s.track_pt.x), yPos(s.track_pt.y));
|
||||
painter->AddCircleFilled(pos, 5.5f, toImU32(s.color.darker(125)));
|
||||
painter->AddCircleFilled(pos, 5.5f, toImU32(graphicColor(s.color)));
|
||||
track_line_x = std::max(track_line_x, pos.x);
|
||||
}
|
||||
}
|
||||
if (track_line_x > 0) {
|
||||
const ImU32 dark_gray = IM_COL32(0x80, 0x80, 0x80, 0xff);
|
||||
const ImU32 dark_gray = ImGui::GetColorU32(palette().text_disabled);
|
||||
for (float y = layout_.plot_area.Min.y; y < layout_.plot_area.Max.y; y += 8) {
|
||||
painter->AddLine(ImVec2(track_line_x, y), ImVec2(track_line_x, std::min(y + 4, layout_.plot_area.Max.y)), dark_gray, 1.0f);
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ void Sparkline::render(const CabanaColor &color, int range, ImVec2 sz, double wi
|
||||
}
|
||||
|
||||
size = sz;
|
||||
color_ = toImU32(sparklineColor(color));
|
||||
color_ = color;
|
||||
draw_individual_points_ = draw_individual_points;
|
||||
window_end_ = window_end;
|
||||
xscale_ = xscale;
|
||||
@@ -108,7 +108,8 @@ void Sparkline::render(const CabanaColor &color, int range, ImVec2 sz, double wi
|
||||
|
||||
void Sparkline::draw(ImDrawList *draw_list, ImVec2 pos, ImU32 color) const {
|
||||
if (render_points_.empty()) return;
|
||||
if (color == 0) color = color_;
|
||||
// Pick up theme changes while paused.
|
||||
if (color == 0) color = toImU32(sparklineColor(color_));
|
||||
|
||||
// update() only runs when a message of this id arrives, so a slow message would hold the sparkline
|
||||
// still for many frames and then move it in one step. scroll the rendered polyline by the time that
|
||||
|
||||
@@ -26,7 +26,7 @@ private:
|
||||
|
||||
std::vector<Point> points_;
|
||||
std::vector<ImVec2> render_points_;
|
||||
ImU32 color_ = 0;
|
||||
CabanaColor color_;
|
||||
double window_end_ = 0; // the time the polyline was built for, so draw() can scroll it on from there
|
||||
double xscale_ = 0;
|
||||
bool draw_individual_points_ = false;
|
||||
|
||||
@@ -181,7 +181,9 @@ void HelpOverlay::draw() {
|
||||
float x = min.x + 8.0f;
|
||||
for (const auto &r : line) {
|
||||
const float w = run_width(r);
|
||||
const ImU32 color = r.color ? r.color : ImGui::GetColorU32(ImGuiCol_Text);
|
||||
const auto background = fromImVec4(r.chip ? palette().button : palette().surface);
|
||||
const auto source = r.color ? fromImVec4(ImGui::ColorConvertU32ToFloat4(r.color)) : fromImVec4(palette().text);
|
||||
const ImU32 color = toImU32(contrastColor(source, background, r.swatch ? 3.0 : 4.5));
|
||||
if (r.swatch) {
|
||||
dl->AddRectFilled(ImVec2(x + 2, y + 3), ImVec2(x + font_size - 2, y + font_size - 1), color);
|
||||
} else {
|
||||
|
||||
@@ -12,30 +12,30 @@ namespace fs = std::filesystem;
|
||||
namespace {
|
||||
|
||||
constexpr Palette DARK_PALETTE = {
|
||||
.text = rgb(0xffffff), .text_disabled = rgb(0x7b7b7b), .text_selected = rgb(0xffffff),
|
||||
.text = rgb(0xffffff), .text_disabled = rgb(0xcccccc), .text_inactive = rgb(0xa4a4a4), .text_selected = rgb(0xffffff),
|
||||
.window = rgb(0x353535), .surface = rgb(0x2b2c2d),
|
||||
.frame = rgb(0x2b2c2d), .frame_hovered = rgb(0x363738), .frame_active = rgb(0x434445),
|
||||
.button = rgb(0x3f4041), .button_hovered = rgb(0x525354), .button_active = rgb(0x303132),
|
||||
.header = rgb(0x2d74d2), .header_hovered = rgb(0x323944), .header_active = rgb(0x2d74d2),
|
||||
.accent = rgb(0x2d74d2),
|
||||
.border = rgb(0x606060), .separator = rgb(0x353535), .scrollbar_grab = rgb(0x4c4e4f),
|
||||
.slider_track = rgb(0x7b7b7b),
|
||||
.header = rgb(0x2d74d2), .header_hovered = rgb(0x323944), .header_active = rgb(0x434445),
|
||||
.accent = rgb(0x90bfff),
|
||||
.border = rgb(0xaaaaaa), .separator = rgb(0x353535), .scrollbar_grab = rgb(0xaaaaaa),
|
||||
.slider_track = rgb(0xaaaaaa),
|
||||
.tab = rgb(0x2c2c2c), .tab_hovered = rgb(0x444647), .tab_selected = rgb(0x393a3b), .table_header = rgb(0x3f4041),
|
||||
.grid = rgb(0xdddddd, 50.0f / 255.0f), .badge = rgb(0x808080),
|
||||
.grid = rgb(0xdddddd, 50.0f / 255.0f), .badge = rgb(0x626262),
|
||||
.sparkline_saturation = 1.0f, .sparkline_value = 1.0f,
|
||||
};
|
||||
|
||||
constexpr Palette LIGHT_PALETTE = {
|
||||
.text = rgb(0x000000), .text_disabled = rgb(0xbebebe), .text_selected = rgb(0xffffff),
|
||||
.text = rgb(0x000000), .text_disabled = rgb(0x595959), .text_inactive = rgb(0x595959), .text_selected = rgb(0xffffff),
|
||||
.window = rgb(0xefefef), .surface = rgb(0xffffff),
|
||||
.frame = rgb(0xffffff), .frame_hovered = rgb(0xf5f9fc), .frame_active = rgb(0xe7f3fb),
|
||||
.button = rgb(0xefefef), .button_hovered = rgb(0xe7f3fb), .button_active = rgb(0xd4e7f4),
|
||||
.header = rgb(0x308cc6), .header_hovered = rgb(0xe7f3fb), .header_active = rgb(0x308cc6),
|
||||
.accent = rgb(0x308cc6),
|
||||
.border = rgb(0xb6b6b6), .separator = rgb(0xd0d0d0), .scrollbar_grab = rgb(0xb6b6b6),
|
||||
.slider_track = rgb(0xd0d0d0),
|
||||
.header = rgb(0x226a99), .header_hovered = rgb(0xe7f3fb), .header_active = rgb(0xd4e7f4),
|
||||
.accent = rgb(0x226a99),
|
||||
.border = rgb(0x747474), .separator = rgb(0xd0d0d0), .scrollbar_grab = rgb(0x747474),
|
||||
.slider_track = rgb(0x747474),
|
||||
.tab = rgb(0xe5e5e5), .tab_hovered = rgb(0xefefef), .tab_selected = rgb(0xffffff), .table_header = rgb(0xefefef),
|
||||
.grid = rgb(0x000000, 50.0f / 255.0f), .badge = rgb(0xa0a0a4),
|
||||
.grid = rgb(0x000000, 50.0f / 255.0f), .badge = rgb(0x626262),
|
||||
.sparkline_saturation = 2.0f, .sparkline_value = 0.7f,
|
||||
};
|
||||
|
||||
@@ -67,6 +67,36 @@ ImFont *addFont(const fs::path &path, float size) {
|
||||
return font;
|
||||
}
|
||||
|
||||
double linearChannel(double value) {
|
||||
value /= 255.0;
|
||||
return value <= 0.04045 ? value / 12.92 : std::pow((value + 0.055) / 1.055, 2.4);
|
||||
}
|
||||
|
||||
double luminance(const CabanaColor &color) {
|
||||
return 0.2126 * linearChannel(color.r) + 0.7152 * linearChannel(color.g) + 0.0722 * linearChannel(color.b);
|
||||
}
|
||||
|
||||
// Directed rounding preserves the luminance bound in 8-bit sRGB.
|
||||
CabanaColor boundLuminance(const CabanaColor &color, double bound, bool minimum) {
|
||||
const double current = luminance(color);
|
||||
if (minimum ? current >= bound : current <= bound) return color;
|
||||
auto channel = [&](uint8_t value) {
|
||||
double c = linearChannel(value);
|
||||
c = minimum ? c + (1.0 - c) * (bound - current) / (1.0 - current) : c * bound / current;
|
||||
const double srgb = c <= 0.0031308 ? 12.92 * c : 1.055 * std::pow(c, 1.0 / 2.4) - 0.055;
|
||||
const double scaled = std::clamp(srgb * 255.0, 0.0, 255.0);
|
||||
return static_cast<uint8_t>(minimum ? std::ceil(scaled) : std::floor(scaled));
|
||||
};
|
||||
return {channel(color.r), channel(color.g), channel(color.b), color.a};
|
||||
}
|
||||
|
||||
CabanaColor composite(const CabanaColor &color, const CabanaColor &base) {
|
||||
auto channel = [&](int foreground, int background) {
|
||||
return static_cast<uint8_t>(std::lround((foreground * color.a + background * (255 - color.a)) / 255.0));
|
||||
};
|
||||
return {channel(color.r, base.r), channel(color.g, base.g), channel(color.b, base.b)};
|
||||
}
|
||||
|
||||
ImVec4 alpha(ImVec4 c, float a) { return ImVec4(c.x, c.y, c.z, a); }
|
||||
|
||||
} // namespace
|
||||
@@ -123,7 +153,8 @@ void applyTheme(int theme) {
|
||||
c[ImGuiCol_FrameBgHovered] = p.frame_hovered;
|
||||
c[ImGuiCol_FrameBgActive] = p.frame_active;
|
||||
c[ImGuiCol_Button] = p.button;
|
||||
c[ImGuiCol_ButtonHovered] = c[ImGuiCol_SliderGrab] = p.button_hovered;
|
||||
c[ImGuiCol_ButtonHovered] = p.button_hovered;
|
||||
c[ImGuiCol_SliderGrab] = p.accent;
|
||||
c[ImGuiCol_ScrollbarGrab] = p.scrollbar_grab;
|
||||
c[ImGuiCol_ScrollbarGrabHovered] = p.text_disabled;
|
||||
c[ImGuiCol_ButtonActive] = p.button_active;
|
||||
@@ -157,10 +188,52 @@ void applyTheme(int theme) {
|
||||
|
||||
const Palette &palette() { return *g_palette; }
|
||||
|
||||
CabanaColor contrastColor(CabanaColor color, const CabanaColor &background, double target) {
|
||||
color.a = 255;
|
||||
const double value = luminance(color), base = luminance(background);
|
||||
if ((std::max(value, base) + 0.05) / (std::min(value, base) + 0.05) >= target) return color;
|
||||
const bool lighter = base < 0.179;
|
||||
const double bound = lighter ? target * (base + 0.05) - 0.05 : (base + 0.05) / target - 0.05;
|
||||
return boundLuminance(color, std::clamp(bound, 0.0, 1.0), lighter);
|
||||
}
|
||||
|
||||
CabanaColor byteColor(const CabanaColor &color) {
|
||||
const bool dark = palette().text.x > 0.5f;
|
||||
const auto [h, s, v] = color.hsv();
|
||||
auto fill = CabanaColor::fromHsv(h, std::min(s, 0.30f), 0.86f, color.alphaF());
|
||||
if (dark) fill = boundLuminance(fill, 0.16, false); // 5:1 with white text
|
||||
fill = composite(fill, fromImVec4(palette().surface));
|
||||
return dark ? fill : composite({255, 255, 255, 40}, fill);
|
||||
}
|
||||
|
||||
CabanaColor signalFill(const CabanaColor &color, bool defined) {
|
||||
const bool dark = palette().text.x > 0.5f;
|
||||
auto fill = composite(color, fromImVec4(palette().surface));
|
||||
fill = composite(dark ? CabanaColor(0, 0, 0, 115) : CabanaColor(255, 255, 255, defined ? 20 : 40), fill);
|
||||
return boundLuminance(fill, 0.18, !dark); // 4.5:1 with the theme's text
|
||||
}
|
||||
|
||||
CabanaColor signalHighlight(CabanaColor color) {
|
||||
color.a = 255;
|
||||
return boundLuminance(boundLuminance(color, 0.175, true), 0.18, false);
|
||||
}
|
||||
|
||||
CabanaColor signalOutline(CabanaColor color, bool hovered) {
|
||||
const bool dark = palette().text.x > 0.5f;
|
||||
if (dark && hovered) color = color.lighter(150);
|
||||
color.a = 255;
|
||||
// 3:1 against normal and highlighted fills, including neighboring signals.
|
||||
return dark ? boundLuminance(color, 0.67, true) : boundLuminance(color, 0.02, false);
|
||||
}
|
||||
|
||||
CabanaColor graphicColor(const CabanaColor &color, const ImVec4 &background) {
|
||||
return contrastColor(color, fromImVec4(background), 3.0);
|
||||
}
|
||||
|
||||
CabanaColor sparklineColor(const CabanaColor &color) {
|
||||
const Palette &p = palette();
|
||||
auto [h, s, v] = color.hsv();
|
||||
return CabanaColor::fromHsv(h, std::min(1.0f, s * p.sparkline_saturation), v * p.sparkline_value, color.a / 255.0f);
|
||||
return graphicColor(CabanaColor::fromHsv(h, std::min(1.0f, s * p.sparkline_saturation), v * p.sparkline_value));
|
||||
}
|
||||
|
||||
ImFont *boldFont() { return g_bold_font; }
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
#include "tools/cabana/core/color.h"
|
||||
|
||||
struct Palette {
|
||||
ImVec4 text, text_disabled, text_selected;
|
||||
ImVec4 text, text_disabled, text_inactive, text_selected;
|
||||
ImVec4 window; // the background behind panels and docked windows
|
||||
ImVec4 surface; // panels, popups, table bodies: what content is drawn on
|
||||
ImVec4 frame, frame_hovered, frame_active;
|
||||
ImVec4 button, button_hovered, button_active;
|
||||
ImVec4 header, header_hovered, header_active; // selections
|
||||
ImVec4 header, header_hovered, header_active; // selected fill; unselected hover/press fills
|
||||
ImVec4 accent;
|
||||
ImVec4 border, separator, scrollbar_grab;
|
||||
ImVec4 slider_track;
|
||||
@@ -28,6 +28,10 @@ inline ImVec4 colorRgb(int r, int g, int b, float alpha = 1.0f) {
|
||||
return ImVec4(r / 255.0f, g / 255.0f, b / 255.0f, alpha);
|
||||
}
|
||||
inline ImU32 toImU32(const CabanaColor &c) { return IM_COL32(c.r, c.g, c.b, c.a); }
|
||||
inline CabanaColor fromImVec4(const ImVec4 &c) {
|
||||
return {static_cast<uint8_t>(std::lround(c.x * 255)), static_cast<uint8_t>(std::lround(c.y * 255)),
|
||||
static_cast<uint8_t>(std::lround(c.z * 255)), static_cast<uint8_t>(std::lround(c.w * 255))};
|
||||
}
|
||||
inline ImVec4 toImVec4(const CabanaColor &c) { return ImVec4(c.r / 255.0f, c.g / 255.0f, c.b / 255.0f, c.a / 255.0f); }
|
||||
inline ImU32 withAlpha(ImU32 c, int alpha) { return (c & ~IM_COL32_A_MASK) | ((ImU32)alpha << IM_COL32_A_SHIFT); }
|
||||
|
||||
@@ -44,6 +48,12 @@ constexpr float UI_FONT_SIZE = 16.0f;
|
||||
void loadFonts();
|
||||
void applyTheme(int theme); // Safe to call at runtime.
|
||||
const Palette &palette();
|
||||
CabanaColor contrastColor(CabanaColor color, const CabanaColor &background, double target = 4.5);
|
||||
CabanaColor byteColor(const CabanaColor &color);
|
||||
CabanaColor signalFill(const CabanaColor &color, bool defined = true);
|
||||
CabanaColor signalHighlight(CabanaColor color);
|
||||
CabanaColor signalOutline(CabanaColor color, bool hovered = false);
|
||||
CabanaColor graphicColor(const CabanaColor &color, const ImVec4 &background = palette().surface);
|
||||
CabanaColor sparklineColor(const CabanaColor &color);
|
||||
|
||||
ImFont *boldFont();
|
||||
|
||||
@@ -94,9 +94,10 @@ bool selectable(const char *label, bool selected, ImGuiSelectableFlags flags, co
|
||||
if (selected) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, palette().text_selected);
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, palette().header);
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive, palette().header);
|
||||
}
|
||||
const bool clicked = ImGui::Selectable(label, selected, flags, size);
|
||||
if (selected) ImGui::PopStyleColor(2);
|
||||
if (selected) ImGui::PopStyleColor(3);
|
||||
return clicked;
|
||||
}
|
||||
|
||||
@@ -382,7 +383,7 @@ int tableHeadersRow() {
|
||||
|
||||
bool viewSelectable(const char *label, bool selected, ImGuiSelectableFlags flags, const ImVec2 &size) {
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, selected ? ImGui::GetColorU32(ImGuiCol_Header) : IM_COL32(0, 0, 0, 0));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImGui::GetColorU32(ImGuiCol_Header));
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive, selected ? palette().header : palette().header_active);
|
||||
const bool clicked = selectable(label, selected, flags, size);
|
||||
ImGui::PopStyleColor(2);
|
||||
return clicked;
|
||||
|
||||
@@ -22,10 +22,8 @@ const float SMALL_FONT_SIZE = 10.0f; // Inter needs 10 px for a 7 px cap height
|
||||
const int VERTICAL_HEADER_WIDTH = 30;
|
||||
inline int get_bit_pos(const BinaryIndex &index) { return flipBitPos(index.row * 8 + index.column); }
|
||||
|
||||
inline ImU32 paletteHighlight() { return ImGui::GetColorU32(ImGuiCol_Header); }
|
||||
inline ImU32 paletteBase() { return ImGui::GetColorU32(ImGuiCol_ChildBg); }
|
||||
inline ImU32 paletteText(bool active) { return ImGui::GetColorU32(active ? ImGuiCol_Text : ImGuiCol_TextDisabled); }
|
||||
const ImU32 DARK_GRAY = IM_COL32(128, 128, 128, 255);
|
||||
inline ImU32 paletteText() { return ImGui::GetColorU32(ImGuiCol_Text); }
|
||||
|
||||
// JetBrains Mono ships no bold variant, so emulate one by drawing the glyphs again a fraction of a
|
||||
// pixel to the right. Keeps the monospace advance, unlike switching to the proportional bold face.
|
||||
@@ -332,7 +330,7 @@ void BinaryView::draw() {
|
||||
for (int row = 0; row < rows; ++row) {
|
||||
const ImRect r(grid_pos_.x, grid_pos_.y + row * CELL_HEIGHT, grid_pos_.x + VERTICAL_HEADER_WIDTH, grid_pos_.y + (row + 1) * CELL_HEIGHT);
|
||||
painter->AddRectFilled(r.Min, r.Max, ImGui::GetColorU32(ImGuiCol_WindowBg)); // plain header background
|
||||
drawText(painter, r, std::to_string(row).c_str(), paletteText(true));
|
||||
drawText(painter, r, std::to_string(row).c_str(), paletteText());
|
||||
}
|
||||
for (int row = 0; row < rows; ++row) {
|
||||
for (int column = 0; column < COLUMN_COUNT; ++column) {
|
||||
@@ -457,7 +455,7 @@ void BinaryView::paintCell(ImDrawList *painter, const ImRect &rect, const Binary
|
||||
auto item = &cellAt(index);
|
||||
ImFont *font = ImGui::GetFont();
|
||||
float font_size = CELL_FONT_SIZE;
|
||||
ImU32 pen = paletteText(true);
|
||||
ImU32 pen = paletteText();
|
||||
|
||||
if (index.column == HEX_COLUMN) {
|
||||
if (item->valid) {
|
||||
@@ -465,31 +463,30 @@ void BinaryView::paintCell(ImDrawList *painter, const ImRect &rect, const Binary
|
||||
font = ImGui::GetFont();
|
||||
font_size = ImGui::GetFontSize();
|
||||
popMonoFont();
|
||||
painter->AddRectFilled(rect.Min, rect.Max, toImU32(item->bg_color));
|
||||
painter->AddRectFilled(rect.Min, rect.Max, toImU32(byteColor(item->bg_color)));
|
||||
}
|
||||
} else if (isSelected(index)) {
|
||||
painter->AddRectFilled(rect.Min, rect.Max, resize_sig_ ? toImU32(resize_sig_->color) : paletteHighlight());
|
||||
painter->AddRectFilled(rect.Min, rect.Max, toImU32(signalHighlight(resize_sig_ ? resize_sig_->color : fromImVec4(palette().header))));
|
||||
pen = IM_COL32_WHITE;
|
||||
} else if (!hasSelection() || std::find(item->sigs.begin(), item->sigs.end(), resize_sig_) == item->sigs.end()) { // not resizing
|
||||
if (item->sigs.size() > 0) {
|
||||
for (auto &s : item->sigs) {
|
||||
if (s == hovered_sig_) {
|
||||
painter->AddRectFilled(rect.Min, rect.Max, toImU32(s->color.darker(125))); // 4/5x brightness
|
||||
} else {
|
||||
drawSignalCell(painter, rect, index, s);
|
||||
}
|
||||
drawSignalCell(painter, rect, index, s);
|
||||
}
|
||||
} else if (item->valid) {
|
||||
if (item->bg_color.alpha() > 0) painter->AddRectFilled(rect.Min, rect.Max, toImU32(item->bg_color));
|
||||
if (item->bg_color.alpha() > 0) painter->AddRectFilled(rect.Min, rect.Max, toImU32(signalFill(item->bg_color, false)));
|
||||
}
|
||||
bool bright = std::find(item->sigs.begin(), item->sigs.end(), hovered_sig_) != item->sigs.end();
|
||||
pen = bright ? IM_COL32_WHITE : paletteText(is_message_active_);
|
||||
if (bright) painter->AddRectFilled(rect.Min, rect.Max, toImU32(signalHighlight(hovered_sig_->color)));
|
||||
pen = bright ? IM_COL32_WHITE : paletteText();
|
||||
}
|
||||
|
||||
const auto text = fromImVec4(ImGui::ColorConvertU32ToFloat4(pen));
|
||||
const ImU32 pattern = toImU32(contrastColor({128, 128, 128}, text));
|
||||
if (item->sigs.size() > 1) {
|
||||
fillDense7Pattern(painter, rect, DARK_GRAY);
|
||||
fillDense7Pattern(painter, rect, pattern);
|
||||
} else if (!item->valid) {
|
||||
fillBDiagPattern(painter, rect, DARK_GRAY);
|
||||
fillBDiagPattern(painter, rect, pattern);
|
||||
}
|
||||
if (item->valid) {
|
||||
if (index.column == HEX_COLUMN) {
|
||||
@@ -545,13 +542,13 @@ void BinaryView::drawSignalCell(ImDrawList *painter, const ImRect &rect, const B
|
||||
auto item = &cellAt(index);
|
||||
CabanaColor color = sig->color;
|
||||
color.a = item->bg_color.alpha();
|
||||
const ImU32 edge = toImU32(sig->color.darker(125));
|
||||
const ImU32 edge = toImU32(signalOutline(sig->color));
|
||||
|
||||
for (const ImRect &clip : region) {
|
||||
painter->PushClipRect(clip.Min, clip.Max, true);
|
||||
// mix the signal color with the background to fade it
|
||||
painter->AddRectFilled(rc.Min, rc.Max, paletteBase());
|
||||
painter->AddRectFilled(rc.Min, rc.Max, toImU32(color));
|
||||
painter->AddRectFilled(rc.Min, rc.Max, toImU32(signalFill(color)));
|
||||
|
||||
if (draw_left) painter->AddLine(ImVec2(rc.Min.x + 0.5f, rc.Min.y), ImVec2(rc.Min.x + 0.5f, rc.Max.y), edge, 1.0f);
|
||||
if (draw_right) painter->AddLine(ImVec2(rc.Max.x - 0.5f, rc.Min.y), ImVec2(rc.Max.x - 0.5f, rc.Max.y), edge, 1.0f);
|
||||
|
||||
@@ -397,7 +397,7 @@ void CenterWidget::drawWelcomeWidget() {
|
||||
ImGui::SetCursorPos(ImVec2(origin.x + (avail.x - size.x) * 0.5f, y));
|
||||
ImGui::TextUnformatted(text);
|
||||
};
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, colorRgb(169, 169, 169));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, palette().text_disabled);
|
||||
float y = origin.y + avail.y * 0.5f - 90.0f;
|
||||
pushLargeFont();
|
||||
centered("CABANA", y);
|
||||
|
||||
@@ -26,9 +26,9 @@ ImVec2 bytesCellSize(int n, bool multiple_lines) {
|
||||
ImU32 cellTextColor(bool selected, bool inactive) {
|
||||
if (selected) {
|
||||
const ImU32 text = ImGui::GetColorU32(palette().text_selected);
|
||||
return inactive ? withAlpha(text, 100) : text;
|
||||
return text;
|
||||
}
|
||||
return ImGui::GetColorU32(inactive ? ImGuiCol_TextDisabled : ImGuiCol_Text);
|
||||
return ImGui::GetColorU32(inactive ? palette().text_inactive : palette().text);
|
||||
}
|
||||
|
||||
void drawTextCell(ImDrawList *dl, const ImRect &rect, const std::string &text, bool selected, bool inactive, bool align_right) {
|
||||
@@ -48,14 +48,11 @@ void drawBytesCell(ImDrawList *dl, const ImRect &rect, const std::vector<uint8_t
|
||||
const ImVec2 min(rect.Min.x + column * byte_size.x, rect.Min.y + row * byte_size.y);
|
||||
const ImRect r(min, ImVec2(min.x + byte_size.x, min.y + byte_size.y));
|
||||
|
||||
// a colored unselected byte keeps text_pen, like the other cells of the row
|
||||
ImU32 pen = text_pen;
|
||||
if (colors && i < (int)colors->size() && (*colors)[i].alpha() > 0) {
|
||||
if (selected) {
|
||||
pen = ImGui::GetColorU32(ImGuiCol_Text);
|
||||
dl->AddRectFilled(r.Min, r.Max, ImGui::GetColorU32(ImGuiCol_WindowBg));
|
||||
}
|
||||
dl->AddRectFilled(r.Min, r.Max, toImU32((*colors)[i]));
|
||||
// Activity backgrounds use the theme's text, including stale values.
|
||||
pen = ImGui::GetColorU32(ImGuiCol_Text);
|
||||
dl->AddRectFilled(r.Min, r.Max, toImU32(byteColor((*colors)[i])));
|
||||
}
|
||||
drawText(dl, r, utils::hexByte(bytes[i]), pen, font, font_size);
|
||||
}
|
||||
|
||||
@@ -267,7 +267,7 @@ void SignalView::paintCell(ImDrawList *painter, const ImRect &option_rect, const
|
||||
if (item->type == SignalModel::Item::Sig) {
|
||||
// color label
|
||||
ImRect icon_rect(rect.Min.x, rect.Min.y, rect.Min.x + COLOR_LABEL_WIDTH, rect.Max.y);
|
||||
painter->AddRectFilled(icon_rect.Min, icon_rect.Max, toImU32(item->sig->color.darker(item->highlight ? 125 : 0)), ImGui::GetStyle().FrameRounding);
|
||||
painter->AddRectFilled(icon_rect.Min, icon_rect.Max, toImU32(item->highlight ? signalHighlight(item->sig->color) : contrastColor(item->sig->color, {0, 0, 0})), ImGui::GetStyle().FrameRounding);
|
||||
drawText(painter, icon_rect, std::to_string(item->row() + 1).c_str(), item->highlight ? IM_COL32_WHITE : IM_COL32_BLACK,
|
||||
nullptr, LABEL_FONT);
|
||||
|
||||
@@ -276,7 +276,7 @@ void SignalView::paintCell(ImDrawList *painter, const ImRect &option_rect, const
|
||||
if (item->sig->type != cabana::Signal::Type::Normal) {
|
||||
const std::string indicator = multiplexIndicator(item->sig);
|
||||
ImRect indicator_rect(rect.Min.x, rect.Min.y, rect.Min.x + ImGui::CalcTextSize(indicator.c_str()).x, rect.Max.y);
|
||||
painter->AddRectFilled(indicator_rect.Min, indicator_rect.Max, IM_COL32(160, 160, 164, 255), ImGui::GetStyle().FrameRounding);
|
||||
painter->AddRectFilled(indicator_rect.Min, indicator_rect.Max, ImGui::GetColorU32(palette().badge), ImGui::GetStyle().FrameRounding);
|
||||
drawElidedText(painter, indicator_rect, indicator, IM_COL32_WHITE, false);
|
||||
rect.Min.x = indicator_rect.Max.x + h_margin * 2;
|
||||
}
|
||||
|
||||
@@ -425,7 +425,7 @@ void Slider::paint(double thumbnail_time) {
|
||||
groove_rect.Min.y = std::floor(center_y - groove_height / 2);
|
||||
groove_rect.Max.y = groove_rect.Min.y + groove_height;
|
||||
|
||||
p->AddRectFilled(groove_rect.Min, groove_rect.Max, timeline_colors[(int)TimelineType::None], groove_height * 0.5f);
|
||||
p->AddRectFilled(groove_rect.Min, groove_rect.Max, toImU32(graphicColor(fromImVec4(ImGui::ColorConvertU32ToFloat4(timeline_colors[(int)TimelineType::None])), palette().window)), groove_height * 0.5f);
|
||||
|
||||
double min = minimum() / factor;
|
||||
double max = maximum() / factor;
|
||||
@@ -444,7 +444,7 @@ void Slider::paint(double thumbnail_time) {
|
||||
|
||||
if (auto replay = getReplay()) {
|
||||
for (const auto &entry : *replay->getTimeline()) {
|
||||
fillRange(entry.start_time, entry.end_time, timeline_colors[(int)entry.type]);
|
||||
fillRange(entry.start_time, entry.end_time, toImU32(graphicColor(fromImVec4(ImGui::ColorConvertU32ToFloat4(timeline_colors[(int)entry.type])), palette().window)));
|
||||
}
|
||||
|
||||
ImU32 empty_color = ImGui::GetColorU32(ImGuiCol_WindowBg, 160 / 255.0f);
|
||||
@@ -531,8 +531,9 @@ void StreamCameraView::draw(const ImVec2 &size, double thumbnail_time) {
|
||||
const char *text = "PAUSED";
|
||||
const ImVec2 text_size = font->CalcTextSizeA(POINT_16_FONT_SIZE, FLT_MAX, 0.0f, text);
|
||||
const ImVec2 center = rect().GetCenter();
|
||||
p->AddText(font, POINT_16_FONT_SIZE, ImVec2(center.x - text_size.x / 2, center.y - text_size.y / 2),
|
||||
IM_COL32(200, 200, 200, static_cast<int>(255 * 0.7f)), text);
|
||||
const ImVec2 pos(center.x - text_size.x / 2, center.y - text_size.y / 2);
|
||||
p->AddRectFilled(ImVec2(pos.x - 4, pos.y - 2), ImVec2(pos.x + text_size.x + 4, pos.y + text_size.y + 2), ImGui::GetColorU32(palette().badge), ImGui::GetStyle().FrameRounding);
|
||||
p->AddText(font, POINT_16_FONT_SIZE, pos, ImGui::GetColorU32(palette().text_selected), text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,13 +584,16 @@ void StreamCameraView::drawTime(ImDrawList *p, const ImRect &rect, double second
|
||||
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
|
||||
p->AddText(font, POINT_10_FONT_SIZE, ImVec2(rect.GetCenter().x - text_size.x / 2, rect.Max.y - THUMBNAIL_MARGIN - text_size.y),
|
||||
IM_COL32_WHITE, text);
|
||||
const ImVec2 pos(rect.GetCenter().x - text_size.x / 2, rect.Max.y - THUMBNAIL_MARGIN - text_size.y);
|
||||
p->AddRectFilled(ImVec2(pos.x - 4, pos.y - 2), ImVec2(pos.x + text_size.x + 4, pos.y + text_size.y + 2), ImGui::GetColorU32(palette().badge), ImGui::GetStyle().FrameRounding);
|
||||
p->AddText(font, POINT_10_FONT_SIZE, pos, ImGui::GetColorU32(palette().text_selected), text);
|
||||
}
|
||||
|
||||
void StreamCameraView::drawAlert(ImDrawList *p, const ImRect &rect, const Timeline::Entry &alert, float font_size, float rounding) {
|
||||
const ImU32 pen = IM_COL32_WHITE;
|
||||
ImU32 color = withAlpha(timeline_colors[int(alert.type)], 128);
|
||||
// Opaque backing keeps alert text readable over every camera frame.
|
||||
const auto source = fromImVec4(ImGui::ColorConvertU32ToFloat4(timeline_colors[int(alert.type)]));
|
||||
const ImU32 color = toImU32(contrastColor(source, fromImVec4(palette().text_selected)));
|
||||
std::string text = alert.text1;
|
||||
if (!alert.text2.empty()) text += "\n" + alert.text2;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user