#include "RadioWidget.h" #include #include #include #include "../component/FrequentShower.h" #include "../component/ProgressBar.h" #include "../Global.h" #include "../menu/BaseWidgetMenu.h" #include "BackEnd.h" #include "../BackEnd/MainWidget.h" #include "../../../third_party/Renderive/Demo_Gallery/base/Tool.h" static bool use_Performance_shower = false; static double max = 160; static renderive::Range frequent_range = {-12000, 12000}; static bool radio_mock_perf_mode() { bool ok = false; int value = qEnvironmentVariableIntValue("RADIO_MOCK_PERF_MODE", &ok); return ok ? value != 0 : true; } static bool radio_show_performance_overlay() { bool ok = false; int value = qEnvironmentVariableIntValue("RADIO_SHOW_PERFORMANCE_OVERLAY", &ok); return ok ? value != 0 : false; } static void configure_radio_plot_perf(renderive::Latency_Eager_Plot* plot) { if (!radio_mock_perf_mode()) return; plot->set_max_render_fps(1000); } QWidget* Radio_Widget::create_spectrogram_power_plot() { class Spectrum_Plot : public renderive::Latency_Eager_Plot { public: std::shared_ptr x_axis{}; std::shared_ptr y_axis{}; std::shared_ptr msr{}; std::shared_ptr sp{}; QMenu* menu{}; void init() override { Latency_Eager_Plot::init(); configure_radio_plot_perf(this); object_name = "Spectrum_Plot"; auto data = create_renderable_node(get_root_renderable(), "Data_Renderable"); // auto frequency_axis_cache = create_renderable_node(get_root_renderable(), "Frequency_Axis_Cache"); // auto power_axis_cache = create_renderable_node(get_root_renderable(), "Power_Axis_Cache"); // frequency_axis_cache->set_cache_mode(renderive::Renderable_Cache_Mode::Local_Pixel); // power_axis_cache->set_cache_mode(renderive::Renderable_Cache_Mode::Local_Pixel); auto axis_cache = create_renderable_node(get_root_renderable(), "Power_Axis_Cache"); axis_cache->set_cache_mode(renderive::Renderable_Cache_Mode::Local_Pixel); auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); x_axis = renderive::Frequency_Axis::Builder(axis_cache, Qt::Horizontal) .set_coord_range(frequent_range) .set_tick_length(-10) .build(); y_axis = renderive::Axis::Builder(axis_cache, Qt::Vertical) .set_coord_range({max, 0}) .set_unit_text("功率") .build(); sp = renderive::Spectrum::Builder(data, x_axis, y_axis) .set_frequency_range(frequent_range) .set_frequency_point_size(1024) .build(); msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); } protected: void resizeEvent(QResizeEvent* event) override { x_axis->set_x(0); x_axis->set_y(height() - 1); x_axis->set_pixel_size(width()); y_axis->set_x(0); y_axis->set_y(0); y_axis->set_pixel_size(height()); } void contextMenuEvent(QContextMenuEvent* event) override { if (!menu) { auto ws = concat_widgets( bw(cw(sp.get(), -1), "频谱图"), bw(cw(x_axis.get()), "频率x轴"), bw(cw(y_axis.get()), "功率y轴"), bw(cw(msr.get()), "多选框")); menu = create_menu(this, ws); } menu->exec(event->globalPos()); } }; auto w = new Spectrum_Plot; w->init(); spectrogram_line = w->sp; if (!radio_mock_perf_mode()) { progress_bar1->set_value = [this]() { double middle_frequent = this->spectrogram_line->frequency_range().middle(); bool ok = false; double power = spectrogram_line->get_power(middle_frequent, ok); if (ok) this->progress_bar1->setValue(power); }; } return w; } QWidget* Radio_Widget::create_water_fall_plot() { class Water_Fall_Plot : public renderive::Latency_Eager_Plot { public: std::shared_ptr x_axis{}; std::shared_ptr y_axis{}; std::shared_ptr msr{}; std::shared_ptr wf{}; QMenu* menu{}; void init() override { Latency_Eager_Plot::init(); configure_radio_plot_perf(this); object_name = "Water_Fall_Plot"; auto stream_cache = create_renderable_node(get_root_renderable(), "Waterfall_Stream_Cache"); auto data = create_renderable_node(stream_cache, "Data_Renderable"); auto time_axis = create_renderable_node(stream_cache, "Time_Axis_Renderable"); auto frequency_axis_cache = create_renderable_node(get_root_renderable(), "Frequency_Axis_Cache"); auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); stream_cache->set_cache_mode(renderive::Renderable_Cache_Mode::Local_Pixel); frequency_axis_cache->set_cache_mode(renderive::Renderable_Cache_Mode::Local_Pixel); x_axis = renderive::Frequency_Axis::Builder(frequency_axis_cache, Qt::Horizontal) .set_tick_length(-10) .set_sub_tick_length(-5) .set_coord_range(frequent_range) .build(); y_axis = renderive::Time_Axis::Builder(time_axis, Qt::Vertical) .set_time_point_size(100) .build(); wf = renderive::Waterfall::Builder(data, x_axis, y_axis) .set_frequency_range(frequent_range) .set_frequency_point_size(1024) .set_power_range({0, max}) .build(); msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); } protected: void resizeEvent(QResizeEvent* event) override { x_axis->set_x(0); x_axis->set_y(height()); x_axis->set_pixel_size(width()); y_axis->set_x(0); y_axis->set_y(0); y_axis->set_pixel_size(height()); } void contextMenuEvent(QContextMenuEvent* event) override { if (!menu) { auto ws = concat_widgets( bw(cw(wf.get(), -1), "瀑布图"), bw(cw(x_axis.get()), "频率轴"), bw(cw(y_axis.get()), "时间轴"), bw(cw(msr.get()), "多选框")); menu = create_menu(this, ws); } menu->exec(event->globalPos()); } }; auto w = new Water_Fall_Plot; w->init(); water_fall = w->wf; return w; } QWidget* Radio_Widget::create_audio_spectrogram_plot() { class Spectrum_Plot : public renderive::Latency_Eager_Plot { public: std::shared_ptr x_axis{}; std::shared_ptr y_axis{}; std::shared_ptr msr{}; std::shared_ptr sp{}; QMenu* menu{}; void init() override { Latency_Eager_Plot::init(); configure_radio_plot_perf(this); object_name = "Spectrum_Plot"; auto data = create_renderable_node(get_root_renderable(), "Data_Renderable"); auto frequency_axis_cache = create_renderable_node(get_root_renderable(), "Frequency_Axis_Cache"); auto power_axis_cache = create_renderable_node(get_root_renderable(), "Power_Axis_Cache"); auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); frequency_axis_cache->set_cache_mode(renderive::Renderable_Cache_Mode::Local_Pixel); power_axis_cache->set_cache_mode(renderive::Renderable_Cache_Mode::Local_Pixel); x_axis = renderive::Frequency_Axis::Builder(frequency_axis_cache, Qt::Horizontal) .set_coord_range({-12000, 12000}) .set_tick_length(-10) .set_sub_tick_length(-5) .build(); y_axis = renderive::Axis::Builder(power_axis_cache, Qt::Vertical) .set_coord_range({12000, -12000}) .set_unit_text("功率").build(); sp = renderive::Spectrum::Builder(data, x_axis, y_axis) .set_frequency_range({-12000, 12000}) .set_frequency_point_size(512) .build(); msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); } protected: void resizeEvent(QResizeEvent* event) override { x_axis->set_x(0); x_axis->set_y(height() - 1); x_axis->set_pixel_size(width()); y_axis->set_x(0); y_axis->set_y(0); y_axis->set_pixel_size(height()); } void contextMenuEvent(QContextMenuEvent* event) override { if (!menu) { auto ws = concat_widgets( bw(cw(sp.get(), -1), "频谱图"), bw(cw(x_axis.get()), "频率x轴"), bw(cw(y_axis.get()), "功率y轴"), bw(cw(msr.get()), "多选框")); menu = create_menu(this, ws); } menu->exec(event->globalPos()); } }; auto w = new Spectrum_Plot; w->init(); audio_spectrogram_plot = w->sp; return w; } QWidget* Radio_Widget::create_time_power_plot() { class Audio_Plot : public renderive::Latency_Eager_Plot { public: std::shared_ptr x_axis{}; std::shared_ptr y_axis{}; std::shared_ptr audio{}; std::shared_ptr msr{}; QMenu* menu{}; void init() override { Latency_Eager_Plot::init(); configure_radio_plot_perf(this); object_name = "Audio_Plot"; auto stream_cache = create_renderable_node(get_root_renderable(), "Audio_Stream_Cache"); auto data = create_renderable_node(stream_cache, "Data_Renderable"); auto time_axis = create_renderable_node(stream_cache, "Time_Axis_Renderable"); auto power_axis_cache = create_renderable_node(get_root_renderable(), "Power_Axis_Cache"); auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); stream_cache->set_cache_mode(renderive::Renderable_Cache_Mode::Local_Pixel); power_axis_cache->set_cache_mode(renderive::Renderable_Cache_Mode::Local_Pixel); x_axis = renderive::Time_Axis::Builder(time_axis, Qt::Horizontal) .set_tick_length(-10) .set_sub_tick_length(-5) .build(); y_axis = renderive::Axis::Builder(power_axis_cache, Qt::Vertical) .set_coord_range({12000, -12000}) .build(); audio = renderive::Audio_Frequency::Builder(data, x_axis, y_axis) .build(); msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); } protected: void resizeEvent(QResizeEvent* event) override { x_axis->set_x(0); x_axis->set_y(height() - 1); x_axis->set_pixel_size(width()); y_axis->set_x(0); y_axis->set_y(0); y_axis->set_pixel_size(height()); x_axis->set_time_point_size(x_axis->get_pixel_point_size()); } void contextMenuEvent(QContextMenuEvent* event) override { if (!menu) { auto ws = concat_widgets( bw(cw(audio.get(), -1), "音频图"), bw(cw(y_axis.get()), "功率y轴"), bw(cw(x_axis.get()), "时间轴"), bw(cw(msr.get()), "多选框")); menu = create_menu(this, ws); } menu->exec(event->globalPos()); } }; auto w = new Audio_Plot; w->init(); time_power = w->audio; return w; } //am, atu, vsql, nb, nr, dnf, pre, att, spl, fil1, agc_a Radio_Widget::Radio_Widget(QWidget* parent) : Base_Widget(parent) { setObjectName("电台界面"); voice_value = Back_End::instance()->YsGetAfGain(); rf_gain_value = Back_End::instance()->YsGetRfGain(); int font_size = 20; m1 = create_normal("RF Gain\n" + QString::number(rf_gain_value), font_size); m2 = create_normal("FFT SPAN\n100K", font_size); m3 = create_normal("频率表\n(12)89.6MHZ", font_size); m4 = create_normal("MODEM\nRTTY", font_size); m5 = create_normal("FIL1\n20K", font_size); m6 = create_normal("MSG1\n", font_size); select_value_widget = new Frequent_Shower(this); int n = 5; std::vector tick_list(n); double space = 100.0 / n; for (int i = 0; i < n; ++i) { tick_list[i] = i * space; } QColor orange(255, 165, 0); progress_bar1 = new Progress_Bar({ Tick("S", Qt::black), {"3", Qt::black}, {"6", Qt::black}, {"9", Qt::black}, {"20", Qt::black}, {"40", orange}, {"60", orange}, {"100", orange}, {"+160", Qt::red}, }, this); progress_bar2 = new Progress_Bar({ {"1", Qt::black}, {"2", Qt::yellow}, {"3", Qt::red}, {">5", Qt::red}, }, this); progress_bar1->tick_space_w = 2.0f; auto main = create_vbox_layout({}, this); main->addStretch(1); { // 中心Layout auto center = create_hbox_layout(); main->addLayout(center, 7); auto front = create_vbox_layout(); center->addLayout(front, 1); front->addWidget(m1, 3); front->addStretch(1); front->addWidget(m2, 3); center->addSpacing(4); auto middle = create_vbox_layout(); center->addLayout(middle, 9); middle->addStretch(1); middle->addWidget(select_value_widget, 4); auto middle_h = create_hbox_layout(); middle->addLayout(middle_h, 2); middle_h->addWidget(progress_bar1, 5); middle_h->addStretch(1); middle_h->addWidget(progress_bar2, 3); center->addStretch(4); auto back1 = create_vbox_layout(); center->addLayout(back1, 1); back1->addWidget(m3, 3); back1->addStretch(1); back1->addWidget(m4, 3); center->addSpacing(4); auto back2 = create_vbox_layout(); center->addLayout(back2, 1); back2->addWidget(m5, 3); back2->addStretch(1); back2->addWidget(m6, 3); } main->addStretch(1); auto a_h1 = create_hbox_layout(); a_h1->setSpacing(8); main->addLayout(a_h1, 12); a_h1->addWidget(create_spectrogram_power_plot(), 12); a_h1->addWidget(create_time_power_plot(), 4); main->addSpacing(8); auto a_h2 = create_hbox_layout(); a_h2->setSpacing(8); main->addLayout(a_h2, 12); a_h2->addWidget(create_water_fall_plot(), 12); a_h2->addWidget(create_audio_spectrogram_plot(), 4); init_menu(); } Radio_Widget::~Radio_Widget() { Back_End::instance()->stop_mock_thread(); } void Radio_Widget::init_menu() { int font_size = 30; auto btn1_1 = new Menu_Button("模式设置", font_size, []() {}); auto btn1_2 = new Value_Menu_Button("发射功率:%1 W", font_size, [&](Value_Menu_Button* that, bool add) { that->setValue(that->value + (double)(add ? 1 : -1)); }, -1); auto btn2_1 = new Value_Menu_Button("参考增益:%1", font_size, [&](Value_Menu_Button* that, bool add) { that->setValue(that->value + (double)(add ? 1 : -1)); }, -1); base_widget_menu->add_menu_button_on_layout1({btn1_1, btn1_2, {btn2_1},}); //base_widget_menu->add_menu_button_on_layout2( ); Base_Widget_Menu* sub1 = base_widget_menu->create_sub_widget_menu(btn1_1); auto s1_1 = new Menu_Button("AM", font_size, []() {}); auto s1_2 = new Menu_Button("FM", font_size, []() {}); auto s1_3 = new Menu_Button("SSB", font_size, []() {}); auto s1_4 = new Menu_Button("CW", font_size, []() {}); sub1->add_menu_button_on_layout1({s1_1, s1_2, s1_3, s1_4}, 1); } void Radio_Widget::focusInEvent(QFocusEvent* event) { QWidget::focusInEvent(event); select_value_widget->setFocus(); } void Radio_Widget::keyPressEvent(QKeyEvent* event) { if (event->type() == QEvent::KeyPress) { Back_End* g = Back_End::instance(); auto* key_event = dynamic_cast(event); if (g->match(key_event, "切换音量/RF Gain")) { if (m1->text().startsWith("RF Gain")) { m1->setText("Voice\n" + QString::number(voice_value)); } else { m1->setText("RF Gain\n" + QString::number(rf_gain_value)); } } if (g->match(key_event, "特别增加")) { if (m1->text().startsWith("RF Gain")) { rf_gain_value++; Back_End::instance()->YsSetRfGain(rf_gain_value); m1->setText("RF Gain\n" + QString::number(rf_gain_value)); } else { voice_value++; Back_End::instance()->YsSetAfGain(voice_value); m1->setText("Voice\n" + QString::number(voice_value)); } } if (g->match(key_event, "特别减小")) { if (m1->text().startsWith("RF Gain")) { rf_gain_value--; Back_End::instance()->YsSetRfGain(rf_gain_value); m1->setText("RF Gain\n" + QString::number(rf_gain_value)); } else { voice_value--; Back_End::instance()->YsSetAfGain(voice_value); m1->setText("Voice\n" + QString::number(voice_value)); } } } Base_Widget::keyPressEvent(event); }