X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=mainwindow.cpp;h=d3d298100dd5c9f492dc4c4edacbab0d62581df5;hb=b13524e538414c9c6577f2a54b65ec148c5e8b10;hp=36ea55ee3f8883fbe4e97fa484570bc26e70e8ee;hpb=0066ae51753e9ba7dbe54ab9c6f24fd861db41a2;p=nageru diff --git a/mainwindow.cpp b/mainwindow.cpp index 36ea55e..d3d2981 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -45,7 +46,9 @@ #include "aboutdialog.h" #include "alsa_pool.h" +#include "analyzer.h" #include "clickable_label.h" +#include "context_menus.h" #include "correlation_meter.h" #include "disk_space_estimator.h" #include "ellipsis_label.h" @@ -196,18 +199,30 @@ MainWindow::MainWindow() // The menus. connect(ui->cut_action, &QAction::triggered, this, &MainWindow::cut_triggered); connect(ui->exit_action, &QAction::triggered, this, &MainWindow::exit_triggered); + connect(ui->manual_action, &QAction::triggered, this, &MainWindow::manual_triggered); connect(ui->about_action, &QAction::triggered, this, &MainWindow::about_triggered); + connect(ui->open_analyzer_action, &QAction::triggered, this, &MainWindow::open_analyzer_triggered); connect(ui->simple_audio_mode, &QAction::triggered, this, &MainWindow::simple_audio_mode_triggered); connect(ui->multichannel_audio_mode, &QAction::triggered, this, &MainWindow::multichannel_audio_mode_triggered); connect(ui->input_mapping_action, &QAction::triggered, this, &MainWindow::input_mapping_triggered); connect(ui->midi_mapping_action, &QAction::triggered, this, &MainWindow::midi_mapping_triggered); + connect(ui->timecode_stream_action, &QAction::triggered, this, &MainWindow::timecode_stream_triggered); + connect(ui->timecode_stdout_action, &QAction::triggered, this, &MainWindow::timecode_stdout_triggered); - if (global_flags.x264_video_to_http) { + ui->timecode_stream_action->setChecked(global_flags.display_timecode_in_stream); + ui->timecode_stdout_action->setChecked(global_flags.display_timecode_on_stdout); + + if (global_flags.x264_video_to_http && isinf(global_flags.x264_crf)) { connect(ui->x264_bitrate_action, &QAction::triggered, this, &MainWindow::x264_bitrate_triggered); } else { ui->x264_bitrate_action->setEnabled(false); } + connect(ui->video_menu, &QMenu::aboutToShow, [this]{ + fill_hdmi_sdi_output_device_menu(ui->hdmi_sdi_output_device_menu); + fill_hdmi_sdi_output_resolution_menu(ui->hdmi_sdi_output_resolution_menu); + }); + // Hook up the transition buttons. (Keyboard shortcuts are set in set_transition_names().) // TODO: Make them dynamic. connect(ui->transition_btn1, &QPushButton::clicked, bind(&MainWindow::transition_clicked, this, 0)); @@ -238,6 +253,13 @@ MainWindow::MainWindow() connect(new QShortcut(QKeySequence::MoveToNextPage, this), &QShortcut::activated, switch_page); connect(new QShortcut(QKeySequence::MoveToPreviousPage, this), &QShortcut::activated, switch_page); + if (global_flags.enable_quick_cut_keys) { + ui->quick_cut_enable_action->setChecked(true); + } + connect(ui->quick_cut_enable_action, &QAction::changed, [this](){ + global_flags.enable_quick_cut_keys = ui->quick_cut_enable_action->isChecked(); + }); + last_audio_level_callback = steady_clock::now() - seconds(1); if (!global_flags.midi_mapping_filename.empty()) { @@ -251,7 +273,6 @@ MainWindow::MainWindow() } midi_mapper.refresh_highlights(); midi_mapper.refresh_lights(); - midi_mapper.start_thread(); } void MainWindow::resizeEvent(QResizeEvent* event) @@ -268,6 +289,7 @@ void MainWindow::mixer_created(Mixer *mixer) // Make the previews. unsigned num_previews = mixer->get_num_channels(); + const char qwerty[] = "QWERTYUIOP"; for (unsigned i = 0; i < num_previews; ++i) { Mixer::Output output = Mixer::Output(Mixer::OUTPUT_INPUT0 + i); @@ -290,6 +312,12 @@ void MainWindow::mixer_created(Mixer *mixer) QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_1 + i), this); connect(shortcut, &QShortcut::activated, bind(&MainWindow::channel_clicked, this, i)); + // Hook up the quick-cut key. + if (i < strlen(qwerty)) { + QShortcut *shortcut = new QShortcut(QKeySequence(qwerty[i]), this); + connect(shortcut, &QShortcut::activated, bind(&MainWindow::quick_cut_activated, this, i)); + } + // Hook up the white balance button (irrelevant if invisible). ui_display->wb_button->setVisible(mixer->get_supports_set_wb(output)); connect(ui_display->wb_button, &QPushButton::clicked, bind(&MainWindow::wb_button_clicked, this, i)); @@ -366,6 +394,9 @@ void MainWindow::mixer_created(Mixer *mixer) midi_mapper.refresh_highlights(); midi_mapper.refresh_lights(); + midi_mapper.start_thread(); + + analyzer.reset(new Analyzer); struct sigaction act; memset(&act, 0, sizeof(act)); @@ -482,7 +513,7 @@ void MainWindow::setup_audio_expanded_view() update_eq_label(bus_index, EQ_BAND_MID, global_audio_mixer->get_eq(bus_index, EQ_BAND_MID)); update_eq_label(bus_index, EQ_BAND_BASS, global_audio_mixer->get_eq(bus_index, EQ_BAND_BASS)); ui_audio_expanded_view->fader->setDbValue(global_audio_mixer->get_fader_volume(bus_index)); - ui_audio_expanded_view->mute_button->setChecked(global_audio_mixer->get_mute(bus_index) ? Qt::Checked : Qt::Unchecked); + ui_audio_expanded_view->mute_button->setChecked(global_audio_mixer->get_mute(bus_index)); connect(ui_audio_expanded_view->mute_button, &QPushButton::toggled, bind(&MainWindow::mute_button_toggled, this, bus_index, _1)); ui->buses->addWidget(channel); @@ -536,11 +567,14 @@ void MainWindow::setup_audio_expanded_view() void MainWindow::mixer_shutting_down() { - ui->me_live->clean_context(); - ui->me_preview->clean_context(); + ui->me_live->shutdown(); + ui->me_preview->shutdown(); + for (Ui::Display *display : previews) { - display->display->clean_context(); + display->display->shutdown(); } + + analyzer->mixer_shutting_down(); } void MainWindow::cut_triggered() @@ -563,11 +597,25 @@ void MainWindow::exit_triggered() close(); } +void MainWindow::manual_triggered() +{ + if (!QDesktopServices::openUrl(QUrl("https://nageru.sesse.net/doc/"))) { + QMessageBox msgbox; + msgbox.setText("Could not launch manual in web browser.\nPlease see https://nageru.sesse.net/doc/ manually."); + msgbox.exec(); + } +} + void MainWindow::about_triggered() { AboutDialog().exec(); } +void MainWindow::open_analyzer_triggered() +{ + analyzer->show(); +} + void MainWindow::simple_audio_mode_triggered() { if (global_audio_mixer->get_mapping_mode() == AudioMixer::MappingMode::SIMPLE) { @@ -620,6 +668,16 @@ void MainWindow::midi_mapping_triggered() MIDIMappingDialog(&midi_mapper).exec(); } +void MainWindow::timecode_stream_triggered() +{ + global_mixer->set_display_timecode_in_stream(ui->timecode_stream_action->isChecked()); +} + +void MainWindow::timecode_stdout_triggered() +{ + global_mixer->set_display_timecode_on_stdout(ui->timecode_stdout_action->isChecked()); +} + void MainWindow::gain_staging_knob_changed(unsigned bus_index, int value) { if (bus_index == 0) { @@ -855,9 +913,9 @@ void MainWindow::relayout() double remaining_height = height; // Allocate the height; the most important part is to keep the main displays - // at 16:9 if at all possible. + // at the right aspect if at all possible. double me_width = ui->me_preview->width(); - double me_height = me_width * 9.0 / 16.0 + ui->label_preview->height() + ui->preview_vertical_layout->spacing(); + double me_height = me_width * double(global_flags.height) / double(global_flags.width) + ui->label_preview->height() + ui->preview_vertical_layout->spacing(); // TODO: Scale the widths when we need to do this. if (me_height / double(height) > 0.8) { @@ -877,7 +935,7 @@ void MainWindow::relayout() double preview_label_height = previews[0]->title_bar->geometry().height() + previews[0]->main_vertical_layout->spacing(); int preview_total_width = ui->preview_displays->geometry().width() - (previews.size() - 1) * ui->preview_displays->spacing(); - double preview_height = min(remaining_height - preview_label_height, (preview_total_width / double(previews.size())) * 9.0 / 16.0); + double preview_height = min(remaining_height - preview_label_height, (preview_total_width / double(previews.size())) * double(global_flags.height) / double(global_flags.width)); remaining_height -= preview_height + preview_label_height + ui->vertical_layout->spacing(); ui->vertical_layout->setStretch(0, lrintf(me_height)); @@ -891,7 +949,7 @@ void MainWindow::relayout() ui->compact_audio_layout->setStretch(2, lrintf(preview_height + preview_label_height)); // Set the widths for the previews. - double preview_width = preview_height * 16.0 / 9.0; + double preview_width = preview_height * double(global_flags.width) / double(global_flags.height); for (unsigned i = 0; i < previews.size(); ++i) { ui->preview_displays->setStretch(i, lrintf(preview_width)); } @@ -1210,6 +1268,8 @@ void MainWindow::update_channel_name(Mixer::Output output, const string &name) unsigned channel = output - Mixer::OUTPUT_INPUT0; previews[channel]->label->setText(name.c_str()); } + + analyzer->update_channel_name(output, name); } void MainWindow::update_channel_color(Mixer::Output output, const string &color) @@ -1235,6 +1295,15 @@ void MainWindow::channel_clicked(int channel_number) } } +void MainWindow::quick_cut_activated(int channel_number) +{ + if (!global_flags.enable_quick_cut_keys) { + return; + } + global_mixer->channel_clicked(channel_number); + global_mixer->transition_clicked(0); +} + void MainWindow::wb_button_clicked(int channel_number) { current_wb_pick_display = channel_number; @@ -1259,6 +1328,22 @@ bool MainWindow::eventFilter(QObject *watched, QEvent *event) return false; } +void MainWindow::closeEvent(QCloseEvent *event) +{ + if (global_mixer->get_num_connected_clients() > 0) { + QMessageBox::StandardButton reply = + QMessageBox::question(this, "Nageru", "There are clients connected. Do you really want to quit?", + QMessageBox::Yes | QMessageBox::No); + if (reply != QMessageBox::Yes) { + event->ignore(); + return; + } + } + + analyzer->hide(); + event->accept(); +} + namespace { double srgb_to_linear(double x) @@ -1290,6 +1375,9 @@ void MainWindow::set_white_balance(int channel_number, int x, int y) void MainWindow::audio_state_changed() { post_to_main_thread([this]{ + if (global_audio_mixer->get_mapping_mode() == AudioMixer::MappingMode::SIMPLE) { + return; + } InputMapping mapping = global_audio_mixer->get_input_mapping(); for (unsigned bus_index = 0; bus_index < mapping.buses.size(); ++bus_index) { const InputMapping::Bus &bus = mapping.buses[bus_index];