颜色修改红绿,修复帧错误卡顿bug
This commit is contained in:
@@ -127,10 +127,9 @@ public:
|
||||
cpmp->setColorScale(color_scale);
|
||||
|
||||
QCPColorGradient gradient;
|
||||
gradient.setColorStopAt(0.0, QColor(240, 246, 255)); // 低值淡色
|
||||
gradient.setColorStopAt(0.35, QColor(142, 197, 252));
|
||||
gradient.setColorStopAt(0.7, QColor(56, 128, 199));
|
||||
gradient.setColorStopAt(1.0, QColor(8, 36, 95)); // 高值深色
|
||||
gradient.setColorStopAt(0.0, QColor(0, 176, 80));
|
||||
gradient.setColorStopAt(0.5, QColor(255, 214, 10));
|
||||
gradient.setColorStopAt(1.0, QColor(204, 0, 0));
|
||||
cpmp->setGradient(gradient);
|
||||
|
||||
cpmp->setDataRange(QCPRange(color_min, color_max));
|
||||
|
||||
221
components/charts/line_chart.cc
Normal file
221
components/charts/line_chart.cc
Normal file
@@ -0,0 +1,221 @@
|
||||
//
|
||||
// Created by Codex on 2025/12/10.
|
||||
//
|
||||
|
||||
#include "line_chart.hh"
|
||||
#include <QLinearGradient>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
using creeper::line_widget::internal::LinePlot;
|
||||
|
||||
LinePlot::LinePlot() {
|
||||
setBackground(Qt::transparent);
|
||||
}
|
||||
|
||||
LinePlot::~LinePlot() = default;
|
||||
|
||||
void LinePlot::load_theme_manager(creeper::ThemeManager& mgr) {
|
||||
mgr.append_handler(this, [this](const creeper::ThemeManager& manager) {
|
||||
scheme_ = manager.color_scheme();
|
||||
apply_theme();
|
||||
if (initialized_) {
|
||||
replot();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void LinePlot::set_data(const QVector<QPointF>& points) {
|
||||
points_ = points;
|
||||
trim_points();
|
||||
if (initialized_) {
|
||||
update_graph();
|
||||
}
|
||||
}
|
||||
|
||||
void LinePlot::set_max_points(int count) {
|
||||
const int clamped = std::max(1, count);
|
||||
if (clamped == max_points_) {
|
||||
return;
|
||||
}
|
||||
max_points_ = clamped;
|
||||
trim_points();
|
||||
if (initialized_) {
|
||||
update_graph();
|
||||
}
|
||||
}
|
||||
|
||||
void LinePlot::paintEvent(QPaintEvent* event) {
|
||||
if (!initialized_) {
|
||||
initialize_plot();
|
||||
}
|
||||
QCustomPlot::paintEvent(event);
|
||||
}
|
||||
|
||||
void LinePlot::initialize_plot() {
|
||||
if (initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
axisRect()->setAutoMargins(QCP::msNone);
|
||||
axisRect()->setMargins(QMargins(40, 12, 12, 18));
|
||||
axisRect()->setBackground(QBrush(QColor(246, 249, 255)));
|
||||
|
||||
legend->setVisible(false);
|
||||
xAxis->setVisible(true);
|
||||
yAxis->setVisible(true);
|
||||
xAxis->setRange(0.0, std::max(10, max_points_));
|
||||
yAxis->setRange(0.0, default_y_range_);
|
||||
|
||||
xAxis->grid()->setVisible(false);
|
||||
yAxis->grid()->setVisible(false);
|
||||
xAxis->setTicks(false);
|
||||
yAxis->setTicks(true);
|
||||
xAxis->setSubTicks(false);
|
||||
yAxis->setSubTicks(false);
|
||||
xAxis->setTickLength(0);
|
||||
yAxis->setTickLength(0);
|
||||
yAxis->setTickLabelPadding(6);
|
||||
yAxis->setLabelPadding(8);
|
||||
|
||||
graph_ = addGraph();
|
||||
graph_->setLineStyle(QCPGraph::lsLine);
|
||||
graph_->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssCircle, QPen(Qt::NoPen), QBrush(Qt::white), 6));
|
||||
graph_->setBrush(QColor(16, 54, 128, 42));
|
||||
graph_->setAntialiased(true);
|
||||
graph_->setAdaptiveSampling(true);
|
||||
|
||||
initialized_ = true;
|
||||
apply_theme();
|
||||
update_graph();
|
||||
}
|
||||
|
||||
void LinePlot::reset_graph_range() {
|
||||
xAxis->setRange(0.0, std::max(10, max_points_));
|
||||
yAxis->setRange(0.0, default_y_range_);
|
||||
}
|
||||
|
||||
void LinePlot::apply_theme() {
|
||||
QColor line_color{ 16, 54, 128 };
|
||||
QColor text_color{ 30, 30, 30 };
|
||||
QColor bg_color{ 232, 238, 248 };
|
||||
if (scheme_.has_value()) {
|
||||
if (scheme_->primary.isValid()) {
|
||||
line_color = scheme_->primary;
|
||||
}
|
||||
if (scheme_->on_surface.isValid()) {
|
||||
text_color = scheme_->on_surface;
|
||||
}
|
||||
if (scheme_->surface_container_high.isValid()) {
|
||||
bg_color = scheme_->surface_container_high;
|
||||
}
|
||||
else if (scheme_->surface_container.isValid()) {
|
||||
bg_color = scheme_->surface_container;
|
||||
}
|
||||
else if (scheme_->surface.isValid()) {
|
||||
bg_color = scheme_->surface;
|
||||
}
|
||||
}
|
||||
|
||||
QColor grid_color = bg_color;
|
||||
|
||||
QPen axis_pen(bg_color);
|
||||
axis_pen.setWidthF(1.0);
|
||||
xAxis->setBasePen(axis_pen);
|
||||
yAxis->setBasePen(axis_pen);
|
||||
xAxis->setTickPen(axis_pen);
|
||||
yAxis->setTickPen(axis_pen);
|
||||
xAxis->setTickLabelColor(Qt::transparent);
|
||||
yAxis->setTickLabelColor(text_color);
|
||||
xAxis->setLabelColor(Qt::transparent);
|
||||
yAxis->setLabelColor(text_color);
|
||||
axisRect()->setBackground(bg_color);
|
||||
|
||||
if (graph_) {
|
||||
QPen pen(line_color);
|
||||
pen.setWidthF(3.0);
|
||||
pen.setCapStyle(Qt::RoundCap);
|
||||
graph_->setPen(pen);
|
||||
|
||||
QLinearGradient fill_grad(0, 0, 0, 1);
|
||||
fill_grad.setCoordinateMode(QGradient::CoordinateMode::ObjectBoundingMode);
|
||||
fill_grad.setColorAt(0.0, QColor(line_color.red(), line_color.green(), line_color.blue(), 70));
|
||||
fill_grad.setColorAt(1.0, QColor(line_color.red(), line_color.green(), line_color.blue(), 18));
|
||||
graph_->setBrush(QBrush(fill_grad));
|
||||
|
||||
auto scatter = graph_->scatterStyle();
|
||||
scatter.setPen(QPen(line_color, 1.5));
|
||||
scatter.setBrush(QBrush(QColor(bg_color).lighter(104)));
|
||||
scatter.setSize(7);
|
||||
graph_->setScatterStyle(scatter);
|
||||
}
|
||||
}
|
||||
|
||||
void LinePlot::update_graph() {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
if (!graph_) {
|
||||
graph_ = addGraph();
|
||||
apply_theme();
|
||||
}
|
||||
|
||||
if (points_.isEmpty()) {
|
||||
graph_->data()->clear();
|
||||
reset_graph_range();
|
||||
replot();
|
||||
return;
|
||||
}
|
||||
|
||||
QVector<double> keys(points_.size());
|
||||
QVector<double> values(points_.size());
|
||||
double min_key = std::numeric_limits<double>::max();
|
||||
double max_key = std::numeric_limits<double>::lowest();
|
||||
double min_val = std::numeric_limits<double>::max();
|
||||
double max_val = std::numeric_limits<double>::lowest();
|
||||
|
||||
for (int i = 0; i < points_.size(); ++i) {
|
||||
const auto& pt = points_[i];
|
||||
keys[i] = pt.x();
|
||||
values[i] = pt.y();
|
||||
min_key = std::min(min_key, pt.x());
|
||||
max_key = std::max(max_key, pt.x());
|
||||
min_val = std::min(min_val, pt.y());
|
||||
max_val = std::max(max_val, pt.y());
|
||||
}
|
||||
|
||||
graph_->setData(keys, values, true);
|
||||
|
||||
if (min_key == std::numeric_limits<double>::max()) {
|
||||
reset_graph_range();
|
||||
}
|
||||
else {
|
||||
const double key_span = std::max(1e-3, max_key - min_key);
|
||||
xAxis->setRange(min_key, max_key + key_span * 0.02);
|
||||
|
||||
double value_span = max_val - min_val;
|
||||
if (value_span < 1e-3) {
|
||||
value_span = std::max(std::abs(max_val), 1.0);
|
||||
min_val = max_val - value_span * 0.5;
|
||||
}
|
||||
const double padding = std::max(value_span * 0.25, 1.0);
|
||||
yAxis->setRange(min_val - padding, max_val + padding);
|
||||
}
|
||||
|
||||
replot();
|
||||
}
|
||||
|
||||
void LinePlot::trim_points() {
|
||||
if (max_points_ <= 0 || points_.size() <= max_points_) {
|
||||
return;
|
||||
}
|
||||
const int start = points_.size() - max_points_;
|
||||
points_ = points_.mid(start);
|
||||
}
|
||||
|
||||
using namespace creeper;
|
||||
|
||||
void SumLinePlot::paintEvent(QPaintEvent* event) {
|
||||
line_widget::internal::LinePlot::paintEvent(event);
|
||||
}
|
||||
79
components/charts/line_chart.hh
Normal file
79
components/charts/line_chart.hh
Normal file
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Created by Codex on 2025/12/10.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "creeper-qt/utility/theme/theme.hh"
|
||||
#include "creeper-qt/utility/wrapper/common.hh"
|
||||
#include "creeper-qt/utility/wrapper/property.hh"
|
||||
#include "creeper-qt/utility/wrapper/widget.hh"
|
||||
#include "qcustomplot/qcustomplot.h"
|
||||
#include <QPaintEvent>
|
||||
#include <QPointF>
|
||||
#include <concepts>
|
||||
#include <optional>
|
||||
#include <qsize.h>
|
||||
#include <qvector.h>
|
||||
|
||||
namespace creeper {
|
||||
class SumLinePlot;
|
||||
|
||||
namespace line_widget::internal {
|
||||
class LinePlot: public QCustomPlot {
|
||||
public:
|
||||
LinePlot();
|
||||
~LinePlot() override;
|
||||
|
||||
void load_theme_manager(ThemeManager& mgr);
|
||||
void set_data(const QVector<QPointF>& points);
|
||||
void set_max_points(int count);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
|
||||
private:
|
||||
void initialize_plot();
|
||||
void update_graph();
|
||||
void apply_theme();
|
||||
void reset_graph_range();
|
||||
void trim_points();
|
||||
|
||||
QVector<QPointF> points_;
|
||||
bool initialized_ = false;
|
||||
std::optional<ColorScheme> scheme_;
|
||||
QCPGraph* graph_ = nullptr;
|
||||
int max_points_ = 240;
|
||||
double default_y_range_ = 100.0;
|
||||
};
|
||||
} // namespace line_widget::internal
|
||||
|
||||
namespace line_widget::pro {
|
||||
using Token = common::Token<internal::LinePlot>;
|
||||
|
||||
struct MaxPoints: Token {
|
||||
int count;
|
||||
explicit MaxPoints(int c): count{ c } { }
|
||||
void apply(auto& self) const { self.set_max_points(count); }
|
||||
};
|
||||
|
||||
using PlotData = DerivedProp<Token, QVector<QPointF>, [](auto& self, const auto& vec) {
|
||||
self.set_data(vec);
|
||||
}>;
|
||||
|
||||
template<class PlotWidget>
|
||||
concept trait = std::derived_from<PlotWidget, Token>;
|
||||
|
||||
CREEPER_DEFINE_CHECKER(trait);
|
||||
|
||||
using namespace widget::pro;
|
||||
using namespace theme::pro;
|
||||
} // namespace line_widget::pro
|
||||
|
||||
struct SumLinePlot
|
||||
: public Declarative<line_widget::internal::LinePlot,
|
||||
CheckerOr<line_widget::pro::checker, widget::pro::checker, theme::pro::checker>> {
|
||||
using Declarative::Declarative;
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
};
|
||||
} // namespace creeper
|
||||
202
components/charts/vector_field.cc
Normal file
202
components/charts/vector_field.cc
Normal file
@@ -0,0 +1,202 @@
|
||||
//
|
||||
// Created by Codex on 2025/12/05.
|
||||
//
|
||||
|
||||
#include "vector_field.hh"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
using creeper::vector_widget::internal::VectorPlot;
|
||||
|
||||
VectorPlot::VectorPlot() {
|
||||
setBackground(Qt::transparent);
|
||||
}
|
||||
|
||||
VectorPlot::~VectorPlot() = default;
|
||||
|
||||
void VectorPlot::load_theme_manager(creeper::ThemeManager& mgr) {
|
||||
mgr.append_handler(this, [this](const creeper::ThemeManager& manager) {
|
||||
scheme_ = manager.color_scheme();
|
||||
apply_color_scheme();
|
||||
if (initialized_) {
|
||||
replot();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void VectorPlot::set_matrix_size(const QSize& size) {
|
||||
if (size == matrix_size_) {
|
||||
return;
|
||||
}
|
||||
matrix_size_ = size;
|
||||
reset_plot();
|
||||
}
|
||||
|
||||
void VectorPlot::set_data(const QVector<PointData>& data) {
|
||||
data_points_ = data;
|
||||
if (initialized_) {
|
||||
update_vectors();
|
||||
}
|
||||
}
|
||||
|
||||
void VectorPlot::paintEvent(QPaintEvent* event) {
|
||||
if (!initialized_) {
|
||||
initialize_plot();
|
||||
}
|
||||
QCustomPlot::paintEvent(event);
|
||||
}
|
||||
|
||||
void VectorPlot::initialize_plot() {
|
||||
if (initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
xAxis->setVisible(false);
|
||||
yAxis->setVisible(false);
|
||||
xAxis->grid()->setPen(Qt::NoPen);
|
||||
yAxis->grid()->setPen(Qt::NoPen);
|
||||
xAxis->setRange(0.0, std::max(1, matrix_size_.width()));
|
||||
yAxis->setRange(0.0, std::max(1, matrix_size_.height()));
|
||||
|
||||
xAxis->setSubTicks(true);
|
||||
yAxis->setSubTicks(true);
|
||||
xAxis->setTickLength(0);
|
||||
yAxis->setTickLength(0);
|
||||
xAxis->setSubTickLength(4);
|
||||
yAxis->setSubTickLength(4);
|
||||
|
||||
initialized_ = true;
|
||||
apply_color_scheme();
|
||||
ensure_arrows();
|
||||
update_vectors();
|
||||
}
|
||||
|
||||
void VectorPlot::reset_plot() {
|
||||
clearItems();
|
||||
primary_arrow_ = nullptr;
|
||||
initialized_ = false;
|
||||
initialize_plot();
|
||||
}
|
||||
|
||||
void VectorPlot::ensure_arrows() {
|
||||
// no-op: legacy multi-arrow support removed
|
||||
}
|
||||
|
||||
void VectorPlot::ensure_primary_arrow() {
|
||||
if (primary_arrow_) {
|
||||
return;
|
||||
}
|
||||
primary_arrow_ = new QCPItemLine(this);
|
||||
primary_arrow_->start->setType(QCPItemPosition::ptPlotCoords);
|
||||
primary_arrow_->end->setType(QCPItemPosition::ptPlotCoords);
|
||||
primary_arrow_->setClipToAxisRect(true);
|
||||
primary_arrow_->setClipAxisRect(axisRect());
|
||||
primary_arrow_->setHead(QCPLineEnding(QCPLineEnding::esSpikeArrow, 14, 8));
|
||||
primary_arrow_->setTail(QCPLineEnding(QCPLineEnding::esNone));
|
||||
apply_color_scheme();
|
||||
}
|
||||
|
||||
void VectorPlot::apply_color_scheme() {
|
||||
QColor pen_color = arrow_color_;
|
||||
if (scheme_.has_value() && scheme_->primary.isValid()) {
|
||||
pen_color = scheme_->primary;
|
||||
}
|
||||
|
||||
QPen strong_pen(pen_color);
|
||||
strong_pen.setWidthF(8.0); // 稍细一点但仍然饱满
|
||||
strong_pen.setCapStyle(Qt::FlatCap);
|
||||
strong_pen.setJoinStyle(Qt::MiterJoin);
|
||||
if (primary_arrow_) {
|
||||
primary_arrow_->setPen(strong_pen);
|
||||
}
|
||||
}
|
||||
|
||||
void VectorPlot::update_vectors() {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
ensure_primary_arrow();
|
||||
|
||||
const int width = std::max(1, matrix_size_.width());
|
||||
const int height = std::max(1, matrix_size_.height());
|
||||
const int expected = width * height;
|
||||
if (expected <= 0 || !primary_arrow_) {
|
||||
replot();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<double> values(static_cast<std::size_t>(expected), 0.0);
|
||||
for (const auto& item: data_points_) {
|
||||
const int x = static_cast<int>(item.x);
|
||||
const int y = static_cast<int>(item.y);
|
||||
if (x >= 0 && x < width && y >= 0 && y < height) {
|
||||
const int idx = y * width + x;
|
||||
values[static_cast<std::size_t>(idx)] = item.z;
|
||||
}
|
||||
}
|
||||
|
||||
auto value_at = [&](int x, int y) -> double {
|
||||
if (x < 0 || x >= width || y < 0 || y >= height) {
|
||||
return 0.0;
|
||||
}
|
||||
return values[static_cast<std::size_t>(y * width + x)];
|
||||
};
|
||||
|
||||
std::vector<std::pair<double, double>> grads(static_cast<std::size_t>(expected), { 0.0, 0.0 });
|
||||
double max_mag = 0.0;
|
||||
double sum_gx = 0.0;
|
||||
double sum_gy = 0.0;
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
const double gx = 0.5 * (value_at(x + 1, y) - value_at(x - 1, y));
|
||||
const double gy = 0.5 * (value_at(x, y + 1) - value_at(x, y - 1));
|
||||
const double mag = std::sqrt(gx * gx + gy * gy);
|
||||
grads[static_cast<std::size_t>(y * width + x)] = { gx, gy };
|
||||
max_mag = std::max(max_mag, mag);
|
||||
sum_gx += gx;
|
||||
sum_gy += gy;
|
||||
}
|
||||
}
|
||||
|
||||
const double scale = (max_mag > 1e-6) ? (0.35 / max_mag) : 0.0;
|
||||
const bool fallback = max_mag <= 1e-6;
|
||||
const double mid_x = static_cast<double>(width) * 0.5;
|
||||
const double mid_y = static_cast<double>(height) * 0.5;
|
||||
|
||||
double dir_x = sum_gx;
|
||||
double dir_y = sum_gy;
|
||||
if (fallback || std::abs(dir_x) + std::abs(dir_y) < 1e-6) {
|
||||
dir_x = 0.0;
|
||||
dir_y = -1.0; // 默认向上指,保证可见
|
||||
}
|
||||
double dir_len = std::sqrt(dir_x * dir_x + dir_y * dir_y);
|
||||
if (dir_len < 1e-6) {
|
||||
dir_x = 0.0;
|
||||
dir_y = -1.0;
|
||||
dir_len = 1.0;
|
||||
}
|
||||
dir_x /= dir_len;
|
||||
dir_y /= dir_len;
|
||||
const double arrow_len = 0.48 * std::min(width, height); // 稍长的指针
|
||||
const double tail_ratio = 0.25; // 穿过中心的尾巴略长
|
||||
const double tail_len = arrow_len * tail_ratio;
|
||||
const double head_len = arrow_len - tail_len;
|
||||
const double backoff = std::max(0.5, head_len * 0.12); // 轻微回缩,避免方头顶出
|
||||
const double head_base = std::max(0.0, head_len - backoff);
|
||||
const double cx = static_cast<double>(width) * 0.5;
|
||||
const double cy = static_cast<double>(height) * 0.5;
|
||||
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);
|
||||
}
|
||||
|
||||
replot();
|
||||
}
|
||||
|
||||
using namespace creeper;
|
||||
|
||||
void VectorFieldPlot::paintEvent(QPaintEvent* event) {
|
||||
vector_widget::internal::VectorPlot::paintEvent(event);
|
||||
}
|
||||
82
components/charts/vector_field.hh
Normal file
82
components/charts/vector_field.hh
Normal file
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// Created by Codex on 2025/12/05.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "components/charts/heatmap.hh" // for PointData definition
|
||||
#include "creeper-qt/utility/theme/theme.hh"
|
||||
#include "creeper-qt/utility/wrapper/common.hh"
|
||||
#include "creeper-qt/utility/wrapper/property.hh"
|
||||
#include "creeper-qt/utility/wrapper/widget.hh"
|
||||
#include "qcustomplot/qcustomplot.h"
|
||||
#include <optional>
|
||||
#include <QPaintEvent>
|
||||
#include <concepts>
|
||||
#include <qsize.h>
|
||||
#include <qvector.h>
|
||||
|
||||
namespace creeper {
|
||||
class VectorFieldPlot;
|
||||
|
||||
namespace vector_widget::internal {
|
||||
class VectorPlot : public QCustomPlot {
|
||||
public:
|
||||
VectorPlot();
|
||||
~VectorPlot() override;
|
||||
|
||||
void load_theme_manager(ThemeManager& mgr);
|
||||
void set_matrix_size(const QSize& size);
|
||||
void set_data(const QVector<PointData>& data);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
|
||||
private:
|
||||
void initialize_plot();
|
||||
void reset_plot();
|
||||
void update_vectors();
|
||||
void ensure_arrows();
|
||||
void apply_color_scheme();
|
||||
|
||||
QSize matrix_size_{ 3, 4 };
|
||||
QVector<PointData> data_points_;
|
||||
bool initialized_ = false;
|
||||
std::optional<ColorScheme> scheme_;
|
||||
QColor arrow_color_{ 16, 54, 128 }; // 深蓝色
|
||||
QCPItemLine* primary_arrow_ = nullptr;
|
||||
|
||||
void ensure_primary_arrow();
|
||||
};
|
||||
} // namespace vector_widget::internal
|
||||
|
||||
namespace vector_widget::pro {
|
||||
using Token = common::Token<internal::VectorPlot>;
|
||||
|
||||
struct MatrixSize : Token {
|
||||
QSize size;
|
||||
explicit MatrixSize(const QSize& s) : size{ s } { }
|
||||
explicit MatrixSize(int w, int h) : size{ w, h } { }
|
||||
void apply(auto& self) const { self.set_matrix_size(size); }
|
||||
};
|
||||
|
||||
using PlotData = DerivedProp<Token, QVector<PointData>, [](auto& self, const auto& vec) {
|
||||
self.set_data(vec);
|
||||
}>;
|
||||
|
||||
template<class PlotWidget>
|
||||
concept trait = std::derived_from<PlotWidget, Token>;
|
||||
|
||||
CREEPER_DEFINE_CHECKER(trait);
|
||||
|
||||
using namespace widget::pro;
|
||||
using namespace theme::pro;
|
||||
} // namespace vector_widget::pro
|
||||
|
||||
struct VectorFieldPlot
|
||||
: public Declarative<vector_widget::internal::VectorPlot,
|
||||
CheckerOr<vector_widget::pro::checker, widget::pro::checker, theme::pro::checker>> {
|
||||
using Declarative::Declarative;
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
};
|
||||
} // namespace creeper
|
||||
Reference in New Issue
Block a user