Files
Radio/module/radio/Tool.h
T
2026-08-02 14:20:28 +08:00

762 lines
38 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include <algorithm>
#include <QApplication>
#include <QColorDialog>
#include <QComboBox>
#include <QDebug>
#include <QFontMetrics>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QMenu>
#include <QPushButton>
#include <QRandomGenerator>
#include <QScrollArea>
#include <QWidgetAction>
namespace renderive {
static Time_Of_Day current_time_of_day() {
return renderive::qt_to_time_of_day(QTime::currentTime());
}
static QColor get_color(int lowest, int highest) {
int r = QRandomGenerator::global()->bounded(lowest, highest);
int g = QRandomGenerator::global()->bounded(lowest, highest);
int b = QRandomGenerator::global()->bounded(lowest, highest);
return {r, g, b};
}
static QString get_background_style_sheet() {
QString color = QString("background-color: %1;").arg(get_color(176, 256).name());
return color;
}
static QString get_button_style_sheet() {
QString color = QString("background-color: %1; color: #000000;").arg(get_color(200, 256).name());
return color;
}
template <typename T>
QString get_init_value(const T& value) {
return QString::number(value);
}
template <>
inline QString get_init_value<QString>(const QString& value) {
return value;
}
template <typename T>
T get_value_from_string(const QString& value) {
return value.toDouble();
}
template <>
inline QString get_value_from_string<QString>(const QString& value) {
return value;
}
template <typename T>
static QWidget* create_edit_widget_list(const QString& button_text,
const std::function<void(const std::vector<T>&)>& click, const std::vector<T>& init_values) {
auto container = new QWidget;
auto layout = new QHBoxLayout(container);
layout->setAlignment(Qt::AlignLeft);
layout->setContentsMargins(0, 0, 0, 0);
auto confirm = new QPushButton(button_text);
// QApplication* app = (QApplication*)QApplication::instance();
// qDebug() << "Global StyleSheet:" << app->styleSheet();
confirm->setStyleSheet(get_button_style_sheet());
// 清除 QSS
QFont font;
font.setFamily("Segoe UI");
confirm->setFont(font);
confirm->setMinimumWidth(QFontMetrics(confirm->font()).horizontalAdvance(button_text) + 8);
confirm->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
layout->addWidget(confirm);
std::vector<QLineEdit*> lineEditList;
for (const T& init_value : init_values) {
QString init_value_str = get_init_value<T>(init_value);
auto cur_edit = new QLineEdit(init_value_str);
cur_edit->setStyleSheet(get_button_style_sheet());
// cur_edit->setMaximumWidth(50);
auto fm = QFontMetrics(QFont());
int width = fm.horizontalAdvance(init_value_str);
// cur_edit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
cur_edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
int w = qMax((int)((double)width * 1.4) + 16, 50);
cur_edit->setMinimumWidth(w);
lineEditList.push_back(cur_edit);
layout->addWidget(cur_edit);
}
QObject::connect(confirm, &QPushButton::clicked, [lineEditList, click]() {
std::vector<T> values;
for (QLineEdit* line_edit : lineEditList) {
values.push_back(get_value_from_string<T>(line_edit->text()));
}
click(values);
});
return container;
}
template <typename T>
static QWidget* create_edit_widget(const QString& button_text,
const std::function<void(const T&)>& click, const T& init_values) {
return create_edit_widget_list<T>(button_text, [click](const std::vector<T>& data) {
click(data.front());
}, std::vector<T>{init_values});
}
static QWidget* create_range(Axis* axis, const QString& text = "更改轴范围") {
return create_edit_widget_list<double>(text, [axis](const std::vector<double>& values) {
axis->set_coord_range(Range{values[0], values[1]});
},
{axis->coord_range().origin, axis->coord_range().target});
}
static QMenu* find_parent_menu(QWidget* widget) {
// 从当前窗口开始,逐步检查父窗口
QWidget* parent = widget->parentWidget();
while (parent) {
if (QMenu* menu = qobject_cast<QMenu*>(parent)) {
return menu; // 找到第一个 QMenu 类型的父窗口
}
parent = parent->parentWidget();
}
return nullptr; // 如果没有找到 QMenu 类型的父窗口
}
static QWidget* create_select_color(const QString& text, const std::function<void(QColor)>& click, const QColor& color = QColor()) {
auto ret = new QWidget;
auto l = new QHBoxLayout(ret);
l->setContentsMargins(0, 0, 0, 0);
// l->setSpacing(0);
QString bs = get_button_style_sheet();
auto show_color = new QWidget;
show_color->setStyleSheet(QString("background-color: %1; border: 2px solid #000000;").arg(color.name(QColor::HexArgb)));
show_color->setFixedWidth(30);
static QPushButton* btn = nullptr;
// static auto dialog = new CustomColorDialog(Qt::white, QApplication::activeWindow());
static auto dialog = new Select_Color_Dialog;
dialog->resize(800, 600);
// dialog->adjustSize();
auto label = new QLineEdit(color.isValid() ? color.name(QColor::HexArgb) : "无效");
label->setAlignment(Qt::AlignCenter);
label->setStyleSheet("background-color: #ffffff; color: #000000;");
// label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
auto button = new QPushButton(text);
button->setStyleSheet(bs);
QObject::connect(button, &QPushButton::clicked, [button, label]() {
btn = button;
dialog->set_current_color(QColor(label->text()));
dialog->show();
});
QObject::connect(dialog, &QDialog::finished, [ret, button, click, label, show_color](int result) {
if (btn != button)
return;
if (result == QDialog::Accepted) {
QColor select_color = dialog->current_color();
click(select_color);
label->setText(select_color.name(QColor::HexArgb));
show_color->setStyleSheet(QString("background-color: %1; border: 2px solid #000000;")
.arg(select_color.name(QColor::HexArgb)));
}
else if (result == -1) {
click(QColor());
label->setText("无颜色");
show_color->setStyleSheet(QString("background-color: rgba(255, 255, 255, 0); border: 2px solid #000000;"));
}
QMenu* menu = find_parent_menu(ret);
if (menu) {
menu->show();
}
});
l->addWidget(button);
l->addWidget(label);
l->addWidget(show_color);
return ret;
}
static QPushButton* create_button(const QString& text, const std::function<void(void)>& click) {
auto button = new QPushButton(text);
button->setStyleSheet(get_button_style_sheet());
QObject::connect(button, &QPushButton::clicked, [click]() {
click();
});
return button;
}
static QPushButton* create_toggle_button(const QString& text, const QString& text2, const std::function<void()>& click, bool first_state) {
auto button = new QPushButton(first_state ? text : text2);
button->setStyleSheet(get_button_style_sheet());
QObject::connect(button, &QPushButton::clicked, [button, click, text, text2]() {
click();
if (button->text() == text2) {
button->setText(text);
}
else {
button->setText(text2);
}
});
return button;
}
static QLabel* create_label(const QString& text, int h = 50, const QColor& color = Qt::black) {
auto l = new QLabel(text);
QFont font;
font.setFamily("Segoe UI");
font.setBold(true);
l->setFont(font);
l->setFixedHeight(h);
l->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
l->setStyleSheet(QString("color: %1;").arg(color.name(QColor::HexArgb)));
return l;
}
} // namespace renderive
template <typename... Vectors>
static std::vector<QWidget*> concat_widgets(const Vectors&... vectors) {
std::vector<QWidget*> result;
result.reserve((vectors.size() + ... + 0));
(result.insert(result.end(), vectors.begin(), vectors.end()), ...);
return result;
}
static std::vector<QWidget*> bw(const std::vector<QWidget*>& widgets, const QString& name) {
if (widgets.empty())
return {};
auto ret = new QWidget;
ret->setStyleSheet(renderive::get_background_style_sheet());
auto l = new QVBoxLayout(ret);
auto label = new QLabel(name);
label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
QFontMetrics fm(label->font());
label->setFixedSize(fm.horizontalAdvance(name) + 16, fm.height() + 8);
label->setStyleSheet(QString("color: %1; background-color: %2; padding: 0px; margin: 0px;")
.arg(
QColor(Qt::white).name(QColor::HexArgb),
QColor(Qt::black).name(QColor::HexArgb)));
l->addWidget(label, 0, Qt::AlignHCenter | Qt::AlignBottom);
for (QWidget* w : widgets) {
l->addWidget(w);
}
return {ret};
}
template <typename T>
static QWidget* create_line_interpolation_combo(T* renderable) {
auto container = new QWidget;
auto layout = new QHBoxLayout(container);
layout->setContentsMargins(0, 0, 0, 0);
auto label = new QLabel("线图插值");
auto combo = new QComboBox;
label->setStyleSheet(renderive::get_button_style_sheet());
combo->setStyleSheet(renderive::get_button_style_sheet());
combo->addItem("Nearest_Bin", static_cast<int>(renderive::Line_Interpolation_Mode::Nearest_Sample));
combo->addItem("Linear_Display", static_cast<int>(renderive::Line_Interpolation_Mode::Linear_Value));
combo->addItem("Linear_Power", static_cast<int>(renderive::Line_Interpolation_Mode::Linear_Power_Domain));
combo->addItem("Step_Left", static_cast<int>(renderive::Line_Interpolation_Mode::Step_Left));
combo->addItem("Step_Right", static_cast<int>(renderive::Line_Interpolation_Mode::Step_Right));
combo->addItem("Cubic_Display", static_cast<int>(renderive::Line_Interpolation_Mode::Cubic_Value));
combo->setCurrentIndex(combo->findData(static_cast<int>(renderable->interpolation_mode())));
QObject::connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), [renderable, combo](int index) {
renderable->set_interpolation_mode(static_cast<renderive::Line_Interpolation_Mode>(combo->itemData(index).toInt()));
});
layout->addWidget(label);
layout->addWidget(combo);
return container;
}
static QWidget* create_image_interpolation_combo(renderive::Waterfall* waterfall) {
auto container = new QWidget;
auto layout = new QHBoxLayout(container);
layout->setContentsMargins(0, 0, 0, 0);
auto label = new QLabel("二维插值");
auto combo = new QComboBox;
label->setStyleSheet(renderive::get_button_style_sheet());
combo->setStyleSheet(renderive::get_button_style_sheet());
combo->addItem("Nearest", static_cast<int>(renderive::Image_Interpolation_Mode::Nearest));
combo->addItem("Bilinear", static_cast<int>(renderive::Image_Interpolation_Mode::Bilinear));
combo->addItem("Bicubic", static_cast<int>(renderive::Image_Interpolation_Mode::Bicubic));
combo->setCurrentIndex(combo->findData(static_cast<int>(waterfall->interpolation_mode())));
QObject::connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), [waterfall, combo](int index) {
waterfall->set_interpolation_mode(static_cast<renderive::Image_Interpolation_Mode>(combo->itemData(index).toInt()));
});
layout->addWidget(label);
layout->addWidget(combo);
return container;
}
static QWidget* create_control(renderive::Abs_Plot* plot, const std::vector<QWidget*>& widgets = {}) {
auto control = new QWidget;
auto l = new QVBoxLayout(control);
l->setAlignment(Qt::AlignTop);
l->setContentsMargins({0, 0, 0, 0});
l->setSpacing(0);
auto* core = renderive::plot_core(plot);
std::vector<QWidget*> ws = {
renderive::create_toggle_button("停止性能测试", "启动性能测试", [plot]() {
if (auto* current_core = renderive::plot_core(plot))
renderive::set_performance_overlay_enabled(*current_core, !renderive::performance_overlay_enabled(*current_core));
}, core ? renderive::performance_overlay_enabled(*core) : false),
renderive::create_select_color("更改背景色", [plot](const QColor& color) {
plot->set_background_color(color);
}, plot->background_color()),
};
if (auto latency_plot = dynamic_cast<renderive::Latency_Eager_Plot*>(plot)) {
ws.insert(ws.begin(), renderive::create_toggle_button("暂停渲染", "开始渲染", [latency_plot]() {
latency_plot->running() ? latency_plot->pause() : latency_plot->start();
}, latency_plot->running()));
ws.push_back(renderive::create_edit_widget_list<double>("最大渲染FPS", [latency_plot](std::vector<double> data) {
latency_plot->set_max_render_fps(data[0]);
}, {latency_plot->max_render_fps()}));
}
for (QWidget* cur : concat_widgets(bw(ws, "plot基础"), widgets)) {
l->addWidget(cur);
}
return control;
}
static std::vector<QWidget*> cw(renderive::Abs_Axis* it) {
if (it == nullptr)
return {};
auto t = std::vector<QWidget*>{
renderive::create_button("反转轴整体方向", [it]() {
it->set_orientation(it->orientation() == renderive::Orientation::Horizontal ? renderive::Orientation::Vertical : renderive::Orientation::Horizontal);
}),
renderive::create_edit_widget_list<int>("主刻度值", [it](const std::vector<int>& values) {
it->set_tick_length(values[0]);
},
{it->tick_length()}),
renderive::create_edit_widget_list<int>("子刻度值", [it](const std::vector<int>& values) {
it->set_sub_tick_length(values[0]);
},
{it->sub_tick_length()}),
renderive::create_select_color("更改轴颜色", [it](const QColor& color) {
it->set_color(renderive::qt_to_color(color));
}, renderive::to_qcolor(it->color())),
renderive::create_edit_widget_list<QString>("设置单位", [it](const std::vector<QString>& values) {
it->set_unit_text(renderive::qt_to_string(values[0]));
}, {renderive::to_qstring(it->unit_text())}),
renderive::create_select_color("更改UnitText颜色", [it](const QColor& color) {
it->set_unit_text_pen(renderive::qt_to_pen(color));
}, renderive::to_qcolor(it->unit_text_pen().color)),
renderive::create_select_color("更改UnitText背景色", [it](const QColor& color) {
it->set_unit_text_background_brush(renderive::qt_to_brush(color));
}, renderive::to_qcolor(it->unit_text_background_brush().color)),
renderive::create_edit_widget_list<int>("更改刻度斜度", [it](const std::vector<int>& values) {
it->set_label_rotation_degrees(values[0]);
}, {it->label_rotation_degrees()}),
};
return t;
}
static std::vector<QWidget*> cw(renderive::Axis* it) {
if (it == nullptr)
return {};
auto t = std::vector<QWidget*>{
renderive::create_range(it),
};
return concat_widgets(cw(dynamic_cast<renderive::Abs_Axis*>(it)), t);
}
static std::vector<QWidget*> cw(renderive::Frequency_Axis* it) {
if (it == nullptr)
return {};
auto t = std::vector<QWidget*>{};
return concat_widgets(cw(dynamic_cast<renderive::Axis*>(it)), t);
}
static std::vector<QWidget*> cw(renderive::Time_Axis* it, int num_pre_second = -1) {
if (it == nullptr)
return {};
auto t = std::vector<QWidget*>{
renderive::create_edit_widget_list<QString>("时间格式", [it](std::vector<QString> data) {
it->set_time_format(renderive::qt_to_string(data[0]));
},
{renderive::to_qstring(it->time_format())}),
renderive::create_edit_widget_list<int>("单位间隔pixel", [it](std::vector<int> data) {
it->set_tick_label_spacing_px(data[0]);
},
{it->tick_label_spacing_px()}),
};
auto timer = new QTimer(QApplication::instance());
if (num_pre_second > 0)
timer->start(static_cast<int>(1000.0 / static_cast<double>(num_pre_second)));
QObject::connect(timer, &QTimer::timeout, [it]() {
it->append_time(renderive::current_time_of_day());
});
t.push_back(renderive::create_edit_widget_list<double>("推数据Timer(次/s", [timer](std::vector<double> data) {
if (data[0] < 0) {
timer->stop();
}
else {
timer->start((int)(1000.0 / data[0]));
}
},
{timer->interval() > 0 ? 1000.0 / timer->interval() : -1}));
std::vector<QWidget*> axis_widgets = cw(dynamic_cast<renderive::Abs_Axis*>(it));
t.insert(t.end(), axis_widgets.begin(), axis_widgets.end());
return t;
}
static std::vector<QWidget*> cw(renderive::Selection_Rectangle_Overlay* it) {
if (it == nullptr)
return {};
auto t = std::vector<QWidget*>{
renderive::create_select_color("更改填充色", [it](const QColor& color) {
it->set_selection_brush(renderive::qt_to_brush(color));
}, renderive::to_qcolor(it->selection_brush().color)),
renderive::create_select_color("更改边框色", [it](const QColor& color) {
qDebug() << " color.isValid() == " << color.isValid();
auto pen = renderive::qt_to_pen(color);
pen.style = renderive::Line_Style::Dash;
it->set_selection_border_pen(pen);
qDebug() << " color.isValid() == " << renderive::to_qcolor(pen.color).isValid();
}, renderive::to_qcolor(it->selection_border_pen().color)),
renderive::create_select_color("更改字色", [it](const QColor& color) {
it->set_label_pen(renderive::qt_to_pen(color));
}, renderive::to_qcolor(it->label_pen().color))
};
return t;
}
template <typename T>
static std::vector<QWidget*> cw(renderive::Hover_Tooltip_Mixin<T>* it) {
if (it == nullptr)
return {};
auto t = std::vector<QWidget*>{
renderive::create_label("悬浮信息"),
renderive::create_toggle_button("启动悬浮信息", "停止悬浮信息", [it]() {
it->set_use_hover_info(!it->hover_tooltip_enabled());
}, !it->hover_tooltip_enabled()),
renderive::create_select_color("设置文字颜色", [it](const QColor& c) {
it->set_tooltip_text_pen(renderive::qt_to_pen(c));
}, renderive::to_qcolor(it->tooltip_text_pen().color)),
renderive::create_select_color("设置背景颜色", [it](const QColor& c) {
it->set_hover_tooltip_background_brush(renderive::qt_to_brush(c));
}, renderive::to_qcolor(it->hover_info_background_brush().color))
};
return t;
}
static std::vector<QWidget*> cw(renderive::Waterfall* it, int num_pre_second = -1) {
if (it == nullptr)
return {};
auto timer = new QTimer(QApplication::instance());
if (num_pre_second > 0)
timer->start(static_cast<int>(1000.0 / static_cast<double>(num_pre_second)));
QObject::connect(timer, &QTimer::timeout, [it]() {
std::vector<double> d = renderive::get_data(it->power_range(), it->frequency_bin_count());
it->append_row(renderive::current_time_of_day(), d);
});
auto t = std::vector<QWidget*>{
renderive::create_toggle_button("关闭可见区裁剪", "开启可见区裁剪", [it]() {
it->set_visible_range_only(!it->visible_range_only());
}, it->visible_range_only()),
create_image_interpolation_combo(it),
renderive::create_edit_widget_list<double>("推数据Timer(次/s", [timer](std::vector<double> data) {
if (data[0] < 0) {
timer->stop();
}
else {
timer->start((int)(1000.0 / data[0]));
}
}, {timer->interval() > 0 ? 1000.0 / timer->interval() : -1}),
};
std::vector<QWidget*> hover_widgets = cw(static_cast<renderive::Hover_Tooltip_Mixin<renderive::Waterfall>*>(it));
t.insert(t.end(), hover_widgets.begin(), hover_widgets.end());
return t;
}
static std::vector<QWidget*> cw(renderive::Frequency_Trace* it, int num_pre_second = -1) {
if (it == nullptr)
return {};
auto timer = new QTimer(QApplication::instance());
if (num_pre_second > 0)
timer->start(static_cast<int>(1000.0 / static_cast<double>(num_pre_second)));
QObject::connect(timer, &QTimer::timeout, [it]() {
it->append_sample(renderive::current_time_of_day(), renderive::get_data({0, 20}));
});
auto t = std::vector<QWidget*>{
renderive::create_edit_widget_list<double>("推数据Timer(次/s", [timer](std::vector<double> data) {
if (data[0] < 0) {
timer->stop();
}
else {
timer->start((int)(1000.0 / data[0]));
}
},
{timer->interval() > 0 ? 1000.0 / timer->interval() : -1}),
};
return t;
}
static std::vector<QWidget*> cw(renderive::Constellation_Diagram* it, int num_pre_second = -1) {
if (it == nullptr)
return {};
auto timer = new QTimer(QApplication::instance());
QObject::connect(timer, &QTimer::timeout, [it]() {
for (int i = 0; i < 10; ++i) {
double x = renderive::get_data(it->i_range());
double y = renderive::get_data(it->q_range());
it->append_point({x, y});
}
});
if (num_pre_second > 0)
timer->start(static_cast<int>(1000.0 / static_cast<double>(num_pre_second)));
auto t = std::vector<QWidget*>{
renderive::create_edit_widget_list<double>("推数据Timer(次/s", [timer](std::vector<double> data) {
if (data[0] < 0) {
timer->stop();
}
else {
timer->start((int)(1000.0 / data[0]));
}
},
{timer->interval() > 0 ? 1000.0 / timer->interval() : -1}),
renderive::create_edit_widget_list<int>("设置持续时间(ms)", [it](std::vector<int> data) {
it->set_point_lifetime_ms(data[0]);
},
{it->point_lifetime_ms()}),
renderive::create_select_color("更改IQ点颜色", [it](const QColor& color) {
it->set_point_color(renderive::qt_to_color(color));
}, renderive::to_qcolor(it->point_color())),
renderive::create_select_color("更改锚点颜色", [it](const QColor& color) {
it->set_anchor_color(renderive::qt_to_color(color));
}, renderive::to_qcolor(it->anchor_color())),
renderive::create_edit_widget_list<double>("I范围", [it](std::vector<double> data) {
it->set_i_range({data[0], data[1]});
}, {it->i_range().origin, it->i_range().target}),
renderive::create_edit_widget_list<double>("Q范围", [it](std::vector<double> data) {
it->set_q_range({data[0], data[1]});
}, {it->q_range().origin, it->q_range().target}),
renderive::create_button("设置到轴中心", [it]() {
it->fit_square_to_axes();
}),
};
return t;
}
static std::vector<QWidget*> cw(renderive::Afterglow* it, int num_pre_second = -1) {
if (it == nullptr)
return {};
static auto create_base_data = [it]() {
renderive::Range r = it->power_range();
std::vector<double> ret(it->frequency_point_size());
ret[0] = get_data(r);
for (int i = 1; i < it->frequency_point_size(); ++i) {
double rate;
if (i % 20 == 0) {
double that = qAbs(ret[i - 1] - r.origin) / r.size() - 0.5;
rate = (1.0 - that) * renderive::get_data({0.8, 1.2});
}
else {
rate = renderive::get_data({0.8, 1.2});
}
ret[i] = std::clamp(ret[i - 1] * rate, r.origin, r.target);
}
return ret;
};
static std::vector<double> base_data = create_base_data();
auto timer = new QTimer(QApplication::instance());
QObject::connect(timer, &QTimer::timeout, [it]() {
renderive::Range r = it->power_range();
int n = base_data.size();
std::vector<double> cur_data(n);
for (int i = 0; i < n; ++i) {
double rate = renderive::get_data({0.8, 1.2});
cur_data[i] = std::clamp(base_data[i] * rate, r.origin, r.target);
}
it->append_spectrum(cur_data);
});
if (num_pre_second > 0)
timer->start(static_cast<int>(1000.0 / static_cast<double>(num_pre_second)));
auto t = std::vector<QWidget*>{
renderive::create_edit_widget_list<double>("推数据Timer(次/s", [timer](std::vector<double> data) {
if (data[0] < 0) {
timer->stop();
}
else {
timer->start((int)(1000.0 / data[0]));
}
},
{timer->interval() > 0 ? 1000.0 / timer->interval() : -1}),
renderive::create_edit_widget_list<double>("频率范围", [it](std::vector<double> data) {
it->set_frequency_range({data[0], data[1]});
},
{it->frequency_range().origin, it->frequency_range().target}),
renderive::create_edit_widget_list<double>("功率概率范围", [it](std::vector<double> data) {
it->set_power_range({data[0], data[1]});
},
{it->power_range().origin, it->power_range().target}),
renderive::create_button("更改基础线", []() {
base_data = create_base_data();
}),
};
return t;
}
static std::vector<QWidget*> cw(renderive::Spectrum* it, int num_pre_second = -1) {
if (it == nullptr)
return {};
auto timer = new QTimer(QApplication::instance());
if (num_pre_second > 0)
timer->start(static_cast<int>(1000.0 / static_cast<double>(num_pre_second)));
QObject::connect(timer, &QTimer::timeout, [it]() {
it->update_samples(renderive::get_data(it->power_axis()->coord_range(), it->frequency_point_size()));
});
auto t = std::vector<QWidget*>{
renderive::create_toggle_button("关闭可见区裁剪", "开启可见区裁剪", [it]() {
it->set_visible_range_only(!it->visible_range_only());
}, it->visible_range_only()),
create_line_interpolation_combo(it),
renderive::create_edit_widget_list<double>("推数据Timer(次/s", [timer](std::vector<double> data) {
if (data[0] < 0) {
timer->stop();
}
else {
timer->start((int)(1000.0 / data[0]));
}
}, {timer->interval() > 0 ? 1000.0 / timer->interval() : -1}),
renderive::create_edit_widget_list<double>("频率范围", [it](std::vector<double> data) {
it->set_frequency_range({data[0], data[1]});
}, {it->frequency_range().origin, it->frequency_range().target}),
renderive::create_edit_widget_list<int>("设置频率点数", [it](std::vector<int> data) {
it->set_frequency_point_size(data[0]);
}, {it->frequency_point_size()}),
renderive::create_label("sweepRect"),
renderive::create_toggle_button("停止sweepRect", "启动sweepRect", [it]() {
it->set_sweep_region_visible(!it->sweep_region_visible());
}, it->sweep_region_visible()),
renderive::create_edit_widget_list<double>("sweepRect 范围", [it](std::vector<double> data) {
if (!it->sweep_region_visible()) it->set_sweep_region_visible(true);
it->set_sweep_frequency_range({data[0], data[1]});
}, {it->sweep_frequency_range().origin, it->sweep_frequency_range().target}),
renderive::create_edit_widget_list<double>("中频", [it](std::vector<double> data) {
if (!it->sweep_region_visible()) it->set_sweep_region_visible(true);
it->set_center_frequency(data[0]);
}, {it->center_frequency()}),
renderive::create_select_color("扫频矩形", [it](const QColor& c) {
it->set_sweep_region_brush(renderive::qt_to_brush(c));
}),
renderive::create_select_color("中频", [it](const QColor& c) {
if (!c.isValid()) {
it->set_middle_frequency_pen(renderive::Pen{.style = renderive::Line_Style::None});
return;
}
it->set_middle_frequency_pen(renderive::qt_to_pen(c));
}, renderive::to_qcolor(it->middle_frequency_pen().color)),
renderive::create_label("marker"),
renderive::create_toggle_button("停止最大值marker", "启动最大值marker", [it]() {
it->set_max_marker_visible(!it->max_marker_visible());
}, it->max_marker_visible()),
renderive::create_toggle_button("停止最小值marker", "启动最小值marker", [it]() {
it->set_use_min_marker(!it->use_min_marker());
}, it->use_min_marker()),
renderive::create_edit_widget_list<double>("添加自定义marker", [it](std::vector<double> data) {
it->add_custom_marker(data[0]);
}, {0}),
renderive::create_edit_widget_list<double>("添加自定义Linemarker", [it](std::vector<double> data) {
it->add_custom_line_marker(data[0]);
}, {0}),
renderive::create_edit_widget_list<double>("删除marker", [it](std::vector<double> data) {
it->remove_custom_marker(data[0]);
}, {0}),
renderive::create_edit_widget_list<double>("清楚所有marker", [it](std::vector<double> data) {
it->clear_custom_markers();
}, {}),
renderive::create_edit_widget_list<int>("选择当前marker", [it](std::vector<int> data) {
it->set_selected_marker_index(data[0]);
}, {0}),
renderive::create_edit_widget_list<double>("选择下一个marker", [it](std::vector<double> data) {
it->select_next_marker();
}, {}),
renderive::create_edit_widget_list<double>("选择上一个marker", [it](std::vector<double> data) {
it->select_previous_marker();
}, {}),
renderive::create_label("当前线"),
renderive::create_select_color("当前线色", [it](const QColor& c) {
if (!c.isValid()) {
it->set_current_pen(renderive::Pen{.style = renderive::Line_Style::None});
return;
}
it->set_current_pen(renderive::qt_to_pen(c));
}, renderive::to_qcolor(it->current_pen().color)),
renderive::create_select_color("当前线填充色", [it](const QColor& c) {
it->set_current_brush(renderive::qt_to_brush(c));
}, renderive::to_qcolor(it->current_brush().color)),
renderive::create_label("最大值线"),
renderive::create_toggle_button("停止最大值线", "启动最大值线", [it]() {
it->set_max_hold_visible(!it->max_hold_visible());
}, it->max_hold_visible()),
renderive::create_select_color("最大值线色", [it](const QColor& c) {
if (!c.isValid()) {
it->set_max_pen(renderive::Pen{.style = renderive::Line_Style::None});
return;
}
it->set_max_pen(renderive::qt_to_pen(c));
}, renderive::to_qcolor(it->max_pen().color)),
renderive::create_select_color("最大值线填充色", [it](const QColor& c) {
it->set_max_brush(renderive::qt_to_brush(c));
}, renderive::to_qcolor(it->max_brush().color)),
renderive::create_label("最小值线"),
renderive::create_toggle_button("停止最小值线", "启动最小值线", [it]() {
it->set_min_hold_visible(!it->min_hold_visible());
}, it->min_hold_visible()),
renderive::create_select_color("最小值线色", [it](const QColor& c) {
it->set_min_pen(renderive::qt_to_pen(c));
}, renderive::to_qcolor(it->min_pen().color)),
renderive::create_select_color("最小值线填充色", [it](const QColor& c) {
it->set_min_brush(renderive::qt_to_brush(c));
}, renderive::to_qcolor(it->min_brush().color)),
};
return concat_widgets(cw(static_cast<renderive::Hover_Tooltip_Mixin<renderive::Spectrum>*>(it)), t);
}
static std::vector<QWidget*> cw(renderive::Sweep_Spectrum* it, int num_pre_second = -1) {
if (it == nullptr)
return {};
auto timer = new QTimer(QApplication::instance());
if (num_pre_second > 0)
timer->start(static_cast<int>(1000.0 / static_cast<double>(num_pre_second)));
QObject::connect(timer, &QTimer::timeout, [it]() {
it->append_block(renderive::get_data(it->power_axis()->coord_range(), it->bins_per_block()));
});
auto t = std::vector<QWidget*>{
renderive::create_toggle_button("关闭可见区裁剪", "开启可见区裁剪", [it]() {
it->set_visible_range_only(!it->visible_range_only());
}, it->visible_range_only()),
create_line_interpolation_combo(it), renderive::create_edit_widget_list<double>("推数据Timer(次/s", [timer](std::vector<double> data) {
if (data[0] < 0) {
timer->stop();
}
else {
timer->start((int)(1000.0 / data[0]));
}
}, {timer->interval() > 0 ? 1000.0 / timer->interval() : -1}),
renderive::create_select_color("线颜色", [it](const QColor& color) {
it->set_pen(renderive::qt_to_pen(color));
}, renderive::to_qcolor(it->pen().color)),
renderive::create_select_color("扫频线颜色", [it](const QColor& color) {
auto p = it->cur_frequency_pen();
p.color = renderive::qt_to_color(color);
it->set_cur_frequency_pen(p);
}, renderive::to_qcolor(it->cur_frequency_pen().color)),
renderive::create_edit_widget_list<double>("频率范围", [it](const std::vector<double>& data) {
it->set_frequency_range({data[0], data[1]});
}, {it->frequency_range().origin, it->frequency_range().target})
};
return t;
}
static QMenu* create_menu(renderive::Abs_Plot* plot, const std::vector<QWidget*>& widgets) {
auto menu = new QMenu(plot);
menu->setObjectName("memu");
// menu->setStyle(nullptr);
menu->hide();
menu->setContentsMargins(0, 0, 0, 0);
auto container = create_control(plot, widgets);
auto scroll_area = new QScrollArea;
scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scroll_area->setContentsMargins(0, 0, 0, 0);
scroll_area->setWidget(container);
scroll_area->setWidgetResizable(true);
scroll_area->setObjectName("scroll_area");
auto scrollAction = new QWidgetAction(menu);
scrollAction->setDefaultWidget(scroll_area);
menu->addAction(scrollAction);
return menu;
}
static QMenu* create_menu_normal(QWidget* w, const std::vector<QWidget*>& widgets) {
auto menu = new QMenu(w);
menu->setObjectName("memu_normal");
// menu->setStyle(nullptr);
menu->hide();
menu->setContentsMargins(0, 0, 0, 0);
auto container = new QWidget;
auto l = new QVBoxLayout(container);
l->setAlignment(Qt::AlignTop);
l->setContentsMargins({0, 0, 0, 0});
l->setSpacing(4);
for (auto widget : widgets) {
l->addWidget(widget);
}
auto scroll_area = new QScrollArea;
scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scroll_area->setContentsMargins(0, 0, 0, 0);
scroll_area->setWidget(container);
scroll_area->setWidgetResizable(true);
scroll_area->setObjectName("scrollArea2");
auto scrollAction = new QWidgetAction(menu);
scrollAction->setDefaultWidget(scroll_area);
menu->addAction(scrollAction);
return menu;
}