annotate widgets/PluginParameterDialog.cpp @ 180:29f01de27db4

* Add vertical zooming and snap-to-selection for OSC control; add a demo script
author Chris Cannam
date Wed, 15 Nov 2006 18:22:26 +0000
parents 78d523e8433e
children 42118892f428
rev   line source
Chris@62 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@62 2
Chris@62 3 /*
Chris@62 4 Sonic Visualiser
Chris@62 5 An audio file viewer and annotation editor.
Chris@62 6 Centre for Digital Music, Queen Mary, University of London.
Chris@62 7 This file copyright 2006 Chris Cannam.
Chris@62 8
Chris@62 9 This program is free software; you can redistribute it and/or
Chris@62 10 modify it under the terms of the GNU General Public License as
Chris@62 11 published by the Free Software Foundation; either version 2 of the
Chris@62 12 License, or (at your option) any later version. See the file
Chris@62 13 COPYING included with this distribution for more information.
Chris@62 14 */
Chris@62 15
Chris@62 16 #include "PluginParameterDialog.h"
Chris@62 17
Chris@62 18 #include "PluginParameterBox.h"
Chris@140 19 #include "WindowTypeSelector.h"
Chris@62 20
Chris@106 21 #include "vamp-sdk/Plugin.h"
Chris@147 22 #include "vamp-sdk/PluginHostAdapter.h"
Chris@106 23
Chris@62 24 #include <QGridLayout>
Chris@62 25 #include <QLabel>
Chris@62 26 #include <QGroupBox>
Chris@62 27 #include <QHBoxLayout>
Chris@143 28 #include <QVBoxLayout>
Chris@149 29 #include <QScrollArea>
Chris@62 30 #include <QPushButton>
Chris@69 31 #include <QMessageBox>
Chris@69 32 #include <QComboBox>
Chris@143 33 #include <QSettings>
Chris@62 34
Chris@71 35 PluginParameterDialog::PluginParameterDialog(Vamp::PluginBase *plugin,
Chris@62 36 QWidget *parent) :
Chris@62 37 QDialog(parent),
Chris@62 38 m_plugin(plugin),
Chris@163 39 m_channel(-1),
Chris@145 40 m_stepSize(0),
Chris@145 41 m_blockSize(0),
Chris@145 42 m_windowType(HanningWindow),
Chris@62 43 m_parameterBox(0)
Chris@62 44 {
Chris@122 45 setWindowTitle(tr("Plugin Parameters"));
Chris@122 46
Chris@62 47 QGridLayout *grid = new QGridLayout;
Chris@62 48 setLayout(grid);
Chris@62 49
Chris@62 50 QGroupBox *pluginBox = new QGroupBox;
Chris@62 51 pluginBox->setTitle(tr("Plugin"));
Chris@62 52 grid->addWidget(pluginBox, 0, 0);
Chris@62 53
Chris@62 54 QGridLayout *subgrid = new QGridLayout;
Chris@62 55 pluginBox->setLayout(subgrid);
Chris@62 56
Chris@63 57 subgrid->setSpacing(0);
Chris@63 58 subgrid->setMargin(10);
Chris@63 59
Chris@62 60 QFont font(pluginBox->font());
Chris@62 61 font.setBold(true);
Chris@62 62
Chris@62 63 QLabel *nameLabel = new QLabel(plugin->getDescription().c_str());
Chris@146 64 nameLabel->setWordWrap(true);
Chris@62 65 nameLabel->setFont(font);
Chris@62 66
Chris@62 67 QLabel *makerLabel = new QLabel(plugin->getMaker().c_str());
Chris@146 68 makerLabel->setWordWrap(true);
Chris@62 69
Chris@62 70 QLabel *versionLabel = new QLabel(QString("%1")
Chris@62 71 .arg(plugin->getPluginVersion()));
Chris@146 72 versionLabel->setWordWrap(true);
Chris@62 73
Chris@62 74 QLabel *copyrightLabel = new QLabel(plugin->getCopyright().c_str());
Chris@146 75 copyrightLabel->setWordWrap(true);
Chris@62 76
Chris@63 77 QLabel *typeLabel = new QLabel(plugin->getType().c_str());
Chris@146 78 typeLabel->setWordWrap(true);
Chris@63 79 typeLabel->setFont(font);
Chris@63 80
Chris@163 81 int row = 0;
Chris@163 82
Chris@147 83 QLabel *label = new QLabel(tr("Name:"));
Chris@147 84 label->setAlignment(Qt::AlignTop | Qt::AlignLeft);
Chris@163 85 subgrid->addWidget(label, row, 0);
Chris@163 86 subgrid->addWidget(nameLabel, row, 1);
Chris@163 87 row++;
Chris@62 88
Chris@147 89 label = new QLabel(tr("Type:"));
Chris@147 90 label->setAlignment(Qt::AlignTop | Qt::AlignLeft);
Chris@163 91 subgrid->addWidget(label, row, 0);
Chris@163 92 subgrid->addWidget(typeLabel, row, 1);
Chris@163 93 row++;
Chris@164 94
Chris@163 95 m_outputLabel = new QLabel(tr("Output:"));
Chris@163 96 m_outputLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
Chris@163 97 subgrid->addWidget(m_outputLabel, row, 0);
Chris@163 98 m_outputValue = new QLabel;
Chris@163 99 subgrid->addWidget(m_outputValue, row, 1);
Chris@163 100 m_outputLabel->hide();
Chris@163 101 m_outputValue->hide();
Chris@163 102 row++;
Chris@62 103
Chris@147 104 label = new QLabel(tr("Maker:"));
Chris@147 105 label->setAlignment(Qt::AlignTop | Qt::AlignLeft);
Chris@163 106 subgrid->addWidget(label, row, 0);
Chris@163 107 subgrid->addWidget(makerLabel, row, 1);
Chris@163 108 row++;
Chris@63 109
Chris@147 110 label = new QLabel(tr("Copyright: "));
Chris@147 111 label->setAlignment(Qt::AlignTop | Qt::AlignLeft);
Chris@163 112 subgrid->addWidget(label, row, 0);
Chris@163 113 subgrid->addWidget(copyrightLabel, row, 1);
Chris@163 114 row++;
Chris@106 115
Chris@147 116 label = new QLabel(tr("Version:"));
Chris@147 117 label->setAlignment(Qt::AlignTop | Qt::AlignLeft);
Chris@163 118 subgrid->addWidget(label, row, 0);
Chris@163 119 subgrid->addWidget(versionLabel, row, 1);
Chris@163 120 row++;
Chris@62 121
Chris@62 122 subgrid->setColumnStretch(1, 2);
Chris@62 123
Chris@164 124 m_inputModelBox = new QGroupBox;
Chris@164 125 m_inputModelBox->setTitle(tr("Input Source"));
Chris@164 126 grid->addWidget(m_inputModelBox, 1, 0);
Chris@164 127
Chris@164 128 m_inputModels = new QComboBox;
Chris@164 129 QHBoxLayout *inputLayout = new QHBoxLayout;
Chris@164 130 m_inputModelBox->setLayout(inputLayout);
Chris@164 131 inputLayout->addWidget(m_inputModels);
Chris@164 132 m_inputModelBox->hide();
Chris@164 133
Chris@62 134 QGroupBox *paramBox = new QGroupBox;
Chris@62 135 paramBox->setTitle(tr("Plugin Parameters"));
Chris@164 136 grid->addWidget(paramBox, 2, 0);
Chris@164 137 grid->setRowStretch(2, 10);
Chris@62 138
Chris@62 139 QHBoxLayout *paramLayout = new QHBoxLayout;
Chris@63 140 paramLayout->setMargin(0);
Chris@62 141 paramBox->setLayout(paramLayout);
Chris@62 142
Chris@149 143 QScrollArea *scroll = new QScrollArea;
Chris@149 144 scroll->setWidgetResizable(true);
Chris@149 145 scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
Chris@149 146 scroll->setFrameShape(QFrame::NoFrame);
Chris@149 147 paramLayout->addWidget(scroll);
Chris@149 148
Chris@62 149 m_parameterBox = new PluginParameterBox(m_plugin);
Chris@64 150 connect(m_parameterBox, SIGNAL(pluginConfigurationChanged(QString)),
Chris@64 151 this, SIGNAL(pluginConfigurationChanged(QString)));
Chris@149 152 scroll->setWidget(m_parameterBox);
Chris@62 153
Chris@143 154 m_advanced = new QFrame;
Chris@143 155 QVBoxLayout *advancedLayout = new QVBoxLayout;
Chris@143 156 advancedLayout->setMargin(0);
Chris@143 157 m_advanced->setLayout(advancedLayout);
Chris@164 158 grid->addWidget(m_advanced, 3, 0);
Chris@143 159
Chris@143 160 bool haveAdvanced = false;
Chris@143 161
Chris@163 162 m_channelBox = new QGroupBox;
Chris@163 163 m_channelBox->setTitle(tr("Channels"));
Chris@163 164 advancedLayout->addWidget(m_channelBox);
Chris@163 165 m_channelBox->setVisible(false);
Chris@163 166 m_haveChannelBoxData = false;
Chris@163 167
Chris@163 168 m_windowBox = new QGroupBox;
Chris@163 169 m_windowBox->setTitle(tr("Processing"));
Chris@163 170 advancedLayout->addWidget(m_windowBox);
Chris@163 171 m_windowBox->setVisible(false);
Chris@163 172 m_haveWindowBoxData = false;
Chris@163 173
Chris@163 174 QHBoxLayout *hbox = new QHBoxLayout;
Chris@163 175 grid->addLayout(hbox, 4, 0);
Chris@163 176
Chris@163 177 m_advancedVisible = false;
Chris@163 178
Chris@163 179 m_advancedButton = new QPushButton(tr("Advanced >>"));
Chris@163 180 m_advancedButton->setCheckable(true);
Chris@163 181 connect(m_advancedButton, SIGNAL(clicked()), this, SLOT(advancedToggled()));
Chris@163 182
Chris@163 183 QSettings settings;
Chris@163 184 settings.beginGroup("PluginParameterDialog");
Chris@163 185 m_advancedVisible = settings.value("advancedvisible", false).toBool();
Chris@163 186 settings.endGroup();
Chris@163 187
Chris@163 188 m_advanced->setVisible(false);
Chris@163 189
Chris@163 190 hbox->addWidget(m_advancedButton);
Chris@163 191 m_advancedButton->hide();
Chris@163 192
Chris@163 193 QPushButton *ok = new QPushButton(tr("OK"));
Chris@163 194 QPushButton *cancel = new QPushButton(tr("Cancel"));
Chris@163 195 hbox->addStretch(10);
Chris@163 196 hbox->addWidget(ok);
Chris@163 197 hbox->addWidget(cancel);
Chris@163 198 connect(ok, SIGNAL(clicked()), this, SLOT(accept()));
Chris@163 199 connect(cancel, SIGNAL(clicked()), this, SLOT(reject()));
Chris@163 200
Chris@163 201 setAdvancedVisible(m_advancedVisible);
Chris@163 202 }
Chris@163 203
Chris@163 204 PluginParameterDialog::~PluginParameterDialog()
Chris@163 205 {
Chris@163 206 }
Chris@163 207
Chris@163 208
Chris@163 209 void
Chris@163 210 PluginParameterDialog::setOutputLabel(QString text)
Chris@163 211 {
Chris@163 212 if (text == "") {
Chris@163 213 m_outputLabel->hide();
Chris@163 214 m_outputValue->hide();
Chris@163 215 } else {
Chris@163 216 m_outputValue->setText(text);
Chris@163 217 m_outputValue->setWordWrap(true);
Chris@163 218 m_outputLabel->show();
Chris@163 219 m_outputValue->show();
Chris@163 220 }
Chris@163 221 }
Chris@163 222
Chris@163 223 void
Chris@163 224 PluginParameterDialog::setChannelArrangement(int sourceChannels,
Chris@163 225 int targetChannels,
Chris@163 226 int defaultChannel)
Chris@163 227 {
Chris@163 228 m_channel = defaultChannel;
Chris@163 229
Chris@69 230 if (sourceChannels != targetChannels) {
Chris@69 231
Chris@69 232 // At the moment we can only cope with the case where
Chris@69 233 // sourceChannels > targetChannels and targetChannels == 1
Chris@69 234
Chris@69 235 if (sourceChannels < targetChannels) {
Chris@69 236
Chris@69 237 QMessageBox::warning
Chris@163 238 (parentWidget(),
Chris@69 239 tr("Channel mismatch"),
Chris@69 240 tr("This plugin requires at least %1 input channels, but only %2 %3 available. The plugin probably will not work correctly.").arg(targetChannels).arg(sourceChannels).arg(sourceChannels != 1 ? tr("are") : tr("is")),
Chris@69 241 QMessageBox::Ok,
Chris@69 242 QMessageBox::NoButton);
Chris@69 243
Chris@69 244 } else {
Chris@69 245
Chris@163 246 if (m_haveChannelBoxData) {
Chris@163 247 std::cerr << "WARNING: PluginParameterDialog::setChannelArrangement: Calling more than once on same dialog is not currently implemented" << std::endl;
Chris@163 248 return;
Chris@163 249 }
Chris@69 250
Chris@69 251 QVBoxLayout *channelLayout = new QVBoxLayout;
Chris@163 252 m_channelBox->setLayout(channelLayout);
Chris@69 253
Chris@69 254 if (targetChannels != 1) {
Chris@69 255
Chris@69 256 channelLayout->addWidget
Chris@69 257 (new QLabel(tr("This plugin accepts no more than %1 input channels,\nbut %2 are available. Only the first %3 will be used.\n")
Chris@69 258 .arg(targetChannels)
Chris@69 259 .arg(sourceChannels)
Chris@69 260 .arg(targetChannels)));
Chris@69 261
Chris@69 262 } else {
Chris@69 263
Chris@69 264 channelLayout->addWidget(new QLabel(tr("This plugin only has a single channel input,\nbut the source has %1 channels.").arg(sourceChannels)));
Chris@69 265
Chris@69 266 QComboBox *channelCombo = new QComboBox;
Chris@76 267 channelCombo->addItem(tr("Use mean of source channels"));
Chris@69 268 for (int i = 0; i < sourceChannels; ++i) {
Chris@69 269 channelCombo->addItem(tr("Use channel %1 only").arg(i + 1));
Chris@69 270 }
Chris@69 271
Chris@69 272 connect(channelCombo, SIGNAL(activated(int)),
Chris@69 273 this, SLOT(channelComboChanged(int)));
Chris@69 274
Chris@69 275 channelLayout->addWidget(channelCombo);
Chris@69 276 }
Chris@163 277
Chris@163 278 m_channelBox->setVisible(true);
Chris@163 279 m_haveChannelBoxData = true;
Chris@163 280 m_advancedButton->show();
Chris@69 281 }
Chris@69 282 }
Chris@69 283
Chris@163 284 setAdvancedVisible(m_advancedVisible);
Chris@163 285 }
Chris@163 286
Chris@163 287 void
Chris@163 288 PluginParameterDialog::setShowProcessingOptions(bool showWindowSize,
Chris@163 289 bool showFrequencyDomainOptions)
Chris@163 290 {
Chris@163 291 if (m_haveWindowBoxData) {
Chris@163 292 std::cerr << "WARNING: PluginParameterDialog::setShowProcessingOptions: Calling more than once on same dialog is not currently implemented" << std::endl;
Chris@163 293 return;
Chris@163 294 }
Chris@163 295
Chris@140 296 if (showWindowSize) {
Chris@140 297
Chris@147 298 Vamp::PluginHostAdapter *fePlugin = dynamic_cast<Vamp::PluginHostAdapter *>(m_plugin);
Chris@140 299 int size = 1024;
Chris@140 300 int increment = 1024;
Chris@140 301 if (fePlugin) {
Chris@140 302 size = fePlugin->getPreferredBlockSize();
Chris@146 303 std::cerr << "Feature extraction plugin \"" << fePlugin->getDescription() << "\" reports preferred block size as " << size << std::endl;
Chris@140 304 if (size == 0) size = 1024;
Chris@140 305 increment = fePlugin->getPreferredStepSize();
Chris@146 306 if (increment == 0) {
Chris@146 307 if (fePlugin->getInputDomain() == Vamp::Plugin::TimeDomain) {
Chris@146 308 increment = size;
Chris@146 309 } else {
Chris@146 310 increment = size/2;
Chris@146 311 }
Chris@146 312 }
Chris@140 313 }
Chris@140 314
Chris@140 315 QGridLayout *windowLayout = new QGridLayout;
Chris@163 316 m_windowBox->setLayout(windowLayout);
Chris@140 317
Chris@140 318 if (showFrequencyDomainOptions) {
Chris@140 319 windowLayout->addWidget(new QLabel(tr("Window size:")), 0, 0);
Chris@140 320 } else {
Chris@140 321 windowLayout->addWidget(new QLabel(tr("Audio frames per block:")), 0, 0);
Chris@140 322 }
Chris@140 323
Chris@143 324 std::cerr << "size: " << size << ", increment: " << increment << std::endl;
Chris@143 325
Chris@140 326 QComboBox *blockSizeCombo = new QComboBox;
Chris@140 327 blockSizeCombo->setEditable(true);
Chris@147 328 bool found = false;
Chris@143 329 for (int i = 0; i < 14; ++i) {
Chris@140 330 int val = pow(2, i + 3);
Chris@140 331 blockSizeCombo->addItem(QString("%1").arg(val));
Chris@147 332 if (val == size) {
Chris@147 333 blockSizeCombo->setCurrentIndex(i);
Chris@147 334 found = true;
Chris@147 335 }
Chris@147 336 }
Chris@147 337 if (!found) {
Chris@147 338 blockSizeCombo->addItem(QString("%1").arg(size));
Chris@147 339 blockSizeCombo->setCurrentIndex(blockSizeCombo->count() - 1);
Chris@140 340 }
Chris@143 341 blockSizeCombo->setValidator(new QIntValidator(1, pow(2, 18), this));
Chris@155 342 connect(blockSizeCombo, SIGNAL(editTextChanged(const QString &)),
Chris@155 343 this, SLOT(blockSizeComboChanged(const QString &)));
Chris@140 344 windowLayout->addWidget(blockSizeCombo, 0, 1);
Chris@140 345
Chris@148 346 windowLayout->addWidget(new QLabel(tr("Window increment:")), 1, 0);
Chris@148 347
Chris@148 348 QComboBox *incrementCombo = new QComboBox;
Chris@148 349 incrementCombo->setEditable(true);
Chris@148 350 found = false;
Chris@148 351 for (int i = 0; i < 14; ++i) {
Chris@148 352 int val = pow(2, i + 3);
Chris@148 353 incrementCombo->addItem(QString("%1").arg(val));
Chris@148 354 if (val == increment) {
Chris@148 355 incrementCombo->setCurrentIndex(i);
Chris@148 356 found = true;
Chris@148 357 }
Chris@148 358 }
Chris@148 359 if (!found) {
Chris@148 360 incrementCombo->addItem(QString("%1").arg(increment));
Chris@148 361 incrementCombo->setCurrentIndex(incrementCombo->count() - 1);
Chris@148 362 }
Chris@148 363 incrementCombo->setValidator(new QIntValidator(1, pow(2, 18), this));
Chris@155 364 connect(incrementCombo, SIGNAL(editTextChanged(const QString &)),
Chris@155 365 this, SLOT(incrementComboChanged(const QString &)));
Chris@148 366 windowLayout->addWidget(incrementCombo, 1, 1);
Chris@148 367
Chris@140 368 if (showFrequencyDomainOptions) {
Chris@140 369
Chris@140 370 windowLayout->addWidget(new QLabel(tr("Window shape:")), 2, 0);
Chris@140 371 WindowTypeSelector *windowTypeSelector = new WindowTypeSelector;
Chris@171 372 connect(windowTypeSelector, SIGNAL(windowTypeChanged(WindowType)),
Chris@171 373 this, SLOT(windowTypeChanged(WindowType)));
Chris@140 374 windowLayout->addWidget(windowTypeSelector, 2, 1);
Chris@140 375 }
Chris@163 376
Chris@163 377 m_windowBox->setVisible(true);
Chris@163 378 m_haveWindowBoxData = true;
Chris@163 379 m_advancedButton->show();
Chris@140 380 }
Chris@140 381
Chris@163 382 setAdvancedVisible(m_advancedVisible);
Chris@62 383 }
Chris@62 384
Chris@69 385 void
Chris@164 386 PluginParameterDialog::setCandidateInputModels(const QStringList &models)
Chris@164 387 {
Chris@164 388 m_inputModels->clear();
Chris@164 389 m_inputModels->insertItems(0, models);
Chris@164 390 connect(m_inputModels, SIGNAL(activated(const QString &)),
Chris@164 391 this, SIGNAL(inputModelChanged(QString)));
Chris@164 392 m_inputModelBox->show();
Chris@164 393 }
Chris@164 394
Chris@164 395 QString
Chris@164 396 PluginParameterDialog::getInputModel() const
Chris@164 397 {
Chris@164 398 return m_inputModels->currentText();
Chris@164 399 }
Chris@164 400
Chris@164 401 void
Chris@145 402 PluginParameterDialog::getProcessingParameters(size_t &blockSize) const
Chris@145 403 {
Chris@145 404 blockSize = m_blockSize;
Chris@145 405 return;
Chris@145 406 }
Chris@145 407
Chris@145 408 void
Chris@145 409 PluginParameterDialog::getProcessingParameters(size_t &stepSize,
Chris@145 410 size_t &blockSize,
Chris@145 411 WindowType &windowType) const
Chris@145 412 {
Chris@145 413 stepSize = m_stepSize;
Chris@145 414 blockSize = m_blockSize;
Chris@145 415 windowType = m_windowType;
Chris@146 416 return;
Chris@145 417 }
Chris@145 418
Chris@145 419 void
Chris@155 420 PluginParameterDialog::blockSizeComboChanged(const QString &text)
Chris@145 421 {
Chris@145 422 m_blockSize = text.toInt();
Chris@146 423 std::cerr << "Block size changed to " << m_blockSize << std::endl;
Chris@145 424 }
Chris@145 425
Chris@145 426 void
Chris@155 427 PluginParameterDialog::incrementComboChanged(const QString &text)
Chris@145 428 {
Chris@145 429 m_stepSize = text.toInt();
Chris@146 430 //!!! rename increment to step size throughout
Chris@147 431 std::cerr << "Increment changed to " << m_stepSize << std::endl;
Chris@145 432 }
Chris@145 433
Chris@145 434 void
Chris@145 435 PluginParameterDialog::windowTypeChanged(WindowType type)
Chris@145 436 {
Chris@145 437 m_windowType = type;
Chris@145 438 }
Chris@145 439
Chris@145 440 void
Chris@143 441 PluginParameterDialog::advancedToggled()
Chris@143 442 {
Chris@163 443 setAdvancedVisible(!m_advancedVisible);
Chris@163 444 }
Chris@143 445
Chris@163 446 void
Chris@163 447 PluginParameterDialog::setAdvancedVisible(bool visible)
Chris@163 448 {
Chris@143 449 m_advanced->setVisible(visible);
Chris@143 450
Chris@163 451 if (visible) {
Chris@163 452 m_advancedButton->setText(tr("Advanced <<"));
Chris@163 453 m_advancedButton->setChecked(true);
Chris@163 454 } else {
Chris@163 455 m_advancedButton->setText(tr("Advanced >>"));
Chris@163 456 m_advancedButton->setChecked(false);
Chris@163 457 }
Chris@143 458
Chris@143 459 QSettings settings;
Chris@143 460 settings.beginGroup("PluginParameterDialog");
Chris@143 461 settings.setValue("advancedvisible", visible);
Chris@143 462 settings.endGroup();
Chris@143 463
Chris@143 464 std::cerr << "resize to " << sizeHint().width() << " x " << sizeHint().height() << std::endl;
Chris@143 465
Chris@149 466 setMinimumHeight(sizeHint().height());
Chris@163 467 adjustSize();
Chris@163 468
Chris@163 469 m_advancedVisible = visible;
Chris@163 470
Chris@163 471 // if (visible) setMaximumHeight(sizeHint().height());
Chris@163 472 // adjustSize();
Chris@143 473 }
Chris@143 474
Chris@143 475 void
Chris@69 476 PluginParameterDialog::channelComboChanged(int index)
Chris@69 477 {
Chris@69 478 m_channel = index - 1;
Chris@69 479 }
Chris@69 480