762 lines
38 KiB
C++
762 lines
38 KiB
C++
#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;
|
||
}
|