Chris@0: /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /* Chris@0: A waveform viewer and audio annotation editor. Chris@5: Chris Cannam, Queen Mary University of London, 2005-2006 Chris@0: Chris@0: This is experimental software. Not for distribution. Chris@0: */ Chris@0: Chris@0: #include "PropertyBox.h" Chris@0: Chris@0: #include "base/PropertyContainer.h" Chris@33: #include "base/PlayParameters.h" Chris@33: #include "base/Layer.h" Chris@0: Chris@0: #include "AudioDial.h" Chris@33: #include "LEDButton.h" Chris@0: Chris@0: #include Chris@0: #include Chris@33: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@33: #include Chris@0: Chris@0: #include Chris@0: #include Chris@0: Chris@0: //#define DEBUG_PROPERTY_BOX 1 Chris@0: Chris@0: PropertyBox::PropertyBox(PropertyContainer *container) : Chris@0: m_container(container) Chris@0: { Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@0: std::cerr << "PropertyBox[" << this << "(\"" << Chris@0: container->getPropertyContainerName().toStdString() << "\")]::PropertyBox" << std::endl; Chris@0: #endif Chris@0: Chris@34: m_mainBox = new QVBoxLayout; Chris@34: setLayout(m_mainBox); Chris@33: Chris@33: bool needViewPlayBox = false; Chris@33: Chris@34: m_mainWidget = new QWidget; Chris@34: m_mainBox->addWidget(m_mainWidget); Chris@34: m_mainBox->insertStretch(1, 10); Chris@33: Chris@34: m_viewPlayFrame = 0; Chris@34: populateViewPlayFrame(); Chris@33: Chris@0: m_layout = new QGridLayout; Chris@34: m_layout->setMargin(0); Chris@33: m_mainWidget->setLayout(m_layout); Chris@0: Chris@34: PropertyContainer::PropertyList properties = m_container->getProperties(); Chris@0: Chris@0: blockSignals(true); Chris@0: Chris@0: size_t i; Chris@0: Chris@0: for (i = 0; i < properties.size(); ++i) { Chris@0: updatePropertyEditor(properties[i]); Chris@0: } Chris@0: Chris@0: blockSignals(false); Chris@0: Chris@0: m_layout->setRowStretch(m_layout->rowCount(), 10); Chris@0: Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@0: std::cerr << "PropertyBox[" << this << "]::PropertyBox returning" << std::endl; Chris@0: #endif Chris@0: } Chris@0: Chris@0: PropertyBox::~PropertyBox() Chris@0: { Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@33: std::cerr << "PropertyBox[" << this << "]::~PropertyBox" << std::endl; Chris@0: #endif Chris@0: } Chris@0: Chris@0: void Chris@34: PropertyBox::populateViewPlayFrame() Chris@33: { Chris@36: #ifdef DEBUG_PROPERTY_BOX Chris@34: std::cerr << "PropertyBox(" << m_container << ")::populateViewPlayFrame" << std::endl; Chris@36: #endif Chris@34: Chris@34: if (m_viewPlayFrame) { Chris@34: delete m_viewPlayFrame; Chris@34: m_viewPlayFrame = 0; Chris@34: } Chris@34: Chris@34: if (!m_container) return; Chris@34: Chris@34: Layer *layer = dynamic_cast(m_container); Chris@34: if (layer) { Chris@34: connect(layer, SIGNAL(modelReplaced()), Chris@34: this, SLOT(populateViewPlayFrame())); Chris@34: } Chris@34: Chris@34: PlayParameters *params = m_container->getPlayParameters(); Chris@33: if (!params && !layer) return; Chris@33: Chris@34: m_viewPlayFrame = new QFrame; Chris@34: m_viewPlayFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); Chris@34: m_mainBox->addWidget(m_viewPlayFrame); Chris@34: Chris@34: QHBoxLayout *layout = new QHBoxLayout; Chris@34: m_viewPlayFrame->setLayout(layout); Chris@34: Chris@34: layout->setMargin(layout->margin() / 2); Chris@34: Chris@36: #ifdef DEBUG_PROPERTY_BOX Chris@34: std::cerr << "PropertyBox::populateViewPlayFrame: container " << m_container << " (name " << m_container->getPropertyContainerName().toStdString() << ") params " << params << std::endl; Chris@36: #endif Chris@36: Chris@33: if (layer) { Chris@34: QLabel *showLabel = new QLabel(tr("Show")); Chris@34: layout->addWidget(showLabel); Chris@34: layout->setAlignment(showLabel, Qt::AlignVCenter); Chris@34: Chris@33: LEDButton *showButton = new LEDButton(Qt::blue); Chris@33: layout->addWidget(showButton); Chris@33: connect(showButton, SIGNAL(stateChanged(bool)), Chris@33: layer, SLOT(showLayer(bool))); Chris@34: layout->setAlignment(showButton, Qt::AlignVCenter); Chris@33: } Chris@33: Chris@33: if (params) { Chris@34: Chris@34: QLabel *playLabel = new QLabel(tr("Play")); Chris@34: layout->addWidget(playLabel); Chris@34: layout->setAlignment(playLabel, Qt::AlignVCenter); Chris@34: Chris@33: LEDButton *playButton = new LEDButton(Qt::darkGreen); Chris@33: layout->addWidget(playButton); Chris@33: connect(playButton, SIGNAL(stateChanged(bool)), Chris@33: params, SLOT(setPlayAudible(bool))); Chris@34: connect(params, SIGNAL(playAudibleChanged(bool)), Chris@34: playButton, SLOT(setState(bool))); Chris@34: layout->setAlignment(playButton, Qt::AlignVCenter); Chris@34: Chris@34: layout->insertStretch(-1, 10); Chris@34: Chris@34: AudioDial *gainDial = new AudioDial; Chris@34: layout->addWidget(gainDial); Chris@34: gainDial->setMeterColor(Qt::darkRed); Chris@34: gainDial->setMinimum(-50); Chris@34: gainDial->setMaximum(50); Chris@34: gainDial->setPageStep(1); Chris@34: gainDial->setFixedWidth(24); Chris@34: gainDial->setFixedHeight(24); Chris@34: gainDial->setNotchesVisible(false); Chris@35: gainDial->setToolTip(tr("Layer playback Level")); Chris@34: gainDial->setDefaultValue(0); Chris@34: connect(gainDial, SIGNAL(valueChanged(int)), Chris@34: this, SLOT(playGainDialChanged(int))); Chris@34: connect(params, SIGNAL(playGainChanged(float)), Chris@34: this, SLOT(playGainChanged(float))); Chris@34: connect(this, SIGNAL(changePlayGain(float)), Chris@34: params, SLOT(setPlayGain(float))); Chris@34: connect(this, SIGNAL(changePlayGainDial(int)), Chris@34: gainDial, SLOT(setValue(int))); Chris@34: layout->setAlignment(gainDial, Qt::AlignVCenter); Chris@34: Chris@34: AudioDial *panDial = new AudioDial; Chris@34: layout->addWidget(panDial); Chris@34: panDial->setMeterColor(Qt::darkGreen); Chris@34: panDial->setMinimum(-50); Chris@34: panDial->setMaximum(50); Chris@34: panDial->setPageStep(1); Chris@34: panDial->setFixedWidth(24); Chris@34: panDial->setFixedHeight(24); Chris@34: panDial->setNotchesVisible(false); Chris@35: panDial->setToolTip(tr("Layer playback Pan / Balance")); Chris@34: panDial->setDefaultValue(0); Chris@34: connect(panDial, SIGNAL(valueChanged(int)), Chris@34: this, SLOT(playPanDialChanged(int))); Chris@34: connect(params, SIGNAL(playPanChanged(float)), Chris@34: this, SLOT(playPanChanged(float))); Chris@34: connect(this, SIGNAL(changePlayPan(float)), Chris@34: params, SLOT(setPlayPan(float))); Chris@34: connect(this, SIGNAL(changePlayPanDial(int)), Chris@34: panDial, SLOT(setValue(int))); Chris@34: layout->setAlignment(panDial, Qt::AlignVCenter); Chris@34: Chris@34: } else { Chris@34: Chris@34: layout->insertStretch(-1, 10); Chris@33: } Chris@33: } Chris@33: Chris@33: void Chris@0: PropertyBox::updatePropertyEditor(PropertyContainer::PropertyName name) Chris@0: { Chris@0: PropertyContainer::PropertyType type = m_container->getPropertyType(name); Chris@0: int row = m_layout->rowCount(); Chris@0: Chris@0: int min = 0, max = 0, value = 0; Chris@0: value = m_container->getPropertyRangeAndValue(name, &min, &max); Chris@0: Chris@0: bool have = (m_propertyControllers.find(name) != Chris@0: m_propertyControllers.end()); Chris@0: Chris@0: QString groupName = m_container->getPropertyGroupName(name); Chris@0: Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@0: std::cerr << "PropertyBox[" << this Chris@0: << "(\"" << m_container->getPropertyContainerName().toStdString() Chris@0: << "\")]"; Chris@0: std::cerr << "::updatePropertyEditor(\"" << name.toStdString() << "\"):"; Chris@0: std::cerr << " value " << value << ", have " << have << ", group \"" Chris@0: << groupName.toStdString() << "\"" << std::endl; Chris@0: #endif Chris@0: Chris@0: bool inGroup = (groupName != QString()); Chris@0: Chris@0: if (!have) { Chris@0: if (inGroup) { Chris@0: if (m_groupLayouts.find(groupName) == m_groupLayouts.end()) { Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@0: std::cerr << "PropertyBox: adding label \"" << groupName.toStdString() << "\" and frame for group for \"" << name.toStdString() << "\"" << std::endl; Chris@0: #endif Chris@33: m_layout->addWidget(new QLabel(groupName, m_mainWidget), row, 0); Chris@33: QFrame *frame = new QFrame(m_mainWidget); Chris@0: m_layout->addWidget(frame, row, 1, 1, 2); Chris@0: m_groupLayouts[groupName] = new QHBoxLayout; Chris@0: m_groupLayouts[groupName]->setMargin(0); Chris@0: frame->setLayout(m_groupLayouts[groupName]); Chris@0: } Chris@0: } else { Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@0: std::cerr << "PropertyBox: adding label \"" << name.toStdString() << "\"" << std::endl; Chris@0: #endif Chris@33: m_layout->addWidget(new QLabel(name, m_mainWidget), row, 0); Chris@0: } Chris@0: } Chris@0: Chris@0: switch (type) { Chris@0: Chris@0: case PropertyContainer::ToggleProperty: Chris@0: { Chris@0: QCheckBox *cb; Chris@0: Chris@0: if (have) { Chris@0: cb = dynamic_cast(m_propertyControllers[name]); Chris@0: assert(cb); Chris@0: } else { Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@0: std::cerr << "PropertyBox: creating new checkbox" << std::endl; Chris@0: #endif Chris@0: cb = new QCheckBox(); Chris@0: cb->setObjectName(name); Chris@0: connect(cb, SIGNAL(stateChanged(int)), Chris@0: this, SLOT(propertyControllerChanged(int))); Chris@0: if (inGroup) { Chris@0: cb->setToolTip(name); Chris@0: m_groupLayouts[groupName]->addWidget(cb); Chris@0: } else { Chris@0: m_layout->addWidget(cb, row, 1, 1, 2); Chris@0: } Chris@0: m_propertyControllers[name] = cb; Chris@0: } Chris@0: Chris@0: if (cb->isChecked() != (value > 0)) cb->setChecked(value > 0); Chris@0: break; Chris@0: } Chris@0: Chris@0: case PropertyContainer::RangeProperty: Chris@0: { Chris@0: AudioDial *dial; Chris@0: Chris@0: if (have) { Chris@0: dial = dynamic_cast(m_propertyControllers[name]); Chris@0: assert(dial); Chris@0: } else { Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@0: std::cerr << "PropertyBox: creating new dial" << std::endl; Chris@0: #endif Chris@0: dial = new AudioDial(); Chris@0: dial->setObjectName(name); Chris@0: dial->setMinimum(min); Chris@0: dial->setMaximum(max); Chris@0: dial->setPageStep(1); Chris@34: dial->setNotchesVisible((max - min) <= 12); Chris@34: dial->setDefaultValue(value); Chris@0: connect(dial, SIGNAL(valueChanged(int)), Chris@0: this, SLOT(propertyControllerChanged(int))); Chris@0: Chris@0: if (inGroup) { Chris@0: dial->setFixedWidth(24); Chris@0: dial->setFixedHeight(24); Chris@0: dial->setToolTip(name); Chris@0: m_groupLayouts[groupName]->addWidget(dial); Chris@0: } else { Chris@0: dial->setFixedWidth(32); Chris@0: dial->setFixedHeight(32); Chris@0: m_layout->addWidget(dial, row, 1); Chris@33: QLabel *label = new QLabel(m_mainWidget); Chris@0: connect(dial, SIGNAL(valueChanged(int)), Chris@0: label, SLOT(setNum(int))); Chris@0: label->setNum(value); Chris@0: m_layout->addWidget(label, row, 2); Chris@0: } Chris@0: Chris@0: m_propertyControllers[name] = dial; Chris@0: } Chris@0: Chris@0: if (dial->value() != value) dial->setValue(value); Chris@0: break; Chris@0: } Chris@0: Chris@0: case PropertyContainer::ValueProperty: Chris@0: { Chris@0: QComboBox *cb; Chris@0: Chris@0: if (have) { Chris@0: cb = dynamic_cast(m_propertyControllers[name]); Chris@0: assert(cb); Chris@0: } else { Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@0: std::cerr << "PropertyBox: creating new combobox" << std::endl; Chris@0: #endif Chris@0: Chris@0: cb = new QComboBox(); Chris@0: cb->setObjectName(name); Chris@0: for (int i = min; i <= max; ++i) { Chris@0: cb->addItem(m_container->getPropertyValueLabel(name, i)); Chris@0: } Chris@0: connect(cb, SIGNAL(activated(int)), Chris@0: this, SLOT(propertyControllerChanged(int))); Chris@0: if (inGroup) { Chris@0: cb->setToolTip(name); Chris@0: m_groupLayouts[groupName]->addWidget(cb); Chris@0: } else { Chris@0: m_layout->addWidget(cb, row, 1, 1, 2); Chris@0: } Chris@0: m_propertyControllers[name] = cb; Chris@0: } Chris@0: Chris@0: if (cb->currentIndex() != value) cb->setCurrentIndex(value); Chris@0: Chris@0: #ifdef Q_WS_MAC Chris@0: // Crashes on startup without this, for some reason Chris@0: cb->setMinimumSize(QSize(10, 10)); Chris@0: #endif Chris@0: Chris@0: break; Chris@0: } Chris@0: Chris@0: default: Chris@0: break; Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: PropertyBox::propertyContainerPropertyChanged(PropertyContainer *pc) Chris@0: { Chris@0: if (pc != m_container) return; Chris@0: Chris@0: PropertyContainer::PropertyList properties = m_container->getProperties(); Chris@0: size_t i; Chris@0: Chris@0: blockSignals(true); Chris@0: Chris@0: for (i = 0; i < properties.size(); ++i) { Chris@0: updatePropertyEditor(properties[i]); Chris@0: } Chris@0: Chris@0: blockSignals(false); Chris@0: } Chris@0: Chris@0: void Chris@0: PropertyBox::propertyControllerChanged(int value) Chris@0: { Chris@0: QObject *obj = sender(); Chris@0: QString name = obj->objectName(); Chris@0: Chris@34: #ifdef DEBUG_PROPERTY_BOX Chris@33: std::cerr << "PropertyBox::propertyControllerChanged(" << name.toStdString() Chris@33: << ", " << value << ")" << std::endl; Chris@34: #endif Chris@0: Chris@0: PropertyContainer::PropertyType type = m_container->getPropertyType(name); Chris@0: Chris@0: if (type != PropertyContainer::InvalidProperty) { Chris@0: m_container->setProperty(name, value); Chris@0: } Chris@0: Chris@0: if (type == PropertyContainer::RangeProperty) { Chris@0: AudioDial *dial = dynamic_cast(m_propertyControllers[name]); Chris@0: if (dial) { Chris@0: dial->setToolTip(QString("%1: %2").arg(name).arg(value)); Chris@0: //!!! unfortunately this doesn't update an already-visible tooltip Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@34: void Chris@34: PropertyBox::playGainChanged(float gain) Chris@34: { Chris@34: int dialValue = lrint(log10(gain) * 20.0); Chris@34: if (dialValue < -50) dialValue = -50; Chris@34: if (dialValue > 50) dialValue = 50; Chris@34: emit changePlayGainDial(dialValue); Chris@34: } Chris@34: Chris@34: void Chris@34: PropertyBox::playGainDialChanged(int dialValue) Chris@34: { Chris@34: float gain = pow(10, float(dialValue) / 20.0); Chris@34: emit changePlayGain(gain); Chris@34: } Chris@34: Chris@34: void Chris@34: PropertyBox::playPanChanged(float pan) Chris@34: { Chris@34: int dialValue = lrint(pan * 50.0); Chris@34: if (dialValue < -50) dialValue = -50; Chris@34: if (dialValue > 50) dialValue = 50; Chris@34: emit changePlayPanDial(dialValue); Chris@34: } Chris@34: Chris@34: void Chris@34: PropertyBox::playPanDialChanged(int dialValue) Chris@34: { Chris@34: float pan = float(dialValue) / 50.0; Chris@34: if (pan < -1.0) pan = -1.0; Chris@34: if (pan > 1.0) pan = 1.0; Chris@34: emit changePlayPan(pan); Chris@34: } Chris@0: Chris@0: #ifdef INCLUDE_MOCFILES Chris@0: #include "PropertyBox.moc.cpp" Chris@0: #endif Chris@0: