X-Git-Url: https://git.sesse.net/?p=nageru;a=blobdiff_plain;f=analyzer.cpp;h=b24b46a26ff52457ae3893f7cbf6b1253a1b2f24;hp=2d762236755c85128437ff0f261d01ac9b61790e;hb=4e3c52ba57c4552a969e71ccdefd9941ce8d6290;hpb=b41d4f0ee0ac2a3fc9f13e58b52fb45d87ce526c diff --git a/analyzer.cpp b/analyzer.cpp index 2d76223..b24b46a 100644 --- a/analyzer.cpp +++ b/analyzer.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -36,7 +37,15 @@ Analyzer::Analyzer() { ui->setupUi(this); - //connect(ui->button_box, &QDialogButtonBox::accepted, [this]{ this->close(); }); + surface = create_surface(QSurfaceFormat::defaultFormat()); + context = create_context(surface); + if (!make_current(context, surface)) { + printf("oops\n"); + exit(1); + } + + grab_timer.setSingleShot(true); + connect(&grab_timer, &QTimer::timeout, bind(&Analyzer::grab_clicked, this)); ui->input_box->addItem("Live", Mixer::OUTPUT_LIVE); ui->input_box->addItem("Preview", Mixer::OUTPUT_PREVIEW); @@ -47,22 +56,20 @@ Analyzer::Analyzer() ui->input_box->addItem(QString::fromStdString(name), channel); } + ui->grab_frequency_box->addItem("Never", 0); + ui->grab_frequency_box->addItem("100 ms", 100); + ui->grab_frequency_box->addItem("1 sec", 1000); + ui->grab_frequency_box->addItem("10 sec", 10000); + ui->grab_frequency_box->setCurrentIndex(2); + connect(ui->grab_btn, &QPushButton::clicked, bind(&Analyzer::grab_clicked, this)); connect(ui->input_box, static_cast(&QComboBox::currentIndexChanged), bind(&Analyzer::signal_changed, this)); signal_changed(); ui->grabbed_frame_label->installEventFilter(this); - surface = create_surface(QSurfaceFormat::defaultFormat()); - context = create_context(surface); - - if (!make_current(context, surface)) { - printf("oops\n"); - exit(1); - } - glGenBuffers(1, &pbo); glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo); - glBufferData(GL_PIXEL_PACK_BUFFER_ARB, global_flags.width * global_flags.height * 4, NULL, GL_STREAM_READ); + glBufferData(GL_PIXEL_PACK_BUFFER_ARB, global_flags.width * global_flags.height * 4, nullptr, GL_STREAM_READ); ui->histogram->xAxis->setVisible(true); ui->histogram->yAxis->setVisible(false); @@ -71,6 +78,22 @@ Analyzer::Analyzer() Analyzer::~Analyzer() { + delete_context(context); + delete surface; +} + +void Analyzer::update_channel_name(Mixer::Output output, const string &name) +{ + if (output >= Mixer::OUTPUT_INPUT0) { + int index = (output - Mixer::OUTPUT_INPUT0) + 2; + ui->input_box->setItemText(index, QString::fromStdString(name)); + } +} + +void Analyzer::mixer_shutting_down() +{ + ui->display->shutdown(); + if (!make_current(context, surface)) { printf("oops\n"); exit(1); @@ -80,8 +103,6 @@ Analyzer::~Analyzer() if (resource_pool != nullptr) { resource_pool->clean_context(); } - delete_context(context); - delete surface; } void Analyzer::grab_clicked() @@ -95,7 +116,7 @@ void Analyzer::grab_clicked() Mixer::DisplayFrame frame; if (!global_mixer->get_display_frame(channel, &frame)) { - printf("Not ready yet\n"); + // Not ready yet. return; } @@ -202,34 +223,172 @@ void Analyzer::grab_clicked() check_error(); resource_pool->release_fbo(fbo); check_error(); + + if (last_x >= 0 && last_y >= 0) { + grab_pixel(last_x, last_y); + } + + if (isVisible()) { + grab_timer.stop(); + + // Set up the next autograb if configured. + int delay = ui->grab_frequency_box->currentData().toInt(nullptr); + if (delay > 0) { + grab_timer.start(delay); + } + } } void Analyzer::signal_changed() { Mixer::Output channel = static_cast(ui->input_box->currentData().value()); ui->display->set_output(channel); + grab_clicked(); } bool Analyzer::eventFilter(QObject *watched, QEvent *event) { - if (event->type() == QEvent::MouseMove && - watched->isWidgetType()) { + if (event->type() == QEvent::MouseMove && watched->isWidgetType()) { const QMouseEvent *mouse_event = (QMouseEvent *)event; - const QPixmap *pixmap = ui->grabbed_frame_label->pixmap(); - if (pixmap != nullptr) { - int x = lrint(mouse_event->x() * double(pixmap->width()) / ui->grabbed_frame_label->width()); - int y = lrint(mouse_event->y() * double(pixmap->height()) / ui->grabbed_frame_label->height()); - x = std::min(x, pixmap->width() - 1); - y = std::min(y, pixmap->height() - 1); - QRgb pixel = grabbed_image.pixel(x, y); - ui->red_label->setText(QString::fromStdString(to_string(qRed(pixel)))); - ui->green_label->setText(QString::fromStdString(to_string(qGreen(pixel)))); - ui->blue_label->setText(QString::fromStdString(to_string(qBlue(pixel)))); - - char buf[256]; - snprintf(buf, sizeof(buf), "#%02x%02x%02x", qRed(pixel), qGreen(pixel), qBlue(pixel)); - ui->hex_label->setText(buf); - } - } + last_x = mouse_event->x(); + last_y = mouse_event->y(); + grab_pixel(mouse_event->x(), mouse_event->y()); + } + if (event->type() == QEvent::Leave && watched->isWidgetType()) { + last_x = last_y = -1; + ui->coord_label->setText("Selected coordinate (x,y): (none)"); + ui->red_label->setText(u8"—"); + ui->green_label->setText(u8"—"); + ui->blue_label->setText(u8"—"); + ui->hex_label->setText(u8"#—"); + } return false; } + +void Analyzer::grab_pixel(int x, int y) +{ + const QPixmap *pixmap = ui->grabbed_frame_label->pixmap(); + if (pixmap != nullptr) { + x = lrint(x * double(pixmap->width()) / ui->grabbed_frame_label->width()); + y = lrint(y * double(pixmap->height()) / ui->grabbed_frame_label->height()); + x = std::min(x, pixmap->width() - 1); + y = std::min(y, pixmap->height() - 1); + + char buf[256]; + snprintf(buf, sizeof(buf), "Selected coordinate (x,y): (%d,%d)", x, y); + ui->coord_label->setText(buf); + + QRgb pixel = grabbed_image.pixel(x, y); + ui->red_label->setText(QString::fromStdString(to_string(qRed(pixel)))); + ui->green_label->setText(QString::fromStdString(to_string(qGreen(pixel)))); + ui->blue_label->setText(QString::fromStdString(to_string(qBlue(pixel)))); + + snprintf(buf, sizeof(buf), "#%02x%02x%02x", qRed(pixel), qGreen(pixel), qBlue(pixel)); + ui->hex_label->setText(buf); + } +} + +void Analyzer::resizeEvent(QResizeEvent* event) +{ + QMainWindow::resizeEvent(event); + + // Ask for a relayout, but only after the event loop is done doing relayout + // on everything else. + QMetaObject::invokeMethod(this, "relayout", Qt::QueuedConnection); +} + +void Analyzer::showEvent(QShowEvent *event) +{ + grab_clicked(); +} + +void Analyzer::relayout() +{ + double aspect = double(global_flags.width) / global_flags.height; + + // Left pane (2/5 of the width). + { + int width = ui->left_pane->geometry().width(); + int height = ui->left_pane->geometry().height(); + + // Figure out how much space everything that's non-responsive needs. + int remaining_height = height - ui->left_pane->spacing() * (ui->left_pane->count() - 1); + + remaining_height -= ui->input_box->geometry().height(); + ui->left_pane->setStretch(2, ui->grab_btn->geometry().height()); + + remaining_height -= ui->grab_btn->geometry().height(); + ui->left_pane->setStretch(3, ui->grab_btn->geometry().height()); + + remaining_height -= ui->histogram_label->geometry().height(); + ui->left_pane->setStretch(5, ui->histogram_label->geometry().height()); + + // The histogram's minimumHeight returns 0, so let's set a reasonable minimum for it. + int min_histogram_height = 50; + remaining_height -= min_histogram_height; + + // Allocate so that the display is 16:9, if possible. + unsigned wanted_display_height = width / aspect; + unsigned display_height; + unsigned margin = 0; + if (remaining_height >= int(wanted_display_height)) { + display_height = wanted_display_height; + } else { + display_height = remaining_height; + int display_width = lrint(display_height * aspect); + margin = (width - display_width) / 2; + } + ui->left_pane->setStretch(1, display_height); + ui->display_left_spacer->changeSize(margin, 1); + ui->display_right_spacer->changeSize(margin, 1); + + remaining_height -= display_height; + + // Figure out if we can do the histogram at 16:9. + remaining_height += min_histogram_height; + unsigned histogram_height; + if (remaining_height >= int(wanted_display_height)) { + histogram_height = wanted_display_height; + } else { + histogram_height = remaining_height; + } + remaining_height -= histogram_height; + ui->left_pane->setStretch(4, histogram_height); + + ui->left_pane->setStretch(0, remaining_height / 2); + ui->left_pane->setStretch(6, remaining_height / 2); + } + + // Right pane (remaining 3/5 of the width). + { + int width = ui->right_pane->geometry().width(); + int height = ui->right_pane->geometry().height(); + + // Figure out how much space everything that's non-responsive needs. + int remaining_height = height - ui->right_pane->spacing() * (ui->right_pane->count() - 1); + remaining_height -= ui->grabbed_frame_sublabel->geometry().height(); + remaining_height -= ui->coord_label->geometry().height(); + remaining_height -= ui->color_hbox->geometry().height(); + + // Allocate so that the display is 16:9, if possible. + unsigned wanted_display_height = width / aspect; + unsigned display_height; + unsigned margin = 0; + if (remaining_height >= int(wanted_display_height)) { + display_height = wanted_display_height; + } else { + display_height = remaining_height; + int display_width = lrint(display_height * aspect); + margin = (width - display_width) / 2; + } + ui->right_pane->setStretch(1, display_height); + ui->grabbed_frame_left_spacer->changeSize(margin, 1); + ui->grabbed_frame_right_spacer->changeSize(margin, 1); + remaining_height -= display_height; + + if (remaining_height < 0) remaining_height = 0; + + ui->right_pane->setStretch(0, remaining_height / 2); + ui->right_pane->setStretch(5, remaining_height / 2); + } +}