annotate widgets/PropertyBox.cpp @ 38:beb801473743

* Rearrange spectrogram cacheing so that gain, normalization, instantaneous frequency calculations etc can be done from the cached data (increasing the size of the cache, but also the usability).
author Chris Cannam
date Thu, 23 Feb 2006 18:01:31 +0000
parents c28ebb4ba4de
children ad214997dddb
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 A waveform viewer and audio annotation editor.
Chris@5 5 Chris Cannam, Queen Mary University of London, 2005-2006
Chris@0 6
Chris@0 7 This is experimental software. Not for distribution.
Chris@0 8 */
Chris@0 9
Chris@0 10 #include "PropertyBox.h"
Chris@0 11
Chris@0 12 #include "base/PropertyContainer.h"
Chris@33 13 #include "base/PlayParameters.h"
Chris@33 14 #include "base/Layer.h"
Chris@0 15
Chris@0 16 #include "AudioDial.h"
Chris@33 17 #include "LEDButton.h"
Chris@0 18
Chris@0 19 #include <QGridLayout>
Chris@0 20 #include <QHBoxLayout>
Chris@33 21 #include <QVBoxLayout>
Chris@0 22 #include <QCheckBox>
Chris@0 23 #include <QComboBox>
Chris@0 24 #include <QLabel>
Chris@33 25 #include <QFrame>
Chris@0 26
Chris@0 27 #include <cassert>
Chris@0 28 #include <iostream>
Chris@0 29
Chris@0 30 //#define DEBUG_PROPERTY_BOX 1
Chris@0 31
Chris@0 32 PropertyBox::PropertyBox(PropertyContainer *container) :
Chris@0 33 m_container(container)
Chris@0 34 {
Chris@0 35 #ifdef DEBUG_PROPERTY_BOX
Chris@0 36 std::cerr << "PropertyBox[" << this << "(\"" <<
Chris@0 37 container->getPropertyContainerName().toStdString() << "\")]::PropertyBox" << std::endl;
Chris@0 38 #endif
Chris@0 39
Chris@34 40 m_mainBox = new QVBoxLayout;
Chris@34 41 setLayout(m_mainBox);
Chris@33 42
Chris@33 43 bool needViewPlayBox = false;
Chris@33 44
Chris@34 45 m_mainWidget = new QWidget;
Chris@34 46 m_mainBox->addWidget(m_mainWidget);
Chris@34 47 m_mainBox->insertStretch(1, 10);
Chris@33 48
Chris@34 49 m_viewPlayFrame = 0;
Chris@34 50 populateViewPlayFrame();
Chris@33 51
Chris@0 52 m_layout = new QGridLayout;
Chris@34 53 m_layout->setMargin(0);
Chris@33 54 m_mainWidget->setLayout(m_layout);
Chris@0 55
Chris@34 56 PropertyContainer::PropertyList properties = m_container->getProperties();
Chris@0 57
Chris@0 58 blockSignals(true);
Chris@0 59
Chris@0 60 size_t i;
Chris@0 61
Chris@0 62 for (i = 0; i < properties.size(); ++i) {
Chris@0 63 updatePropertyEditor(properties[i]);
Chris@0 64 }
Chris@0 65
Chris@0 66 blockSignals(false);
Chris@0 67
Chris@0 68 m_layout->setRowStretch(m_layout->rowCount(), 10);
Chris@0 69
Chris@0 70 #ifdef DEBUG_PROPERTY_BOX
Chris@0 71 std::cerr << "PropertyBox[" << this << "]::PropertyBox returning" << std::endl;
Chris@0 72 #endif
Chris@0 73 }
Chris@0 74
Chris@0 75 PropertyBox::~PropertyBox()
Chris@0 76 {
Chris@0 77 #ifdef DEBUG_PROPERTY_BOX
Chris@33 78 std::cerr << "PropertyBox[" << this << "]::~PropertyBox" << std::endl;
Chris@0 79 #endif
Chris@0 80 }
Chris@0 81
Chris@0 82 void
Chris@34 83 PropertyBox::populateViewPlayFrame()
Chris@33 84 {
Chris@36 85 #ifdef DEBUG_PROPERTY_BOX
Chris@34 86 std::cerr << "PropertyBox(" << m_container << ")::populateViewPlayFrame" << std::endl;
Chris@36 87 #endif
Chris@34 88
Chris@34 89 if (m_viewPlayFrame) {
Chris@34 90 delete m_viewPlayFrame;
Chris@34 91 m_viewPlayFrame = 0;
Chris@34 92 }
Chris@34 93
Chris@34 94 if (!m_container) return;
Chris@34 95
Chris@34 96 Layer *layer = dynamic_cast<Layer *>(m_container);
Chris@34 97 if (layer) {
Chris@34 98 connect(layer, SIGNAL(modelReplaced()),
Chris@34 99 this, SLOT(populateViewPlayFrame()));
Chris@34 100 }
Chris@34 101
Chris@34 102 PlayParameters *params = m_container->getPlayParameters();
Chris@33 103 if (!params && !layer) return;
Chris@33 104
Chris@34 105 m_viewPlayFrame = new QFrame;
Chris@34 106 m_viewPlayFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
Chris@34 107 m_mainBox->addWidget(m_viewPlayFrame);
Chris@34 108
Chris@34 109 QHBoxLayout *layout = new QHBoxLayout;
Chris@34 110 m_viewPlayFrame->setLayout(layout);
Chris@34 111
Chris@34 112 layout->setMargin(layout->margin() / 2);
Chris@34 113
Chris@36 114 #ifdef DEBUG_PROPERTY_BOX
Chris@34 115 std::cerr << "PropertyBox::populateViewPlayFrame: container " << m_container << " (name " << m_container->getPropertyContainerName().toStdString() << ") params " << params << std::endl;
Chris@36 116 #endif
Chris@36 117
Chris@33 118 if (layer) {
Chris@34 119 QLabel *showLabel = new QLabel(tr("Show"));
Chris@34 120 layout->addWidget(showLabel);
Chris@34 121 layout->setAlignment(showLabel, Qt::AlignVCenter);
Chris@34 122
Chris@33 123 LEDButton *showButton = new LEDButton(Qt::blue);
Chris@33 124 layout->addWidget(showButton);
Chris@33 125 connect(showButton, SIGNAL(stateChanged(bool)),
Chris@33 126 layer, SLOT(showLayer(bool)));
Chris@34 127 layout->setAlignment(showButton, Qt::AlignVCenter);
Chris@33 128 }
Chris@33 129
Chris@33 130 if (params) {
Chris@34 131
Chris@34 132 QLabel *playLabel = new QLabel(tr("Play"));
Chris@34 133 layout->addWidget(playLabel);
Chris@34 134 layout->setAlignment(playLabel, Qt::AlignVCenter);
Chris@34 135
Chris@33 136 LEDButton *playButton = new LEDButton(Qt::darkGreen);
Chris@33 137 layout->addWidget(playButton);
Chris@33 138 connect(playButton, SIGNAL(stateChanged(bool)),
Chris@33 139 params, SLOT(setPlayAudible(bool)));
Chris@34 140 connect(params, SIGNAL(playAudibleChanged(bool)),
Chris@34 141 playButton, SLOT(setState(bool)));
Chris@34 142 layout->setAlignment(playButton, Qt::AlignVCenter);
Chris@34 143
Chris@34 144 layout->insertStretch(-1, 10);
Chris@34 145
Chris@34 146 AudioDial *gainDial = new AudioDial;
Chris@34 147 layout->addWidget(gainDial);
Chris@34 148 gainDial->setMeterColor(Qt::darkRed);
Chris@34 149 gainDial->setMinimum(-50);
Chris@34 150 gainDial->setMaximum(50);
Chris@34 151 gainDial->setPageStep(1);
Chris@34 152 gainDial->setFixedWidth(24);
Chris@34 153 gainDial->setFixedHeight(24);
Chris@34 154 gainDial->setNotchesVisible(false);
Chris@35 155 gainDial->setToolTip(tr("Layer playback Level"));
Chris@34 156 gainDial->setDefaultValue(0);
Chris@34 157 connect(gainDial, SIGNAL(valueChanged(int)),
Chris@34 158 this, SLOT(playGainDialChanged(int)));
Chris@34 159 connect(params, SIGNAL(playGainChanged(float)),
Chris@34 160 this, SLOT(playGainChanged(float)));
Chris@34 161 connect(this, SIGNAL(changePlayGain(float)),
Chris@34 162 params, SLOT(setPlayGain(float)));
Chris@34 163 connect(this, SIGNAL(changePlayGainDial(int)),
Chris@34 164 gainDial, SLOT(setValue(int)));
Chris@34 165 layout->setAlignment(gainDial, Qt::AlignVCenter);
Chris@34 166
Chris@34 167 AudioDial *panDial = new AudioDial;
Chris@34 168 layout->addWidget(panDial);
Chris@34 169 panDial->setMeterColor(Qt::darkGreen);
Chris@34 170 panDial->setMinimum(-50);
Chris@34 171 panDial->setMaximum(50);
Chris@34 172 panDial->setPageStep(1);
Chris@34 173 panDial->setFixedWidth(24);
Chris@34 174 panDial->setFixedHeight(24);
Chris@34 175 panDial->setNotchesVisible(false);
Chris@35 176 panDial->setToolTip(tr("Layer playback Pan / Balance"));
Chris@34 177 panDial->setDefaultValue(0);
Chris@34 178 connect(panDial, SIGNAL(valueChanged(int)),
Chris@34 179 this, SLOT(playPanDialChanged(int)));
Chris@34 180 connect(params, SIGNAL(playPanChanged(float)),
Chris@34 181 this, SLOT(playPanChanged(float)));
Chris@34 182 connect(this, SIGNAL(changePlayPan(float)),
Chris@34 183 params, SLOT(setPlayPan(float)));
Chris@34 184 connect(this, SIGNAL(changePlayPanDial(int)),
Chris@34 185 panDial, SLOT(setValue(int)));
Chris@34 186 layout->setAlignment(panDial, Qt::AlignVCenter);
Chris@34 187
Chris@34 188 } else {
Chris@34 189
Chris@34 190 layout->insertStretch(-1, 10);
Chris@33 191 }
Chris@33 192 }
Chris@33 193
Chris@33 194 void
Chris@0 195 PropertyBox::updatePropertyEditor(PropertyContainer::PropertyName name)
Chris@0 196 {
Chris@0 197 PropertyContainer::PropertyType type = m_container->getPropertyType(name);
Chris@0 198 int row = m_layout->rowCount();
Chris@0 199
Chris@0 200 int min = 0, max = 0, value = 0;
Chris@0 201 value = m_container->getPropertyRangeAndValue(name, &min, &max);
Chris@0 202
Chris@0 203 bool have = (m_propertyControllers.find(name) !=
Chris@0 204 m_propertyControllers.end());
Chris@0 205
Chris@0 206 QString groupName = m_container->getPropertyGroupName(name);
Chris@0 207
Chris@0 208 #ifdef DEBUG_PROPERTY_BOX
Chris@0 209 std::cerr << "PropertyBox[" << this
Chris@0 210 << "(\"" << m_container->getPropertyContainerName().toStdString()
Chris@0 211 << "\")]";
Chris@0 212 std::cerr << "::updatePropertyEditor(\"" << name.toStdString() << "\"):";
Chris@0 213 std::cerr << " value " << value << ", have " << have << ", group \""
Chris@0 214 << groupName.toStdString() << "\"" << std::endl;
Chris@0 215 #endif
Chris@0 216
Chris@0 217 bool inGroup = (groupName != QString());
Chris@0 218
Chris@0 219 if (!have) {
Chris@0 220 if (inGroup) {
Chris@0 221 if (m_groupLayouts.find(groupName) == m_groupLayouts.end()) {
Chris@0 222 #ifdef DEBUG_PROPERTY_BOX
Chris@0 223 std::cerr << "PropertyBox: adding label \"" << groupName.toStdString() << "\" and frame for group for \"" << name.toStdString() << "\"" << std::endl;
Chris@0 224 #endif
Chris@33 225 m_layout->addWidget(new QLabel(groupName, m_mainWidget), row, 0);
Chris@33 226 QFrame *frame = new QFrame(m_mainWidget);
Chris@0 227 m_layout->addWidget(frame, row, 1, 1, 2);
Chris@0 228 m_groupLayouts[groupName] = new QHBoxLayout;
Chris@0 229 m_groupLayouts[groupName]->setMargin(0);
Chris@0 230 frame->setLayout(m_groupLayouts[groupName]);
Chris@0 231 }
Chris@0 232 } else {
Chris@0 233 #ifdef DEBUG_PROPERTY_BOX
Chris@0 234 std::cerr << "PropertyBox: adding label \"" << name.toStdString() << "\"" << std::endl;
Chris@0 235 #endif
Chris@33 236 m_layout->addWidget(new QLabel(name, m_mainWidget), row, 0);
Chris@0 237 }
Chris@0 238 }
Chris@0 239
Chris@0 240 switch (type) {
Chris@0 241
Chris@0 242 case PropertyContainer::ToggleProperty:
Chris@0 243 {
Chris@0 244 QCheckBox *cb;
Chris@0 245
Chris@0 246 if (have) {
Chris@0 247 cb = dynamic_cast<QCheckBox *>(m_propertyControllers[name]);
Chris@0 248 assert(cb);
Chris@0 249 } else {
Chris@0 250 #ifdef DEBUG_PROPERTY_BOX
Chris@0 251 std::cerr << "PropertyBox: creating new checkbox" << std::endl;
Chris@0 252 #endif
Chris@0 253 cb = new QCheckBox();
Chris@0 254 cb->setObjectName(name);
Chris@0 255 connect(cb, SIGNAL(stateChanged(int)),
Chris@0 256 this, SLOT(propertyControllerChanged(int)));
Chris@0 257 if (inGroup) {
Chris@0 258 cb->setToolTip(name);
Chris@0 259 m_groupLayouts[groupName]->addWidget(cb);
Chris@0 260 } else {
Chris@0 261 m_layout->addWidget(cb, row, 1, 1, 2);
Chris@0 262 }
Chris@0 263 m_propertyControllers[name] = cb;
Chris@0 264 }
Chris@0 265
Chris@0 266 if (cb->isChecked() != (value > 0)) cb->setChecked(value > 0);
Chris@0 267 break;
Chris@0 268 }
Chris@0 269
Chris@0 270 case PropertyContainer::RangeProperty:
Chris@0 271 {
Chris@0 272 AudioDial *dial;
Chris@0 273
Chris@0 274 if (have) {
Chris@0 275 dial = dynamic_cast<AudioDial *>(m_propertyControllers[name]);
Chris@0 276 assert(dial);
Chris@0 277 } else {
Chris@0 278 #ifdef DEBUG_PROPERTY_BOX
Chris@0 279 std::cerr << "PropertyBox: creating new dial" << std::endl;
Chris@0 280 #endif
Chris@0 281 dial = new AudioDial();
Chris@0 282 dial->setObjectName(name);
Chris@0 283 dial->setMinimum(min);
Chris@0 284 dial->setMaximum(max);
Chris@0 285 dial->setPageStep(1);
Chris@34 286 dial->setNotchesVisible((max - min) <= 12);
Chris@34 287 dial->setDefaultValue(value);
Chris@0 288 connect(dial, SIGNAL(valueChanged(int)),
Chris@0 289 this, SLOT(propertyControllerChanged(int)));
Chris@0 290
Chris@0 291 if (inGroup) {
Chris@0 292 dial->setFixedWidth(24);
Chris@0 293 dial->setFixedHeight(24);
Chris@0 294 dial->setToolTip(name);
Chris@0 295 m_groupLayouts[groupName]->addWidget(dial);
Chris@0 296 } else {
Chris@0 297 dial->setFixedWidth(32);
Chris@0 298 dial->setFixedHeight(32);
Chris@0 299 m_layout->addWidget(dial, row, 1);
Chris@33 300 QLabel *label = new QLabel(m_mainWidget);
Chris@0 301 connect(dial, SIGNAL(valueChanged(int)),
Chris@0 302 label, SLOT(setNum(int)));
Chris@0 303 label->setNum(value);
Chris@0 304 m_layout->addWidget(label, row, 2);
Chris@0 305 }
Chris@0 306
Chris@0 307 m_propertyControllers[name] = dial;
Chris@0 308 }
Chris@0 309
Chris@0 310 if (dial->value() != value) dial->setValue(value);
Chris@0 311 break;
Chris@0 312 }
Chris@0 313
Chris@0 314 case PropertyContainer::ValueProperty:
Chris@0 315 {
Chris@0 316 QComboBox *cb;
Chris@0 317
Chris@0 318 if (have) {
Chris@0 319 cb = dynamic_cast<QComboBox *>(m_propertyControllers[name]);
Chris@0 320 assert(cb);
Chris@0 321 } else {
Chris@0 322 #ifdef DEBUG_PROPERTY_BOX
Chris@0 323 std::cerr << "PropertyBox: creating new combobox" << std::endl;
Chris@0 324 #endif
Chris@0 325
Chris@0 326 cb = new QComboBox();
Chris@0 327 cb->setObjectName(name);
Chris@0 328 for (int i = min; i <= max; ++i) {
Chris@0 329 cb->addItem(m_container->getPropertyValueLabel(name, i));
Chris@0 330 }
Chris@0 331 connect(cb, SIGNAL(activated(int)),
Chris@0 332 this, SLOT(propertyControllerChanged(int)));
Chris@0 333 if (inGroup) {
Chris@0 334 cb->setToolTip(name);
Chris@0 335 m_groupLayouts[groupName]->addWidget(cb);
Chris@0 336 } else {
Chris@0 337 m_layout->addWidget(cb, row, 1, 1, 2);
Chris@0 338 }
Chris@0 339 m_propertyControllers[name] = cb;
Chris@0 340 }
Chris@0 341
Chris@0 342 if (cb->currentIndex() != value) cb->setCurrentIndex(value);
Chris@0 343
Chris@0 344 #ifdef Q_WS_MAC
Chris@0 345 // Crashes on startup without this, for some reason
Chris@0 346 cb->setMinimumSize(QSize(10, 10));
Chris@0 347 #endif
Chris@0 348
Chris@0 349 break;
Chris@0 350 }
Chris@0 351
Chris@0 352 default:
Chris@0 353 break;
Chris@0 354 }
Chris@0 355 }
Chris@0 356
Chris@0 357 void
Chris@0 358 PropertyBox::propertyContainerPropertyChanged(PropertyContainer *pc)
Chris@0 359 {
Chris@0 360 if (pc != m_container) return;
Chris@0 361
Chris@0 362 PropertyContainer::PropertyList properties = m_container->getProperties();
Chris@0 363 size_t i;
Chris@0 364
Chris@0 365 blockSignals(true);
Chris@0 366
Chris@0 367 for (i = 0; i < properties.size(); ++i) {
Chris@0 368 updatePropertyEditor(properties[i]);
Chris@0 369 }
Chris@0 370
Chris@0 371 blockSignals(false);
Chris@0 372 }
Chris@0 373
Chris@0 374 void
Chris@0 375 PropertyBox::propertyControllerChanged(int value)
Chris@0 376 {
Chris@0 377 QObject *obj = sender();
Chris@0 378 QString name = obj->objectName();
Chris@0 379
Chris@34 380 #ifdef DEBUG_PROPERTY_BOX
Chris@33 381 std::cerr << "PropertyBox::propertyControllerChanged(" << name.toStdString()
Chris@33 382 << ", " << value << ")" << std::endl;
Chris@34 383 #endif
Chris@0 384
Chris@0 385 PropertyContainer::PropertyType type = m_container->getPropertyType(name);
Chris@0 386
Chris@0 387 if (type != PropertyContainer::InvalidProperty) {
Chris@0 388 m_container->setProperty(name, value);
Chris@0 389 }
Chris@0 390
Chris@0 391 if (type == PropertyContainer::RangeProperty) {
Chris@0 392 AudioDial *dial = dynamic_cast<AudioDial *>(m_propertyControllers[name]);
Chris@0 393 if (dial) {
Chris@0 394 dial->setToolTip(QString("%1: %2").arg(name).arg(value));
Chris@0 395 //!!! unfortunately this doesn't update an already-visible tooltip
Chris@0 396 }
Chris@0 397 }
Chris@0 398 }
Chris@0 399
Chris@34 400 void
Chris@34 401 PropertyBox::playGainChanged(float gain)
Chris@34 402 {
Chris@34 403 int dialValue = lrint(log10(gain) * 20.0);
Chris@34 404 if (dialValue < -50) dialValue = -50;
Chris@34 405 if (dialValue > 50) dialValue = 50;
Chris@34 406 emit changePlayGainDial(dialValue);
Chris@34 407 }
Chris@34 408
Chris@34 409 void
Chris@34 410 PropertyBox::playGainDialChanged(int dialValue)
Chris@34 411 {
Chris@34 412 float gain = pow(10, float(dialValue) / 20.0);
Chris@34 413 emit changePlayGain(gain);
Chris@34 414 }
Chris@34 415
Chris@34 416 void
Chris@34 417 PropertyBox::playPanChanged(float pan)
Chris@34 418 {
Chris@34 419 int dialValue = lrint(pan * 50.0);
Chris@34 420 if (dialValue < -50) dialValue = -50;
Chris@34 421 if (dialValue > 50) dialValue = 50;
Chris@34 422 emit changePlayPanDial(dialValue);
Chris@34 423 }
Chris@34 424
Chris@34 425 void
Chris@34 426 PropertyBox::playPanDialChanged(int dialValue)
Chris@34 427 {
Chris@34 428 float pan = float(dialValue) / 50.0;
Chris@34 429 if (pan < -1.0) pan = -1.0;
Chris@34 430 if (pan > 1.0) pan = 1.0;
Chris@34 431 emit changePlayPan(pan);
Chris@34 432 }
Chris@0 433
Chris@0 434 #ifdef INCLUDE_MOCFILES
Chris@0 435 #include "PropertyBox.moc.cpp"
Chris@0 436 #endif
Chris@0 437