Chris@58: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /* Chris@59: Sonic Visualiser Chris@59: An audio file viewer and annotation editor. Chris@59: Centre for Digital Music, Queen Mary, University of London. Chris@182: This file copyright 2006 Chris Cannam and QMUL. Chris@0: Chris@59: This program is free software; you can redistribute it and/or Chris@59: modify it under the terms of the GNU General Public License as Chris@59: published by the Free Software Foundation; either version 2 of the Chris@59: License, or (at your option) any later version. See the file Chris@59: COPYING included with this distribution for more information. Chris@0: */ Chris@0: Chris@0: #include "PropertyBox.h" Chris@63: #include "PluginParameterDialog.h" Chris@0: Chris@0: #include "base/PropertyContainer.h" Chris@33: #include "base/PlayParameters.h" Chris@377: #include "base/PlayParameterRepository.h" Chris@128: #include "layer/Layer.h" Chris@100: #include "base/UnitDatabase.h" Chris@167: #include "base/RangeMapper.h" Chris@0: Chris@0: #include "AudioDial.h" Chris@33: #include "LEDButton.h" Chris@335: #include "IconLoader.h" Chris@1178: #include "LevelPanWidget.h" Chris@1179: #include "LevelPanToolButton.h" Chris@1174: #include "WidgetScale.h" Chris@1587: #include "MenuTitle.h" Chris@0: Chris@189: #include "NotifyingCheckBox.h" Chris@189: #include "NotifyingComboBox.h" Chris@335: #include "NotifyingPushButton.h" Chris@1189: #include "NotifyingToolButton.h" Chris@1196: #include "ColourComboBox.h" Chris@1198: #include "ColourMapComboBox.h" Chris@189: Chris@0: #include Chris@0: #include Chris@33: #include Chris@63: #include Chris@1189: #include Chris@0: #include Chris@33: #include Chris@218: #include Chris@285: #include Chris@285: #include Chris@769: #include Chris@1587: #include Chris@0: Chris@0: #include Chris@0: #include Martin@46: #include Chris@0: Chris@456: //#define DEBUG_PROPERTY_BOX 1 Chris@0: Chris@0: PropertyBox::PropertyBox(PropertyContainer *container) : Chris@185: m_container(container), Chris@1408: m_showButton(nullptr), Chris@1587: m_playButton(nullptr), Chris@1587: m_lastContextMenu(nullptr) Chris@0: { Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@1525: SVDEBUG << "PropertyBox[" << this << "(\"" << Chris@1266: container->getPropertyContainerName() << "\" at " << container << ")]::PropertyBox" << endl; Chris@0: #endif Chris@0: Chris@34: m_mainBox = new QVBoxLayout; Chris@34: setLayout(m_mainBox); Chris@33: Chris@980: #ifdef Q_OS_MAC Chris@980: QMargins mm = m_mainBox->contentsMargins(); Chris@980: QMargins mmhalf(mm.left()/2, mm.top()/3, mm.right()/2, mm.bottom()/3); Chris@980: m_mainBox->setContentsMargins(mmhalf); Chris@980: #endif Chris@980: Chris@107: // m_nameWidget = new QLabel; Chris@107: // m_mainBox->addWidget(m_nameWidget); Chris@107: // m_nameWidget->setText(container->objectName()); Chris@107: Chris@34: m_mainWidget = new QWidget; Chris@34: m_mainBox->addWidget(m_mainWidget); Chris@107: m_mainBox->insertStretch(2, 10); Chris@33: Chris@1408: m_viewPlayFrame = nullptr; Chris@34: populateViewPlayFrame(); Chris@33: Chris@0: m_layout = new QGridLayout; Chris@34: m_layout->setMargin(0); Chris@833: m_layout->setHorizontalSpacing(2); Chris@833: m_layout->setVerticalSpacing(1); 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@1266: 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@100: connect(UnitDatabase::getInstance(), SIGNAL(unitDatabaseChanged()), Chris@100: this, SLOT(unitDatabaseChanged())); Chris@100: Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@1525: SVDEBUG << "PropertyBox[" << this << "]::PropertyBox returning" << endl; Chris@0: #endif Chris@0: } Chris@0: Chris@0: PropertyBox::~PropertyBox() Chris@0: { Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@1525: SVDEBUG << "PropertyBox[" << this << "]::~PropertyBox" << endl; Chris@0: #endif Chris@1587: delete m_lastContextMenu; Chris@0: } Chris@0: Chris@0: void Chris@34: PropertyBox::populateViewPlayFrame() Chris@33: { Chris@36: #ifdef DEBUG_PROPERTY_BOX Chris@1525: SVDEBUG << "PropertyBox[" << this << ":" << m_container << "]::populateViewPlayFrame" << endl; Chris@36: #endif Chris@34: Chris@34: if (m_viewPlayFrame) { Chris@1266: delete m_viewPlayFrame; Chris@1408: m_viewPlayFrame = nullptr; 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@1266: disconnect(layer, SIGNAL(modelReplaced()), Chris@193: this, SLOT(populateViewPlayFrame())); Chris@1266: connect(layer, SIGNAL(modelReplaced()), Chris@1266: this, SLOT(populateViewPlayFrame())); Chris@34: } Chris@34: Chris@1480: auto 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@1189: QGridLayout *layout = new QGridLayout; Chris@34: m_viewPlayFrame->setLayout(layout); Chris@34: Chris@34: layout->setMargin(layout->margin() / 2); Chris@34: Chris@36: #ifdef DEBUG_PROPERTY_BOX Chris@587: SVDEBUG << "PropertyBox::populateViewPlayFrame: container " << m_container << " (name " << m_container->getPropertyContainerName() << ") params " << params << endl; Chris@36: #endif Chris@1189: Chris@1189: QSize buttonSize = WidgetScale::scaleQSize(QSize(26, 26)); Chris@1189: int col = 0; Chris@1189: Chris@33: if (params) { Chris@1189: Chris@1189: m_playButton = new NotifyingToolButton; Chris@1187: m_playButton->setCheckable(true); Chris@1187: m_playButton->setIcon(IconLoader().load("speaker")); Chris@1190: m_playButton->setToolTip(tr("Click to toggle playback")); Chris@1187: m_playButton->setChecked(!params->isPlayMuted()); Chris@1189: m_playButton->setFixedSize(buttonSize); Chris@1266: connect(m_playButton, SIGNAL(toggled(bool)), Chris@1266: this, SLOT(playAudibleButtonChanged(bool))); Chris@1187: connect(m_playButton, SIGNAL(mouseEntered()), Chris@1187: this, SLOT(mouseEnteredWidget())); Chris@1187: connect(m_playButton, SIGNAL(mouseLeft()), Chris@1187: this, SLOT(mouseLeftWidget())); Chris@1480: connect(params.get(), SIGNAL(playAudibleChanged(bool)), Chris@1266: this, SLOT(playAudibleChanged(bool))); Chris@63: Chris@1179: LevelPanToolButton *levelPan = new LevelPanToolButton; Chris@1189: levelPan->setFixedSize(buttonSize); Chris@1189: levelPan->setImageSize((buttonSize.height() * 3) / 4); Chris@1189: layout->addWidget(levelPan, 0, col++, Qt::AlignCenter); Chris@1178: connect(levelPan, SIGNAL(levelChanged(float)), Chris@1178: this, SLOT(playGainControlChanged(float))); Chris@1178: connect(levelPan, SIGNAL(panChanged(float)), Chris@1178: this, SLOT(playPanControlChanged(float))); Chris@1480: connect(params.get(), SIGNAL(playGainChanged(float)), Chris@1178: levelPan, SLOT(setLevel(float))); Chris@1480: connect(params.get(), SIGNAL(playPanChanged(float)), Chris@1178: levelPan, SLOT(setPan(float))); Chris@1180: connect(levelPan, SIGNAL(mouseEntered()), Chris@1180: this, SLOT(mouseEnteredWidget())); Chris@1180: connect(levelPan, SIGNAL(mouseLeft()), Chris@1180: this, SLOT(mouseLeftWidget())); Chris@1180: Chris@1266: layout->addWidget(m_playButton, 0, col++, Qt::AlignCenter); Chris@1189: Chris@1187: if (params->getPlayClipId() != "") { Chris@1223: NotifyingToolButton *playParamButton = new NotifyingToolButton; Chris@1187: playParamButton->setObjectName("playParamButton"); Chris@1187: playParamButton->setIcon(IconLoader().load("faders")); Chris@1189: playParamButton->setFixedSize(buttonSize); Chris@1189: layout->addWidget(playParamButton, 0, col++, Qt::AlignCenter); Chris@1187: connect(playParamButton, SIGNAL(clicked()), Chris@1187: this, SLOT(editPlayParameters())); Chris@1187: connect(playParamButton, SIGNAL(mouseEntered()), Chris@1187: this, SLOT(mouseEnteredWidget())); Chris@1187: connect(playParamButton, SIGNAL(mouseLeft()), Chris@1187: this, SLOT(mouseLeftWidget())); Chris@1187: } Chris@1187: } Chris@1187: Chris@1189: layout->setColumnStretch(col++, 10); Chris@1187: Chris@1187: if (layer) { Chris@1187: Chris@1266: QLabel *showLabel = new QLabel(tr("Show")); Chris@1266: layout->addWidget(showLabel, 0, col++, Qt::AlignVCenter | Qt::AlignRight); Chris@1187: Chris@1266: m_showButton = new LEDButton(palette().highlight().color()); Chris@1266: layout->addWidget(m_showButton, 0, col++, Qt::AlignVCenter | Qt::AlignLeft); Chris@1266: connect(m_showButton, SIGNAL(stateChanged(bool)), Chris@1266: this, SIGNAL(showLayer(bool))); Chris@1187: connect(m_showButton, SIGNAL(mouseEntered()), Chris@1180: this, SLOT(mouseEnteredWidget())); Chris@1187: connect(m_showButton, SIGNAL(mouseLeft()), Chris@1180: this, SLOT(mouseLeftWidget())); Chris@33: } Chris@33: } Chris@33: Chris@33: void Chris@197: PropertyBox::updatePropertyEditor(PropertyContainer::PropertyName name, Chris@197: bool rangeChanged) Chris@0: { Chris@0: PropertyContainer::PropertyType type = m_container->getPropertyType(name); Chris@0: int row = m_layout->rowCount(); Chris@0: Chris@216: int min = 0, max = 0, value = 0, deflt = 0; Chris@216: value = m_container->getPropertyRangeAndValue(name, &min, &max, &deflt); Chris@0: Chris@0: bool have = (m_propertyControllers.find(name) != Chris@1266: m_propertyControllers.end()); Chris@0: Chris@0: QString groupName = m_container->getPropertyGroupName(name); Chris@87: QString propertyLabel = m_container->getPropertyLabel(name); Chris@335: QString iconName = m_container->getPropertyIconName(name); Chris@0: Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@1525: SVDEBUG << "PropertyBox[" << this Chris@1266: << "(\"" << m_container->getPropertyContainerName() Chris@1266: << "\")]"; Chris@1525: SVDEBUG << "::updatePropertyEditor(\"" << name << "\", " Chris@1281: << rangeChanged << "):"; Chris@1525: SVDEBUG << " type " << type << ", value " << value Chris@1281: << ", have " << have << ", group \"" << groupName << "\"" << endl; Chris@0: #endif Chris@0: Chris@1204: QString groupLabel = groupName; Chris@1204: if (groupName == QString()) { Chris@1204: groupName = "ungrouped: " + name; // not tr(), this is internal id Chris@1204: groupLabel = propertyLabel; Chris@1204: } Chris@1204: Chris@0: if (!have) { Chris@1204: if (m_groupLayouts.find(groupName) == m_groupLayouts.end()) { Chris@1204: QWidget *labelWidget = new QLabel(groupLabel, m_mainWidget); Chris@1190: m_layout->addWidget(labelWidget, row, 0); Chris@1190: QWidget *frame = new QWidget(m_mainWidget); Chris@1190: frame->setMinimumSize(WidgetScale::scaleQSize(QSize(1, 24))); Chris@1190: m_groupLayouts[groupName] = new QGridLayout; Chris@1195: #ifdef Q_OS_MAC Chris@1195: // Seems to be plenty of whitespace already Chris@1195: m_groupLayouts[groupName]->setContentsMargins(0, 0, 0, 0); Chris@1195: #else Chris@1195: // Need a bit of padding on the left Chris@1195: m_groupLayouts[groupName]->setContentsMargins Chris@1195: (WidgetScale::scalePixelSize(10), 0, 0, 0); Chris@1195: #endif Chris@1190: frame->setLayout(m_groupLayouts[groupName]); Chris@1190: m_layout->addWidget(frame, row, 1, 1, 2); Chris@1190: m_layout->setColumnStretch(1, 10); Chris@1190: } Chris@0: } Chris@0: Chris@1204: QGridLayout *groupLayout = m_groupLayouts[groupName]; Chris@1204: Chris@1204: #ifdef DEBUG_PROPERTY_BOX Chris@1525: SVDEBUG << "groupName becomes \"" << groupName << "\", groupLabel = \"" Chris@1204: << groupLabel << "\", groupLayout = " << groupLayout << endl; Chris@1204: #endif Chris@1204: Chris@1204: assert(groupLayout); Chris@1204: Chris@1204: QWidget *existing = m_propertyControllers[name]; Chris@1204: Chris@0: switch (type) { Chris@0: Chris@0: case PropertyContainer::ToggleProperty: Chris@0: { Chris@1204: QAbstractButton *button; Chris@0: Chris@1266: if (!(button = qobject_cast(existing))) { Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@1525: SVDEBUG << "PropertyBox: creating new checkbox" << endl; Chris@0: #endif Chris@335: if (iconName != "") { cannam@1309: #ifdef Q_OS_MAC cannam@1309: button = new NotifyingToolButton(); cannam@1309: #else Chris@335: button = new NotifyingPushButton(); cannam@1309: #endif Chris@335: button->setCheckable(true); Chris@335: QIcon icon(IconLoader().load(iconName)); Chris@335: button->setIcon(icon); Chris@335: button->setObjectName(name); Chris@1174: button->setFixedSize(WidgetScale::scaleQSize(QSize(18, 18))); Chris@335: } else { Chris@335: button = new NotifyingCheckBox(); Chris@335: button->setObjectName(name); Chris@335: } Chris@1266: connect(button, SIGNAL(toggled(bool)), Chris@1266: this, SLOT(propertyControllerChanged(bool))); Chris@335: connect(button, SIGNAL(mouseEntered()), Chris@189: this, SLOT(mouseEnteredWidget())); Chris@335: connect(button, SIGNAL(mouseLeft()), Chris@189: this, SLOT(mouseLeftWidget())); Chris@1197: button->setToolTip(propertyLabel); Chris@1204: Chris@1587: button->setContextMenuPolicy(Qt::CustomContextMenu); Chris@1587: connect(button, SIGNAL(customContextMenuRequested(const QPoint &)), Chris@1587: this, SLOT(contextMenuRequested(const QPoint &))); Chris@1587: Chris@1204: if (existing) { Chris@1204: groupLayout->replaceWidget(existing, button); Chris@1204: delete existing; Chris@1204: } else { Chris@1204: groupLayout->addWidget(button, 0, groupLayout->columnCount()); Chris@1204: } Chris@1204: Chris@1266: m_propertyControllers[name] = button; Chris@1266: } Chris@0: Chris@335: if (button->isChecked() != (value > 0)) { Chris@1266: button->blockSignals(true); Chris@1266: button->setChecked(value > 0); Chris@1266: button->blockSignals(false); Chris@1266: } Chris@1266: break; Chris@0: } Chris@0: Chris@0: case PropertyContainer::RangeProperty: Chris@0: { Chris@1266: AudioDial *dial; Chris@0: Chris@1266: if ((dial = qobject_cast(existing))) { Chris@197: if (rangeChanged) { Chris@197: dial->blockSignals(true); Chris@197: dial->setMinimum(min); Chris@197: dial->setMaximum(max); Chris@197: dial->setRangeMapper(m_container->getNewPropertyRangeMapper(name)); Chris@197: dial->blockSignals(false); Chris@197: } Chris@1204: } else { Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@1525: SVDEBUG << "PropertyBox: creating new dial" << endl; Chris@0: #endif Chris@1266: dial = new AudioDial(); Chris@1266: dial->setObjectName(name); Chris@1266: dial->setMinimum(min); Chris@1266: dial->setMaximum(max); Chris@1266: dial->setPageStep(1); Chris@1266: dial->setNotchesVisible((max - min) <= 12); Chris@1126: // important to set the range mapper before the default, Chris@1126: // because the range mapper is used to map the default Chris@1126: dial->setRangeMapper(m_container->getNewPropertyRangeMapper(name)); Chris@1266: dial->setDefaultValue(deflt); Chris@168: dial->setShowToolTip(true); Chris@1266: connect(dial, SIGNAL(valueChanged(int)), Chris@1266: this, SLOT(propertyControllerChanged(int))); Chris@189: connect(dial, SIGNAL(mouseEntered()), Chris@189: this, SLOT(mouseEnteredWidget())); Chris@189: connect(dial, SIGNAL(mouseLeft()), Chris@189: this, SLOT(mouseLeftWidget())); Chris@0: Chris@1197: dial->setFixedWidth(WidgetScale::scalePixelSize(24)); Chris@1197: dial->setFixedHeight(WidgetScale::scalePixelSize(24)); Chris@1204: Chris@1204: if (existing) { Chris@1204: groupLayout->replaceWidget(existing, dial); Chris@1204: delete existing; Chris@1204: } else { Chris@1204: groupLayout->addWidget(dial, 0, groupLayout->columnCount()); Chris@1204: } Chris@0: Chris@1266: m_propertyControllers[name] = dial; Chris@1266: } Chris@0: Chris@1266: if (dial->value() != value) { Chris@1266: dial->blockSignals(true); Chris@1266: dial->setValue(value); Chris@1266: dial->blockSignals(false); Chris@1266: } Chris@1266: break; Chris@0: } Chris@0: Chris@1196: case PropertyContainer::ColourProperty: Chris@1196: { Chris@1196: ColourComboBox *cb; Chris@1196: Chris@1266: if (!(cb = qobject_cast(existing))) { Chris@1204: Chris@1196: #ifdef DEBUG_PROPERTY_BOX Chris@1525: SVDEBUG << "PropertyBox: creating new colour combobox" << endl; Chris@1196: #endif Chris@1196: cb = new ColourComboBox(true); Chris@1196: cb->setObjectName(name); Chris@1196: Chris@1266: connect(cb, SIGNAL(colourChanged(int)), Chris@1266: this, SLOT(propertyControllerChanged(int))); Chris@1196: connect(cb, SIGNAL(mouseEntered()), Chris@1196: this, SLOT(mouseEnteredWidget())); Chris@1196: connect(cb, SIGNAL(mouseLeft()), Chris@1196: this, SLOT(mouseLeftWidget())); Chris@1196: Chris@1197: cb->setToolTip(propertyLabel); Chris@1204: Chris@1587: cb->setContextMenuPolicy(Qt::CustomContextMenu); Chris@1587: connect(cb, SIGNAL(customContextMenuRequested(const QPoint &)), Chris@1587: this, SLOT(contextMenuRequested(const QPoint &))); Chris@1587: Chris@1204: if (existing) { Chris@1204: groupLayout->replaceWidget(existing, cb); Chris@1204: delete existing; Chris@1204: } else { Chris@1204: groupLayout->addWidget(cb, 0, groupLayout->columnCount()); Chris@1204: } Chris@1204: Chris@1266: m_propertyControllers[name] = cb; Chris@1266: } Chris@1196: Chris@1196: if (cb->currentIndex() != value) { Chris@1196: cb->blockSignals(true); Chris@1196: cb->setCurrentIndex(value); Chris@1196: cb->blockSignals(false); Chris@1196: } Chris@1196: Chris@1198: break; Chris@1198: } Chris@1198: Chris@1198: case PropertyContainer::ColourMapProperty: Chris@1198: { Chris@1198: ColourMapComboBox *cb; Chris@1204: Chris@1204: if (!(cb = qobject_cast(existing))) { Chris@1198: #ifdef DEBUG_PROPERTY_BOX Chris@1525: SVDEBUG << "PropertyBox: creating new colourmap combobox" << endl; Chris@1196: #endif Chris@1199: cb = new ColourMapComboBox(false); Chris@1198: cb->setObjectName(name); Chris@1196: Chris@1266: connect(cb, SIGNAL(colourMapChanged(int)), Chris@1266: this, SLOT(propertyControllerChanged(int))); Chris@1198: connect(cb, SIGNAL(mouseEntered()), Chris@1198: this, SLOT(mouseEnteredWidget())); Chris@1198: connect(cb, SIGNAL(mouseLeft()), Chris@1198: this, SLOT(mouseLeftWidget())); Chris@1204: Chris@1204: cb->setToolTip(propertyLabel); Chris@1198: Chris@1204: if (existing) { Chris@1204: groupLayout->replaceWidget(existing, cb); Chris@1204: delete existing; Chris@1204: } else { Chris@1204: groupLayout->addWidget(cb, 0, groupLayout->columnCount()); Chris@1204: } Chris@1204: Chris@1266: m_propertyControllers[name] = cb; Chris@1266: } Chris@1198: Chris@1198: if (cb->currentIndex() != value) { Chris@1198: cb->blockSignals(true); Chris@1198: cb->setCurrentIndex(value); Chris@1198: cb->blockSignals(false); Chris@1198: } Chris@1198: Chris@1196: break; Chris@1196: } Chris@1196: Chris@0: case PropertyContainer::ValueProperty: Chris@100: case PropertyContainer::UnitsProperty: Chris@0: { Chris@1266: NotifyingComboBox *cb; Chris@0: Chris@1266: if (!(cb = qobject_cast(existing))) { Chris@0: #ifdef DEBUG_PROPERTY_BOX Chris@1525: SVDEBUG << "PropertyBox: creating new combobox" << endl; Chris@0: #endif Chris@1266: cb = new NotifyingComboBox(); Chris@1266: cb->setObjectName(name); Chris@100: cb->setDuplicatesEnabled(false); Chris@197: } Chris@100: Chris@197: if (!have || rangeChanged) { Chris@285: Chris@197: cb->blockSignals(true); Chris@197: cb->clear(); Chris@285: cb->setEditable(false); Chris@285: Chris@100: if (type == PropertyContainer::ValueProperty) { Chris@285: Chris@100: for (int i = min; i <= max; ++i) { Chris@862: Chris@862: QString label = m_container->getPropertyValueLabel(name, i); Chris@862: QString iname = m_container->getPropertyValueIconName(name, i); Chris@862: Chris@862: if (iname != "") { Chris@862: QIcon icon(IconLoader().load(iname)); Chris@862: cb->addItem(icon, label); Chris@862: } else { Chris@862: cb->addItem(label); Chris@862: } Chris@100: } Chris@285: Chris@1196: } else { // PropertyContainer::UnitsProperty Chris@285: Chris@100: QStringList units = UnitDatabase::getInstance()->getKnownUnits(); Chris@100: for (int i = 0; i < units.size(); ++i) { Chris@100: cb->addItem(units[i]); Chris@100: } Chris@285: Chris@100: cb->setEditable(true); Chris@280: } Chris@197: } Chris@100: Chris@197: if (!have) { Chris@1266: connect(cb, SIGNAL(activated(int)), Chris@1266: this, SLOT(propertyControllerChanged(int))); Chris@189: connect(cb, SIGNAL(mouseEntered()), Chris@189: this, SLOT(mouseEnteredWidget())); Chris@189: connect(cb, SIGNAL(mouseLeft()), Chris@189: this, SLOT(mouseLeftWidget())); Chris@100: Chris@1197: cb->setToolTip(propertyLabel); Chris@1587: Chris@1587: cb->setContextMenuPolicy(Qt::CustomContextMenu); Chris@1587: connect(cb, SIGNAL(customContextMenuRequested(const QPoint &)), Chris@1587: this, SLOT(contextMenuRequested(const QPoint &))); Chris@1587: Chris@1204: groupLayout->addWidget(cb, 0, groupLayout->columnCount()); Chris@1266: m_propertyControllers[name] = cb; Chris@1266: } else if (existing != cb) { Chris@1204: groupLayout->replaceWidget(existing, cb); Chris@1204: delete existing; Chris@1204: } Chris@0: Chris@100: cb->blockSignals(true); Chris@1196: if (type == PropertyContainer::ValueProperty) { Chris@100: if (cb->currentIndex() != value) { Chris@100: cb->setCurrentIndex(value); Chris@100: } Chris@100: } else { Chris@100: QString unit = UnitDatabase::getInstance()->getUnitById(value); Chris@100: if (cb->currentText() != unit) { Chris@100: for (int i = 0; i < cb->count(); ++i) { Chris@100: if (cb->itemText(i) == unit) { Chris@100: cb->setCurrentIndex(i); Chris@100: break; Chris@100: } Chris@100: } Chris@100: } Chris@100: } Chris@100: cb->blockSignals(false); Chris@0: Chris@1266: break; Chris@0: } Chris@0: Chris@807: case PropertyContainer::InvalidProperty: Chris@0: default: Chris@1266: 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@55: #ifdef DEBUG_PROPERTY_BOX Chris@587: SVDEBUG << "PropertyBox::propertyContainerPropertyChanged" << endl; Chris@55: #endif Chris@55: 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@1266: updatePropertyEditor(properties[i]); Chris@0: } Chris@0: Chris@0: blockSignals(false); Chris@0: } Chris@0: Chris@0: void Chris@249: PropertyBox::propertyContainerPropertyRangeChanged(PropertyContainer *) Chris@197: { Chris@197: blockSignals(true); Chris@197: Chris@197: PropertyContainer::PropertyList properties = m_container->getProperties(); Chris@197: for (size_t i = 0; i < properties.size(); ++i) { Chris@1266: updatePropertyEditor(properties[i], true); Chris@197: } Chris@197: Chris@197: blockSignals(false); Chris@197: } Chris@197: Chris@197: void Chris@100: PropertyBox::unitDatabaseChanged() Chris@100: { Chris@729: #ifdef DEBUG_PROPERTY_BOX Chris@1525: SVDEBUG << "PropertyBox[" << this << "]: unitDatabaseChanged" << endl; Chris@729: #endif Chris@100: blockSignals(true); Chris@100: Chris@1525: // SVDEBUG << "my container is " << m_container << endl; Chris@1525: // SVDEBUG << "my container's name is... " << endl; Chris@1525: // SVDEBUG << m_container->objectName() << endl; Chris@456: Chris@100: PropertyContainer::PropertyList properties = m_container->getProperties(); Chris@100: for (size_t i = 0; i < properties.size(); ++i) { Chris@285: if (m_container->getPropertyType(properties[i]) == Chris@285: PropertyContainer::UnitsProperty) { Chris@285: updatePropertyEditor(properties[i]); Chris@285: } Chris@285: } Chris@285: Chris@285: blockSignals(false); Chris@285: } Chris@285: Chris@285: void Chris@335: PropertyBox::propertyControllerChanged(bool on) Chris@335: { Chris@335: propertyControllerChanged(on ? 1 : 0); Chris@335: } Chris@335: Chris@335: 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@1498: SVDEBUG << "PropertyBox::propertyControllerChanged(" << name Chris@1498: << ", " << value << ")" << endl; Chris@34: #endif Chris@0: Chris@0: PropertyContainer::PropertyType type = m_container->getPropertyType(name); Chris@100: Chris@1408: Command *c = nullptr; Chris@376: Chris@100: if (type == PropertyContainer::UnitsProperty) { Chris@285: Chris@1196: NotifyingComboBox *cb = qobject_cast(obj); Chris@100: if (cb) { Chris@100: QString unit = cb->currentText(); Chris@376: c = m_container->getSetPropertyCommand Chris@100: (name, UnitDatabase::getInstance()->getUnitId(unit)); Chris@100: } Chris@285: Chris@100: } else if (type != PropertyContainer::InvalidProperty) { Chris@285: Chris@1266: c = m_container->getSetPropertyCommand(name, value); Chris@0: } Chris@376: Chris@376: if (c) CommandHistory::getInstance()->addCommand(c, true, true); Chris@218: Chris@218: updateContextHelp(obj); Chris@0: } Chris@285: Chris@285: void Chris@1587: PropertyBox::contextMenuRequested(const QPoint &pos) Chris@1587: { Chris@1587: QObject *obj = sender(); Chris@1587: QString name = obj->objectName(); Chris@1587: Chris@1587: QString label = m_container->getPropertyLabel(name); Chris@1587: int min = 0, max = 0, value = 0, deflt = 0; Chris@1587: value = m_container->getPropertyRangeAndValue(name, &min, &max, &deflt); Chris@1587: Chris@1587: delete m_lastContextMenu; Chris@1587: QMenu *m = new QMenu; Chris@1587: m_lastContextMenu = m; Chris@1587: Chris@1587: if (auto button = qobject_cast(obj)) { Chris@1587: if (value > 0) { Chris@1587: MenuTitle::addTitle(m, tr("%1: On").arg(label)); Chris@1587: } else { Chris@1587: MenuTitle::addTitle(m, tr("%1: Off").arg(label)); Chris@1587: } Chris@1587: Chris@1587: m->addAction(tr("&Reset to Default"), Chris@1587: [=]() { Chris@1587: button->setChecked(deflt > 0); Chris@1587: }); Chris@1587: Chris@1587: } else if (auto cb = qobject_cast(obj)) { Chris@1587: MenuTitle::addTitle(m, tr("%1: %2").arg(label).arg(cb->itemText(value))); Chris@1587: m->addAction(tr("&Reset to Default"), Chris@1587: [=]() { Chris@1587: cb->setCurrentIndex(deflt); Chris@1587: }); Chris@1587: } else { Chris@1587: // AudioDial has its own context menu, we don't handle it here Chris@1587: return; Chris@1587: } Chris@1587: Chris@1587: m->popup(qobject_cast(sender())->mapToGlobal(pos)); Chris@1587: } Chris@1587: Chris@1587: void Chris@377: PropertyBox::playAudibleChanged(bool audible) Chris@377: { Chris@1180: m_playButton->setChecked(audible); Chris@377: } Chris@377: Chris@377: void Chris@377: PropertyBox::playAudibleButtonChanged(bool audible) Chris@377: { Chris@1480: auto params = m_container->getPlayParameters(); Chris@377: if (!params) return; Chris@377: Chris@377: if (params->isPlayAudible() != audible) { Chris@377: PlayParameterRepository::EditCommand *command = Chris@377: new PlayParameterRepository::EditCommand(params); Chris@377: command->setPlayAudible(audible); Chris@377: CommandHistory::getInstance()->addCommand(command, true, true); Chris@377: } Chris@377: } Chris@34: Chris@34: void Chris@1178: PropertyBox::playGainControlChanged(float gain) Chris@34: { Chris@218: QObject *obj = sender(); Chris@377: Chris@1480: auto params = m_container->getPlayParameters(); Chris@377: if (!params) return; Chris@377: Chris@377: if (params->getPlayGain() != gain) { Chris@377: PlayParameterRepository::EditCommand *command = Chris@377: new PlayParameterRepository::EditCommand(params); Chris@377: command->setPlayGain(gain); Chris@377: CommandHistory::getInstance()->addCommand(command, true, true); Chris@377: } Chris@377: Chris@218: updateContextHelp(obj); Chris@34: } Chris@34: Chris@34: void Chris@1178: PropertyBox::playPanControlChanged(float pan) Chris@34: { Chris@218: QObject *obj = sender(); Chris@377: Chris@1480: auto params = m_container->getPlayParameters(); Chris@377: if (!params) return; Chris@377: Chris@377: if (params->getPlayPan() != pan) { Chris@377: PlayParameterRepository::EditCommand *command = Chris@377: new PlayParameterRepository::EditCommand(params); Chris@377: command->setPlayPan(pan); Chris@377: CommandHistory::getInstance()->addCommand(command, true, true); Chris@377: } Chris@377: Chris@218: updateContextHelp(obj); Chris@34: } Chris@769: Chris@63: void Chris@769: PropertyBox::editPlayParameters() Chris@63: { Chris@1480: auto params = m_container->getPlayParameters(); Chris@63: if (!params) return; Chris@63: Chris@769: QString clip = params->getPlayClipId(); Chris@377: Chris@377: PlayParameterRepository::EditCommand *command = Chris@377: new PlayParameterRepository::EditCommand(params); Chris@63: Chris@769: QInputDialog *dialog = new QInputDialog(this); Chris@63: Chris@769: QDir dir(":/samples"); Chris@769: QStringList clipFiles = dir.entryList(QStringList() << "*.wav", QDir::Files); Chris@63: Chris@769: QStringList clips; Chris@769: foreach (QString str, clipFiles) { Chris@769: clips.push_back(str.replace(".wav", "")); Chris@769: } Chris@769: dialog->setComboBoxItems(clips); Chris@63: Chris@769: dialog->setLabelText(tr("Set playback clip:")); Chris@769: Chris@769: QComboBox *cb = dialog->findChild(); Chris@779: if (cb) { Chris@779: for (int i = 0; i < cb->count(); ++i) { Chris@779: if (cb->itemText(i) == clip) { Chris@779: cb->setCurrentIndex(i); Chris@779: } Chris@779: } Chris@779: } Chris@769: Chris@769: connect(dialog, SIGNAL(textValueChanged(QString)), Chris@769: this, SLOT(playClipChanged(QString))); Chris@64: Chris@63: if (dialog->exec() == QDialog::Accepted) { Chris@769: QString newClip = dialog->textValue(); Chris@769: command->setPlayClipId(newClip); Chris@377: CommandHistory::getInstance()->addCommand(command, true); Chris@64: } else { Chris@377: delete command; Chris@64: // restore in case we mucked about with the configuration Chris@64: // as a consequence of signals from the dialog Chris@769: params->setPlayClipId(clip); Chris@63: } Chris@63: Chris@63: delete dialog; Chris@63: } Chris@63: Chris@64: void Chris@769: PropertyBox::playClipChanged(QString id) Chris@64: { Chris@1480: auto params = m_container->getPlayParameters(); Chris@64: if (!params) return; Chris@64: Chris@769: params->setPlayClipId(id); Chris@64: } Chris@769: Chris@185: void Chris@185: PropertyBox::layerVisibilityChanged(bool visible) Chris@185: { Chris@185: if (m_showButton) m_showButton->setState(visible); Chris@185: } Chris@189: Chris@189: void Chris@189: PropertyBox::mouseEnteredWidget() Chris@189: { Chris@218: updateContextHelp(sender()); Chris@218: } Chris@218: Chris@218: void Chris@218: PropertyBox::updateContextHelp(QObject *o) Chris@218: { Chris@1196: QWidget *w = qobject_cast(o); Chris@189: if (!w) return; Chris@218: Chris@189: if (!m_container) return; Chris@190: QString cname = m_container->getPropertyContainerName(); Chris@189: if (cname == "") return; Chris@189: Chris@1380: QString help; Chris@1380: QString mainText; Chris@1380: QString extraText; Chris@1380: QString editText; Chris@1380: Chris@1380: QString wname = w->objectName(); Chris@1380: QString propertyLabel; Chris@1380: if (wname != "") { Chris@1380: propertyLabel = m_container->getPropertyLabel(wname); Chris@1180: } Chris@1180: Chris@1380: LevelPanToolButton *lp = qobject_cast(w); Chris@1380: AudioDial *dial = qobject_cast(w); Chris@189: Chris@1380: if (lp) { Chris@1380: Chris@1380: mainText = tr("Adjust playback level and pan of %1").arg(cname); Chris@1380: editText = tr("click then drag to adjust, ctrl+click to reset"); Chris@1380: Chris@1380: } else if (wname == "playParamButton") { Chris@1380: Chris@1480: auto params = m_container->getPlayParameters(); Chris@1180: if (params) { Chris@1380: help = tr("Change sound used for playback (currently \"%1\")") Chris@1380: .arg(params->getPlayClipId()); Chris@1180: } Chris@1380: Chris@1380: } else if (dial) { Chris@1380: Chris@908: double mv = dial->mappedValue(); Chris@218: QString unit = ""; Chris@218: if (dial->rangeMapper()) unit = dial->rangeMapper()->getUnit(); Chris@218: if (unit != "") { Chris@218: extraText = tr(" (current value: %1%2)").arg(mv).arg(unit); Chris@218: } else { Chris@218: extraText = tr(" (current value: %1)").arg(mv); Chris@218: } Chris@1380: editText = tr("drag up/down to adjust, ctrl+click to reset"); Chris@1380: Chris@1380: } else if (w == m_showButton) { Chris@1380: help = tr("Toggle Visibility of %1").arg(cname); Chris@1380: Chris@1380: } else if (w == m_playButton) { Chris@1380: help = tr("Toggle Playback of %1").arg(cname); Chris@1380: Chris@218: } Chris@218: Chris@1380: if (help == "" && wname != "") { Chris@1380: Chris@1380: if (qobject_cast(w)) { Chris@1380: mainText = tr("Toggle %1 property of %2") Chris@1380: .arg(propertyLabel).arg(cname); Chris@1380: Chris@1380: } else { Chris@1380: Chris@1380: // Last param empty for historical reasons, to avoid Chris@1380: // changing tr() string Chris@1380: mainText = tr("Adjust %1 property of %2%3") Chris@1380: .arg(propertyLabel).arg(cname).arg(""); Chris@1380: } Chris@1377: } Chris@1380: Chris@1380: if (help == "") { Chris@1380: if (mainText != "") { Chris@1380: if (editText != "") { Chris@1380: help = tr("%1%2: %3") Chris@1380: .arg(mainText).arg(extraText).arg(editText); Chris@1380: } else { Chris@1380: help = tr("%1%2") Chris@1380: .arg(mainText).arg(extraText); Chris@1380: } Chris@1380: } Chris@1380: } Chris@1380: Chris@1380: if (help != "") { Chris@1380: emit contextHelpChanged(help); Chris@189: } Chris@189: } Chris@189: Chris@189: void Chris@189: PropertyBox::mouseLeftWidget() Chris@189: { Chris@218: if (!(QApplication::mouseButtons() & Qt::LeftButton)) { Chris@218: emit contextHelpChanged(""); Chris@218: } Chris@189: } Chris@189: Chris@64: