diff --git a/CMakeLists.txt b/CMakeLists.txt index 38a1c1f..5abbdd1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,21 +100,21 @@ set(TOUCHSENSOR_HEADERS qt6_add_resources(APP_RESOURCES resources.qrc) -# add_executable(${PROJECT_NAME} WIN32 -# ${COMPONENT_SOURCES} -# ${UTILITY_SOURCES} -# ${TOUCHSENSOR_HEADERS} -# ${BASE_SOURCES} -# main.cc -# ) + add_executable(${PROJECT_NAME} WIN32 + ${COMPONENT_SOURCES} + ${UTILITY_SOURCES} + ${TOUCHSENSOR_HEADERS} + ${BASE_SOURCES} + main.cc + ) -add_executable(${PROJECT_NAME} - ${COMPONENT_SOURCES} - ${UTILITY_SOURCES} - ${TOUCHSENSOR_HEADERS} - ${BASE_SOURCES} - main.cc -) +#add_executable(${PROJECT_NAME} +# ${COMPONENT_SOURCES} +# ${UTILITY_SOURCES} +# ${TOUCHSENSOR_HEADERS} +# ${BASE_SOURCES} +# main.cc +#) target_sources(${PROJECT_NAME} PRIVATE ${APP_RESOURCES}) target_include_directories(${PROJECT_NAME} PRIVATE diff --git a/component.hh b/component.hh index 5c6de9b..fbfd2c8 100644 --- a/component.hh +++ b/component.hh @@ -1,31 +1,37 @@ -#pragma once - -#include -#include -#include - -template -using raw_pointer = T*; - -struct NavComponentState { - creeper::ThemeManager& manager; - std::function switch_callback; - std::vector> buttons_context; - std::function stacked_callback; -}; - -auto NavComponent(NavComponentState&) noexcept -> raw_pointer; - -struct ViewComponentState { - creeper::ThemeManager& manager; -}; -auto ViewComponent(ViewComponentState&) noexcept -> raw_pointer; - -struct SettingComponentState { - creeper::ThemeManager& manager; -}; -auto SettingComponent(SettingComponentState&) noexcept -> raw_pointer; - +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +template +using raw_pointer = T*; + +struct NavComponentState { + creeper::ThemeManager& manager; + std::function switch_callback; + std::vector> buttons_context; + std::function stacked_callback; + std::shared_ptr> heatmap_show_numbers; +}; + +auto NavComponent(NavComponentState&) noexcept -> raw_pointer; + +struct ViewComponentState { + creeper::ThemeManager& manager; +}; +auto ViewComponent(ViewComponentState&) noexcept -> raw_pointer; + +struct SettingComponentState { + creeper::ThemeManager& manager; +}; +auto SettingComponent(SettingComponentState&) noexcept -> raw_pointer; + struct HandViewComponentState { creeper::ThemeManager& manager; }; @@ -33,3 +39,4 @@ auto HandViewComponent(HandViewComponentState&) noexcept -> raw_pointer // 让其他模块可触发视图层的串口/配置刷新 void RefreshProfilesForView(); +std::shared_ptr> HeatmapNumberVisibilityContext(); diff --git a/components/charts/heatmap.cc b/components/charts/heatmap.cc index edabc30..474916a 100644 --- a/components/charts/heatmap.cc +++ b/components/charts/heatmap.cc @@ -52,6 +52,14 @@ void BasicPlot::set_data(const QVector& data)const { pimpl->set_data(data); } +void BasicPlot::set_labels_visible(bool visible) const { + pimpl->set_labels_visible(visible); +} + +bool BasicPlot::labels_visible() const { + return pimpl->labels_visible(); +} + bool BasicPlot::is_initialized() const { return pimpl->is_plot_initialized(); } @@ -86,4 +94,4 @@ using namespace creeper; void creeper::HeatMapPlot::paintEvent(QPaintEvent* event) { BasicPlot::paintEvent(event); -} \ No newline at end of file +} diff --git a/components/charts/heatmap.hh b/components/charts/heatmap.hh index 18180e1..5595285 100644 --- a/components/charts/heatmap.hh +++ b/components/charts/heatmap.hh @@ -43,7 +43,9 @@ public: void set_matrix_size(const int& w, const int& h)const; void set_data(const QVector& data)const; void set_color_gradient_range(const double& min, const double& max)const; + void set_labels_visible(bool visible) const; QSize get_matrix_size() const; + bool labels_visible() const; bool is_initialized() const; public slots: diff --git a/components/charts/heatmap.impl.hh b/components/charts/heatmap.impl.hh index dc7a20e..20de731 100644 --- a/components/charts/heatmap.impl.hh +++ b/components/charts/heatmap.impl.hh @@ -19,7 +19,13 @@ using namespace creeper::plot_widget::internal; struct BasicPlot::Impl { - explicit Impl(BasicPlot& self) noexcept : self{self}, initialized(false), matrix_size(QSize{3, 4}) {} + explicit Impl(BasicPlot& self) noexcept + : matrix_size(QSize{3, 4}) + , color_min(0.0) + , color_max(800.0) + , show_labels(false) + , initialized(false) + , self{self} { } public: std::optional scheme; @@ -41,10 +47,15 @@ public: auto set_matrix_size(const QSize& size) -> void { matrix_size = size; + const int expected = std::max(0, matrix_size.width() * matrix_size.height()); + last_values.assign(static_cast(expected), 0.0); if (initialized) { reset_plot(); if (!data_points.isEmpty()) { set_data(data_points); + } else if (show_labels) { + sync_labels(last_values); + self.replot(); } } } @@ -75,6 +86,18 @@ public: } } + auto set_labels_visible(bool visible) -> void { + show_labels = visible; + if (initialized) { + sync_labels(last_values); + self.replot(); + } + } + + auto labels_visible() const -> bool { + return show_labels; + } + auto initialize_plot() -> void { if (initialized) return; @@ -149,12 +172,12 @@ public: auto reset_plot() -> void { // 清除所有绘图元素 + clear_labels(); self.clearPlottables(); self.clearGraphs(); self.clearItems(); self.clearFocus(); color_map = nullptr; - cell_labels.clear(); // 重新初始化 initialized = false; @@ -163,7 +186,7 @@ public: auto update_plot_data() -> void { if (!initialized || !color_map) return; - ensure_labels(); + // ensure_labels(); const int width = matrix_size.width(); const int height = matrix_size.height(); @@ -182,7 +205,8 @@ public: } } - update_label_values(values); + last_values = values; + sync_labels(last_values); // 重绘 self.replot(); @@ -201,8 +225,10 @@ private: QString ylabel; QSize matrix_size; QVector data_points; + std::vector last_values; double color_min = 0.0; double color_max = 800.0; + bool show_labels = false; bool initialized; BasicPlot& self; QCPColorScale* color_scale = nullptr; @@ -217,7 +243,7 @@ private: text_color = scheme->on_surface; } } - label_text_color = QColor(0, 0, 0); // 固定黑色 + label_text_color = text_color; const auto pen = QPen(text_color); @@ -293,7 +319,6 @@ private: void update_label_values(const std::vector& values) { const int width = matrix_size.width(); const int height = matrix_size.height(); - const double range = std::max(color_max - color_min, 1.0); const int expected = width * height; for (int idx = 0; idx < expected && idx < cell_labels.size(); ++idx) { auto* label = cell_labels[idx]; @@ -309,6 +334,18 @@ private: label->position->setCoords(x + 0.5, y + 0.5); } } + + void sync_labels(const std::vector& values) { + if (!initialized) { + return; + } + if (show_labels) { + ensure_labels(); + update_label_values(values); + } else if (!cell_labels.isEmpty()) { + clear_labels(); + } + } }; #endif // TOUCHSENSOR_HEATMAP_IMPL_HH diff --git a/components/charts/line_chart.cc b/components/charts/line_chart.cc index 0ce1a10..20ab184 100644 --- a/components/charts/line_chart.cc +++ b/components/charts/line_chart.cc @@ -4,6 +4,7 @@ #include "line_chart.hh" #include +#include #include #include #include @@ -86,6 +87,16 @@ void LinePlot::initialize_plot() { graph_->setAntialiased(true); graph_->setAdaptiveSampling(true); + current_label_ = new QCPItemText(this); + current_label_->position->setType(QCPItemPosition::ptAxisRectRatio); + current_label_->setPositionAlignment(Qt::AlignRight | Qt::AlignTop); + current_label_->position->setCoords(0.98, 0.04); + current_label_->setPadding(QMargins(6, 3, 6, 3)); + current_label_->setBrush(QColor(0, 0, 0, 50)); + current_label_->setPen(Qt::NoPen); + current_label_->setLayer("overlay"); + current_label_->setClipToAxisRect(true); + initialized_ = true; apply_theme(); update_graph(); @@ -100,6 +111,7 @@ void LinePlot::apply_theme() { QColor line_color{ 16, 54, 128 }; QColor text_color{ 30, 30, 30 }; QColor bg_color{ 232, 238, 248 }; + QColor label_bg = QColor(0, 0, 0, 50); if (scheme_.has_value()) { if (scheme_->primary.isValid()) { line_color = scheme_->primary; @@ -116,6 +128,11 @@ void LinePlot::apply_theme() { else if (scheme_->surface.isValid()) { bg_color = scheme_->surface; } + if (scheme_->surface_container.isValid()) { + label_bg = QColor(scheme_->surface_container.red(), + scheme_->surface_container.green(), + scheme_->surface_container.blue(), 90); + } } QColor grid_color = bg_color; @@ -150,6 +167,14 @@ void LinePlot::apply_theme() { scatter.setSize(7); graph_->setScatterStyle(scatter); } + + if (current_label_) { + current_label_->setColor(text_color); + current_label_->setBrush(label_bg); + QFont f = current_label_->font(); + f.setBold(true); + current_label_->setFont(f); + } } void LinePlot::update_graph() { @@ -164,6 +189,9 @@ void LinePlot::update_graph() { if (points_.isEmpty()) { graph_->data()->clear(); reset_graph_range(); + if (current_label_) { + current_label_->setText(QStringLiteral("--")); + } replot(); return; } @@ -203,6 +231,11 @@ void LinePlot::update_graph() { yAxis->setRange(min_val - padding, max_val + padding); } + if (current_label_) { + const double last_val = points_.back().y(); + current_label_->setText(QString::number(last_val, 'f', 1)); + } + replot(); } diff --git a/components/charts/line_chart.hh b/components/charts/line_chart.hh index d4a678b..14089e0 100644 --- a/components/charts/line_chart.hh +++ b/components/charts/line_chart.hh @@ -11,6 +11,7 @@ #include "qcustomplot/qcustomplot.h" #include #include +#include #include #include #include @@ -43,6 +44,7 @@ class LinePlot: public QCustomPlot { bool initialized_ = false; std::optional scheme_; QCPGraph* graph_ = nullptr; + QCPItemText* current_label_ = nullptr; int max_points_ = 240; double default_y_range_ = 100.0; }; diff --git a/components/charts/vector_field.cc b/components/charts/vector_field.cc index 5a770e6..f647064 100644 --- a/components/charts/vector_field.cc +++ b/components/charts/vector_field.cc @@ -6,6 +6,10 @@ #include #include #include +#include +#include +#include +#include using creeper::vector_widget::internal::VectorPlot; @@ -45,6 +49,116 @@ void VectorPlot::paintEvent(QPaintEvent* event) { initialize_plot(); } QCustomPlot::paintEvent(event); + + // Custom glossy arrow rendering + const auto rect = axisRect(); + if (!rect) { + return; + } + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, true); + + const QRectF plot_rect = rect->rect(); + const double side_pad = plot_rect.width() * 0.24; + QRectF area = plot_rect.adjusted(side_pad, 8.0, -side_pad, -8.0); + const double cx_canvas = area.center().x(); + const double cy_canvas = area.center().y(); + const double scale = 0.72; // overall shrink to make it slimmer + area.setWidth(area.width() * scale); + area.setHeight(area.height() * scale); + area.moveCenter(QPointF(cx_canvas, cy_canvas)); + if (area.width() <= 0.0 || area.height() <= 0.0) { + return; + } + + const double w = area.width(); + const double h = area.height(); + const double cx = area.center().x(); + const double shaft_w = w * 0.18; + const double shaft_r = shaft_w * 0.25; + const double head_h = h * 0.36; + const double head_w = w * 0.52; + const double shaft_h = h - head_h; + const double shaft_x = cx - shaft_w * 0.5; + const double shaft_y = area.top(); + const double head_base_y = shaft_y + shaft_h - shaft_r * 0.4; // overlap slightly to avoid seam + + QPainterPath shaft; + shaft.addRoundedRect(QRectF(shaft_x, shaft_y, shaft_w, shaft_h), shaft_r, shaft_r); + + QPainterPath head; + head.moveTo(cx - head_w * 0.5, head_base_y); + head.lineTo(cx + head_w * 0.5, head_base_y); + head.lineTo(cx, area.bottom()); + head.closeSubpath(); + + QPainterPath arrow = shaft.united(head); + + // Vibrant orange palette (fixed) + QColor base_color(255, 140, 0); + QColor highlight = base_color.lighter(165); + QColor mid = base_color; + QColor shadow = base_color.darker(180); + + QLinearGradient body_grad(area.topLeft(), QPointF(area.left(), area.bottom())); + body_grad.setColorAt(0.0, highlight); + body_grad.setColorAt(0.28, mid); + body_grad.setColorAt(0.72, base_color.darker(110)); + body_grad.setColorAt(1.0, shadow); + + const double angle_deg = std::atan2(arrow_dir_.y(), arrow_dir_.x()) * 180.0 / 3.14159265358979323846 - 90.0; + QTransform transform; + transform.translate(cx, (shaft_y + head_base_y + area.bottom()) / 3.0); // approximate center + transform.rotate(angle_deg); + transform.translate(-cx, -(shaft_y + head_base_y + area.bottom()) / 3.0); + + auto draw_with_transform = [&](const QPainterPath& path, const QBrush& brush, const QPen* pen = nullptr) { + const QPainterPath rotated = transform.map(path); + painter.setBrush(brush); + if (pen) { + painter.setPen(*pen); + } + else { + painter.setPen(Qt::NoPen); + } + painter.drawPath(rotated); + }; + + draw_with_transform(arrow, QBrush(body_grad)); + + // Gloss highlight + QPainterPath gloss; + const double gloss_w = shaft_w * 0.42; + QRectF gloss_rect(cx - gloss_w * 0.5, shaft_y + h * 0.04, gloss_w, shaft_h * 0.5); + gloss.addRoundedRect(gloss_rect, gloss_w * 0.4, gloss_w * 0.4); + QLinearGradient gloss_grad(gloss_rect.topLeft(), gloss_rect.bottomLeft()); + QColor gloss_hi = Qt::white; + gloss_hi.setAlpha(190); + QColor gloss_lo = Qt::white; + gloss_lo.setAlpha(40); + gloss_grad.setColorAt(0.0, gloss_hi); + gloss_grad.setColorAt(1.0, gloss_lo); + draw_with_transform(gloss, QBrush(gloss_grad)); + + // Head specular highlights + const double spec_w = head_w * 0.18; + QRectF spec_left(cx - head_w * 0.32, head_base_y + head_h * 0.08, spec_w, head_h * 0.2); + QRectF spec_right(cx + head_w * 0.14, head_base_y + head_h * 0.1, spec_w * 0.8, head_h * 0.2); + auto paint_spec = [&](const QRectF& r) { + QPainterPath p; + p.addRoundedRect(r, r.width() * 0.4, r.height() * 0.6); + QLinearGradient g(r.topLeft(), r.bottomLeft()); + QColor hi = Qt::white; + hi.setAlpha(180); + QColor lo = Qt::white; + lo.setAlpha(30); + g.setColorAt(0.0, hi); + g.setColorAt(1.0, lo); + draw_with_transform(p, QBrush(g)); + }; + paint_spec(spec_left); + paint_spec(spec_right); } void VectorPlot::initialize_plot() { @@ -109,6 +223,7 @@ void VectorPlot::apply_color_scheme() { strong_pen.setJoinStyle(Qt::MiterJoin); if (primary_arrow_) { primary_arrow_->setPen(strong_pen); + primary_arrow_->setVisible(false); // 使用自绘 3D 箭头 } } @@ -178,6 +293,7 @@ void VectorPlot::update_vectors() { } dir_x /= dir_len; dir_y /= dir_len; + arrow_dir_ = QPointF(dir_x, dir_y); const double arrow_len = 0.48 * std::min(width, height); // 稍长的指针 const double tail_ratio = 0.25; // 穿过中心的尾巴略长 const double tail_len = arrow_len * tail_ratio; @@ -189,7 +305,7 @@ void VectorPlot::update_vectors() { if (primary_arrow_) { primary_arrow_->start->setCoords(cx - dir_x * tail_len, cy - dir_y * tail_len); primary_arrow_->end->setCoords(cx + dir_x * head_base, cy + dir_y * head_base); - primary_arrow_->setVisible(true); + primary_arrow_->setVisible(false); // 位置保留以备需要,但当前使用自绘 3D 箭头 } replot(); diff --git a/components/charts/vector_field.hh b/components/charts/vector_field.hh index b24726f..38e48ad 100644 --- a/components/charts/vector_field.hh +++ b/components/charts/vector_field.hh @@ -14,6 +14,7 @@ #include #include #include +#include #include namespace creeper { @@ -39,12 +40,13 @@ class VectorPlot : public QCustomPlot { void ensure_arrows(); void apply_color_scheme(); - QSize matrix_size_{ 3, 4 }; - QVector data_points_; - bool initialized_ = false; + QSize matrix_size_{ 3, 4 }; + QVector data_points_; + bool initialized_ = false; std::optional scheme_; - QColor arrow_color_{ 16, 54, 128 }; // 深蓝色 - QCPItemLine* primary_arrow_ = nullptr; + QColor arrow_color_{ 16, 54, 128 }; // 深蓝色 + QPointF arrow_dir_{ 0.0, 1.0 }; + QCPItemLine* primary_arrow_ = nullptr; void ensure_primary_arrow(); }; diff --git a/components/ffmsep/presist/presist.cc b/components/ffmsep/presist/presist.cc index 021b0f8..03753ab 100644 --- a/components/ffmsep/presist/presist.cc +++ b/components/ffmsep/presist/presist.cc @@ -27,10 +27,12 @@ using nlohmann::json; // void dump_compact_json(...) // json serialize_tactile_frame(const DecodedFrame& frame) { ... } -std::string payload_to_csv_row(const std::vector& payload) { - // Combine every 2 bytes (little-endian) into one 16-bit value, output in decimal. +std::string payload_to_csv_row(const std::string& timestamp, +const std::vector& payload) { + // First column: receive local time (YYYYMMDDHHMMSS). Then payload every 2 bytes -> uint16. std::ostringstream oss; - bool first = true; + oss << timestamp; + bool first = false; // timestamp already placed for (std::size_t idx = 0; idx + 1U < payload.size(); idx += 2U) { const auto value = static_cast(payload[idx]) | static_cast(payload[idx + 1U] << 8U); @@ -49,6 +51,28 @@ std::string payload_to_csv_row(const std::vector& payload) { namespace { using nlohmann::json; +std::string format_receive_time(const std::chrono::steady_clock::time_point& received) { + // Map steady_clock timestamp to system_clock using the current offset, then format as YYYYMMDDHHMMSS. + const auto now_sys = std::chrono::system_clock::now(); + const auto now_steady = std::chrono::steady_clock::now(); + const auto steady_delta = received - now_steady; + const auto sys_tp = now_sys + steady_delta; + const auto sys_ms_tp = std::chrono::time_point_cast(sys_tp); + const auto ms_part = std::chrono::duration_cast(sys_ms_tp.time_since_epoch()) % 1000; + const auto sys_sec_tp = std::chrono::time_point_cast(sys_ms_tp); + const std::time_t tt = std::chrono::system_clock::to_time_t(sys_sec_tp); + std::tm tm{}; +#if defined(_WIN32) + localtime_s(&tm, &tt); +#else + localtime_r(&tt, &tm); +#endif + std::ostringstream oss; + oss << std::put_time(&tm, "%Y%m%d%H%M%S") + << std::setw(3) << std::setfill('0') << ms_part.count(); + return oss.str(); +} + bool is_simple_array(const json& value) { if (!value.is_array()) { return false; @@ -261,7 +285,8 @@ std::deque> frames) { continue; } - const auto row = payload_to_csv_row(payload); + const auto timestamp = format_receive_time(frame->received_at); + const auto row = payload_to_csv_row(timestamp, payload); stream << row << '\n'; wrote_any = true; } diff --git a/components/nav.cc b/components/nav.cc index 2a27188..713b182 100644 --- a/components/nav.cc +++ b/components/nav.cc @@ -92,6 +92,23 @@ auto NavComponent(NavComponentState& state) noexcept -> raw_pointer { ic::FontIcon {material::icon::kLogout}, ic::Clickable {&app::quit}, }, + ln::Item { + {0, Qt::AlignHCenter}, + navigation_icons_config, + ic::ColorFilled, + ic::FontIcon {material::icon::k123}, + MutableTransform{ [](auto& self, bool show_numbers) { + self.set_types(show_numbers + ? icon_button::internal::IconButton::Types::TOGGLE_SELECTED + : icon_button::internal::IconButton::Types::TOGGLE_UNSELECTED); + }, + state.heatmap_show_numbers }, + ic::Clickable{ [ctx = state.heatmap_show_numbers] { + if (ctx) { + ctx->set(!ctx->get()); + } + } }, + }, ln::Item { {0, Qt::AlignHCenter}, navigation_icons_config, @@ -102,4 +119,3 @@ auto NavComponent(NavComponentState& state) noexcept -> raw_pointer { } }; } - diff --git a/components/view.cc b/components/view.cc index 5c6f71a..4fd423f 100644 --- a/components/view.cc +++ b/components/view.cc @@ -171,11 +171,14 @@ class SensorStreamController: public QObject { std::shared_ptr>> heatmap_data, std::shared_ptr> matrix_context, std::shared_ptr>> line_series, + std::shared_ptr>> line_series_max, int line_capacity = 240, QObject* parent = nullptr): QObject(parent), heatmap_data_(std::move(heatmap_data)), matrix_context_(std::move(matrix_context)), line_series_(std::move(line_series)), - line_series_capacity_(std::max(1, line_capacity)) { + line_series_max_(std::move(line_series_max)), + line_series_capacity_(std::max(1, line_capacity)), + line_series_half_capacity_(std::max(1, line_capacity / 2)) { std::call_once(codec_registration_flag(), [] { ffmsep::tactile::register_tactile_codec(); @@ -197,6 +200,9 @@ class SensorStreamController: public QObject { if (line_series_) { line_series_->set(QVector{}); } + if (line_series_max_) { + line_series_max_->set(QVector{}); + } const auto ports = ffmsep::CPStreamCore::list_available_ports(); std::string port_utf8; @@ -335,6 +341,9 @@ class SensorStreamController: public QObject { if (line_series_) { line_series_->set(QVector{}); } + if (line_series_max_) { + line_series_max_->set(QVector{}); + } sample_counter_ = 0; } @@ -444,8 +453,13 @@ class SensorStreamController: public QObject { } double total = 0.0; + double max_v = 0.0; for (const auto value: pressures) { - total += static_cast(value); + const double v = static_cast(value); + total += v; + if (v > max_v) { + max_v = v; + } } if (line_series_) { @@ -456,9 +470,19 @@ class SensorStreamController: public QObject { const int start = series.size() - line_series_capacity_; series = series.mid(start); } - ++sample_counter_; line_series_->set(std::move(series)); } + if (line_series_max_) { + auto series = line_series_max_->get(); + series.append(QPointF(static_cast(sample_counter_), max_v)); + const int cap = std::max(1, line_series_half_capacity_); + if (series.size() > cap) { + const int start = series.size() - cap; + series = series.mid(start); + } + line_series_max_->set(std::move(series)); + } + ++sample_counter_; QVector points; points.reserve(matrix.width() * matrix.height()); @@ -546,11 +570,13 @@ class SensorStreamController: public QObject { std::shared_ptr>> heatmap_data_; std::shared_ptr> matrix_context_; std::shared_ptr>> line_series_; + std::shared_ptr>> line_series_max_; std::unique_ptr core_; QString active_port_; QString last_error_; std::uint64_t sample_counter_ = 0; int line_series_capacity_ = 240; + int line_series_half_capacity_ = 120; bool connected_ = false; static std::future @@ -573,8 +599,12 @@ struct SensorUiState { std::make_shared>(); std::shared_ptr>> heatmap_range = std::make_shared>>(QPair{ 0, 300 }); + std::shared_ptr> heatmap_show_numbers = + std::make_shared>(false); std::shared_ptr>> line_series = std::make_shared>>(); + std::shared_ptr>> line_series_max = + std::make_shared>>(); int line_series_capacity = 240; std::shared_ptr> port_items = std::make_shared>(); @@ -631,7 +661,7 @@ struct SensorUiState { controller = std::make_unique( - heatmap_data, heatmap_matrix, line_series, line_series_capacity); + heatmap_data, heatmap_matrix, line_series, line_series_max, line_series_capacity); } }; @@ -674,6 +704,10 @@ class PortHoverRefreshFilter final: public QObject { } // namespace +std::shared_ptr> HeatmapNumberVisibilityContext() { + return sensor_state().heatmap_show_numbers; +} + void RefreshProfilesForView() { auto& sensor = sensor_state(); @@ -912,9 +946,10 @@ int /*index*/ = 0) noexcept { auto& sensor = sensor_state(); const auto row = new Row{ lnpro::Item{ - plot_widget::pro::SizePolicy{ - QSizePolicy::Expanding, - }, + widget::pro::FixedSize {600, 600}, + // plot_widget::pro::SizePolicy{ + // // QSizePolicy::Fixed, + // }, plot_widget::pro::ThemeManager{ manager }, MutableForward{ plot_widget::pro::PlotData{}, @@ -933,6 +968,10 @@ int /*index*/ = 0) noexcept { widget.set_color_gradient_range(min, max); }, sensor.heatmap_range }, + MutableTransform{ [](auto& widget, bool show_numbers) { + widget.set_labels_visible(show_numbers); + }, + sensor.heatmap_show_numbers }, }, }; return new Widget{ @@ -966,21 +1005,29 @@ static auto DisplayVectorComponent(ThemeManager& manager) noexcept { static auto DisplayLineComponent(ThemeManager& manager) noexcept { auto& sensor = sensor_state(); - const auto row = new Row{ + const int half_cap = std::max(1, sensor.line_series_capacity / 2); + const auto col = new Col{ lnpro::Item{ - lcpro::SizePolicy{ - QSizePolicy::Expanding, - }, + lcpro::SizePolicy{ QSizePolicy::Expanding }, lcpro::ThemeManager{ manager }, - lcpro::MaxPoints{ sensor.line_series_capacity }, + lcpro::MaxPoints{ half_cap }, MutableForward{ lcpro::PlotData{}, sensor.line_series, }, }, + lnpro::Item{ + lcpro::SizePolicy{ QSizePolicy::Expanding }, + lcpro::ThemeManager{ manager }, + lcpro::MaxPoints{ half_cap }, + MutableForward{ + lcpro::PlotData{}, + sensor.line_series_max, + }, + }, }; return new Widget{ - widget::pro::Layout{ row }, + widget::pro::Layout{ col }, }; } diff --git a/creeper-qt/utility/material-icon.hh b/creeper-qt/utility/material-icon.hh index ea8542f..9f1ea42 100644 --- a/creeper-qt/utility/material-icon.hh +++ b/creeper-qt/utility/material-icon.hh @@ -146,6 +146,7 @@ namespace material { constexpr auto kCancel = "cancel"; constexpr auto kOpenInNew = "open_in_new"; constexpr auto kLogout = "logout"; + constexpr auto k123 = "123"; constexpr auto kRoutine = "routine"; constexpr auto kDarkMode = "dark_mode"; constexpr auto kFileExport = "file_export"; diff --git a/main.cc b/main.cc index bd8360c..950f276 100644 --- a/main.cc +++ b/main.cc @@ -33,7 +33,7 @@ auto main(int argc, char *argv[]) -> int { auto stack_index = std::make_shared>(); stack_index->set_silent(0); - auto manager = ThemeManager {kBlueMikuThemePack}; + auto manager = ThemeManager {kBlueMikuThemePack, ColorMode::DARK}; creeper::material::FontLoader::load_font(); auto nav_component_state = NavComponentState { .manager = manager, @@ -51,7 +51,8 @@ auto main(int argc, char *argv[]) -> int { }, .stacked_callback = [&](int index) { *stack_index = index; - } + }, + .heatmap_show_numbers = HeatmapNumberVisibilityContext(), }; auto setting_component_state = SettingComponentState { .manager = manager,