annotate widgets/PropertyBox.cpp @ 1204:d421df27e184 3.0-integration

Further PropertyBox layout overhaul: avoid crash (/ assertion failure) when property type changes from e.g. colour to colourmap, by replacing the existing widget within the layout rather than trying to repopulate it
author Chris Cannam
date Tue, 20 Dec 2016 10:49:24 +0000
parents 73d43e410a6b
children 312f99a9f2aa
rev   line source
Chris@58 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@59 4 Sonic Visualiser
Chris@59 5 An audio file viewer and annotation editor.
Chris@59 6 Centre for Digital Music, Queen Mary, University of London.
Chris@182 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@0 8
Chris@59 9 This program is free software; you can redistribute it and/or
Chris@59 10 modify it under the terms of the GNU General Public License as
Chris@59 11 published by the Free Software Foundation; either version 2 of the
Chris@59 12 License, or (at your option) any later version. See the file
Chris@59 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "PropertyBox.h"
Chris@63 17 #include "PluginParameterDialog.h"
Chris@0 18
Chris@0 19 #include "base/PropertyContainer.h"
Chris@33 20 #include "base/PlayParameters.h"
Chris@377 21 #include "base/PlayParameterRepository.h"
Chris@128 22 #include "layer/Layer.h"
Chris@100 23 #include "base/UnitDatabase.h"
Chris@167 24 #include "base/RangeMapper.h"
Chris@0 25
Chris@0 26 #include "AudioDial.h"
Chris@33 27 #include "LEDButton.h"
Chris@335 28 #include "IconLoader.h"
Chris@1178 29 #include "LevelPanWidget.h"
Chris@1179 30 #include "LevelPanToolButton.h"
Chris@1174 31 #include "WidgetScale.h"
Chris@0 32
Chris@189 33 #include "NotifyingCheckBox.h"
Chris@189 34 #include "NotifyingComboBox.h"
Chris@335 35 #include "NotifyingPushButton.h"
Chris@1189 36 #include "NotifyingToolButton.h"
Chris@1196 37 #include "ColourComboBox.h"
Chris@1198 38 #include "ColourMapComboBox.h"
Chris@189 39
Chris@0 40 #include <QGridLayout>
Chris@0 41 #include <QHBoxLayout>
Chris@33 42 #include <QVBoxLayout>
Chris@63 43 #include <QPushButton>
Chris@1189 44 #include <QToolButton>
Chris@0 45 #include <QLabel>
Chris@33 46 #include <QFrame>
Chris@218 47 #include <QApplication>
Chris@285 48 #include <QColorDialog>
Chris@285 49 #include <QInputDialog>
Chris@769 50 #include <QDir>
Chris@0 51
Chris@0 52 #include <cassert>
Chris@0 53 #include <iostream>
Martin@46 54 #include <cmath>
Chris@0 55
Chris@456 56 //#define DEBUG_PROPERTY_BOX 1
Chris@0 57
Chris@0 58 PropertyBox::PropertyBox(PropertyContainer *container) :
Chris@185 59 m_container(container),
Chris@189 60 m_showButton(0),
Chris@189 61 m_playButton(0)
Chris@0 62 {
Chris@0 63 #ifdef DEBUG_PROPERTY_BOX
Chris@682 64 cerr << "PropertyBox[" << this << "(\"" <<
Chris@682 65 container->getPropertyContainerName() << "\" at " << container << ")]::PropertyBox" << endl;
Chris@0 66 #endif
Chris@0 67
Chris@34 68 m_mainBox = new QVBoxLayout;
Chris@34 69 setLayout(m_mainBox);
Chris@33 70
Chris@980 71 #ifdef Q_OS_MAC
Chris@980 72 QMargins mm = m_mainBox->contentsMargins();
Chris@980 73 QMargins mmhalf(mm.left()/2, mm.top()/3, mm.right()/2, mm.bottom()/3);
Chris@980 74 m_mainBox->setContentsMargins(mmhalf);
Chris@980 75 #endif
Chris@980 76
Chris@107 77 // m_nameWidget = new QLabel;
Chris@107 78 // m_mainBox->addWidget(m_nameWidget);
Chris@107 79 // m_nameWidget->setText(container->objectName());
Chris@107 80
Chris@34 81 m_mainWidget = new QWidget;
Chris@34 82 m_mainBox->addWidget(m_mainWidget);
Chris@107 83 m_mainBox->insertStretch(2, 10);
Chris@33 84
Chris@34 85 m_viewPlayFrame = 0;
Chris@34 86 populateViewPlayFrame();
Chris@33 87
Chris@0 88 m_layout = new QGridLayout;
Chris@34 89 m_layout->setMargin(0);
Chris@833 90 m_layout->setHorizontalSpacing(2);
Chris@833 91 m_layout->setVerticalSpacing(1);
Chris@33 92 m_mainWidget->setLayout(m_layout);
Chris@0 93
Chris@34 94 PropertyContainer::PropertyList properties = m_container->getProperties();
Chris@0 95
Chris@0 96 blockSignals(true);
Chris@0 97
Chris@0 98 size_t i;
Chris@0 99
Chris@0 100 for (i = 0; i < properties.size(); ++i) {
Chris@0 101 updatePropertyEditor(properties[i]);
Chris@0 102 }
Chris@0 103
Chris@0 104 blockSignals(false);
Chris@0 105
Chris@0 106 m_layout->setRowStretch(m_layout->rowCount(), 10);
Chris@0 107
Chris@100 108 connect(UnitDatabase::getInstance(), SIGNAL(unitDatabaseChanged()),
Chris@100 109 this, SLOT(unitDatabaseChanged()));
Chris@100 110
Chris@0 111 #ifdef DEBUG_PROPERTY_BOX
Chris@682 112 cerr << "PropertyBox[" << this << "]::PropertyBox returning" << endl;
Chris@0 113 #endif
Chris@0 114 }
Chris@0 115
Chris@0 116 PropertyBox::~PropertyBox()
Chris@0 117 {
Chris@0 118 #ifdef DEBUG_PROPERTY_BOX
Chris@682 119 cerr << "PropertyBox[" << this << "]::~PropertyBox" << endl;
Chris@0 120 #endif
Chris@0 121 }
Chris@0 122
Chris@0 123 void
Chris@34 124 PropertyBox::populateViewPlayFrame()
Chris@33 125 {
Chris@36 126 #ifdef DEBUG_PROPERTY_BOX
Chris@729 127 cerr << "PropertyBox[" << this << ":" << m_container << "]::populateViewPlayFrame" << endl;
Chris@36 128 #endif
Chris@34 129
Chris@34 130 if (m_viewPlayFrame) {
Chris@34 131 delete m_viewPlayFrame;
Chris@34 132 m_viewPlayFrame = 0;
Chris@34 133 }
Chris@34 134
Chris@34 135 if (!m_container) return;
Chris@34 136
Chris@34 137 Layer *layer = dynamic_cast<Layer *>(m_container);
Chris@34 138 if (layer) {
Chris@193 139 disconnect(layer, SIGNAL(modelReplaced()),
Chris@193 140 this, SLOT(populateViewPlayFrame()));
Chris@34 141 connect(layer, SIGNAL(modelReplaced()),
Chris@34 142 this, SLOT(populateViewPlayFrame()));
Chris@34 143 }
Chris@34 144
Chris@34 145 PlayParameters *params = m_container->getPlayParameters();
Chris@33 146 if (!params && !layer) return;
Chris@33 147
Chris@34 148 m_viewPlayFrame = new QFrame;
Chris@34 149 m_viewPlayFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
Chris@34 150 m_mainBox->addWidget(m_viewPlayFrame);
Chris@34 151
Chris@1189 152 QGridLayout *layout = new QGridLayout;
Chris@34 153 m_viewPlayFrame->setLayout(layout);
Chris@34 154
Chris@34 155 layout->setMargin(layout->margin() / 2);
Chris@34 156
Chris@36 157 #ifdef DEBUG_PROPERTY_BOX
Chris@587 158 SVDEBUG << "PropertyBox::populateViewPlayFrame: container " << m_container << " (name " << m_container->getPropertyContainerName() << ") params " << params << endl;
Chris@36 159 #endif
Chris@1189 160
Chris@1189 161 QSize buttonSize = WidgetScale::scaleQSize(QSize(26, 26));
Chris@1189 162 int col = 0;
Chris@1189 163
Chris@33 164 if (params) {
Chris@1189 165
Chris@1189 166 m_playButton = new NotifyingToolButton;
Chris@1187 167 m_playButton->setCheckable(true);
Chris@1187 168 m_playButton->setIcon(IconLoader().load("speaker"));
Chris@1190 169 m_playButton->setToolTip(tr("Click to toggle playback"));
Chris@1187 170 m_playButton->setChecked(!params->isPlayMuted());
Chris@1189 171 m_playButton->setFixedSize(buttonSize);
Chris@1187 172 connect(m_playButton, SIGNAL(toggled(bool)),
Chris@1187 173 this, SLOT(playAudibleButtonChanged(bool)));
Chris@1187 174 connect(m_playButton, SIGNAL(mouseEntered()),
Chris@1187 175 this, SLOT(mouseEnteredWidget()));
Chris@1187 176 connect(m_playButton, SIGNAL(mouseLeft()),
Chris@1187 177 this, SLOT(mouseLeftWidget()));
Chris@1187 178 connect(params, SIGNAL(playAudibleChanged(bool)),
Chris@1187 179 this, SLOT(playAudibleChanged(bool)));
Chris@63 180
Chris@1179 181 LevelPanToolButton *levelPan = new LevelPanToolButton;
Chris@1189 182 levelPan->setFixedSize(buttonSize);
Chris@1189 183 levelPan->setImageSize((buttonSize.height() * 3) / 4);
Chris@1189 184 layout->addWidget(levelPan, 0, col++, Qt::AlignCenter);
Chris@1178 185 connect(levelPan, SIGNAL(levelChanged(float)),
Chris@1178 186 this, SLOT(playGainControlChanged(float)));
Chris@1178 187 connect(levelPan, SIGNAL(panChanged(float)),
Chris@1178 188 this, SLOT(playPanControlChanged(float)));
Chris@1178 189 connect(params, SIGNAL(playGainChanged(float)),
Chris@1178 190 levelPan, SLOT(setLevel(float)));
Chris@1178 191 connect(params, SIGNAL(playPanChanged(float)),
Chris@1178 192 levelPan, SLOT(setPan(float)));
Chris@1180 193 connect(levelPan, SIGNAL(mouseEntered()),
Chris@1180 194 this, SLOT(mouseEnteredWidget()));
Chris@1180 195 connect(levelPan, SIGNAL(mouseLeft()),
Chris@1180 196 this, SLOT(mouseLeftWidget()));
Chris@1180 197
Chris@1189 198 layout->addWidget(m_playButton, 0, col++, Qt::AlignCenter);
Chris@1189 199
Chris@1187 200 if (params->getPlayClipId() != "") {
Chris@1189 201 QToolButton *playParamButton = new QToolButton;
Chris@1187 202 playParamButton->setObjectName("playParamButton");
Chris@1187 203 playParamButton->setIcon(IconLoader().load("faders"));
Chris@1189 204 playParamButton->setFixedSize(buttonSize);
Chris@1189 205 layout->addWidget(playParamButton, 0, col++, Qt::AlignCenter);
Chris@1187 206 connect(playParamButton, SIGNAL(clicked()),
Chris@1187 207 this, SLOT(editPlayParameters()));
Chris@1187 208 connect(playParamButton, SIGNAL(mouseEntered()),
Chris@1187 209 this, SLOT(mouseEnteredWidget()));
Chris@1187 210 connect(playParamButton, SIGNAL(mouseLeft()),
Chris@1187 211 this, SLOT(mouseLeftWidget()));
Chris@1187 212 }
Chris@1187 213 }
Chris@1187 214
Chris@1189 215 layout->setColumnStretch(col++, 10);
Chris@1187 216
Chris@1187 217 if (layer) {
Chris@1187 218
Chris@1187 219 QLabel *showLabel = new QLabel(tr("Show"));
Chris@1189 220 layout->addWidget(showLabel, 0, col++, Qt::AlignVCenter | Qt::AlignRight);
Chris@1187 221
Chris@1199 222 m_showButton = new LEDButton(palette().highlight().color());
Chris@1189 223 layout->addWidget(m_showButton, 0, col++, Qt::AlignVCenter | Qt::AlignLeft);
Chris@1187 224 connect(m_showButton, SIGNAL(stateChanged(bool)),
Chris@1187 225 this, SIGNAL(showLayer(bool)));
Chris@1187 226 connect(m_showButton, SIGNAL(mouseEntered()),
Chris@1180 227 this, SLOT(mouseEnteredWidget()));
Chris@1187 228 connect(m_showButton, SIGNAL(mouseLeft()),
Chris@1180 229 this, SLOT(mouseLeftWidget()));
Chris@33 230 }
Chris@33 231 }
Chris@33 232
Chris@33 233 void
Chris@197 234 PropertyBox::updatePropertyEditor(PropertyContainer::PropertyName name,
Chris@197 235 bool rangeChanged)
Chris@0 236 {
Chris@0 237 PropertyContainer::PropertyType type = m_container->getPropertyType(name);
Chris@0 238 int row = m_layout->rowCount();
Chris@0 239
Chris@216 240 int min = 0, max = 0, value = 0, deflt = 0;
Chris@216 241 value = m_container->getPropertyRangeAndValue(name, &min, &max, &deflt);
Chris@0 242
Chris@0 243 bool have = (m_propertyControllers.find(name) !=
Chris@0 244 m_propertyControllers.end());
Chris@0 245
Chris@0 246 QString groupName = m_container->getPropertyGroupName(name);
Chris@87 247 QString propertyLabel = m_container->getPropertyLabel(name);
Chris@335 248 QString iconName = m_container->getPropertyIconName(name);
Chris@0 249
Chris@0 250 #ifdef DEBUG_PROPERTY_BOX
Chris@682 251 cerr << "PropertyBox[" << this
Chris@683 252 << "(\"" << m_container->getPropertyContainerName()
Chris@0 253 << "\")]";
Chris@682 254 cerr << "::updatePropertyEditor(\"" << name << "\"):";
Chris@682 255 cerr << " value " << value << ", have " << have << ", group \""
Chris@682 256 << groupName << "\"" << endl;
Chris@0 257 #endif
Chris@0 258
Chris@1204 259 QString groupLabel = groupName;
Chris@1204 260 if (groupName == QString()) {
Chris@1204 261 groupName = "ungrouped: " + name; // not tr(), this is internal id
Chris@1204 262 groupLabel = propertyLabel;
Chris@1204 263 }
Chris@1204 264
Chris@0 265 if (!have) {
Chris@1204 266 if (m_groupLayouts.find(groupName) == m_groupLayouts.end()) {
Chris@1204 267 QWidget *labelWidget = new QLabel(groupLabel, m_mainWidget);
Chris@1190 268 m_layout->addWidget(labelWidget, row, 0);
Chris@1190 269 QWidget *frame = new QWidget(m_mainWidget);
Chris@1190 270 frame->setMinimumSize(WidgetScale::scaleQSize(QSize(1, 24)));
Chris@1190 271 m_groupLayouts[groupName] = new QGridLayout;
Chris@1195 272 #ifdef Q_OS_MAC
Chris@1195 273 // Seems to be plenty of whitespace already
Chris@1195 274 m_groupLayouts[groupName]->setContentsMargins(0, 0, 0, 0);
Chris@1195 275 #else
Chris@1195 276 // Need a bit of padding on the left
Chris@1195 277 m_groupLayouts[groupName]->setContentsMargins
Chris@1195 278 (WidgetScale::scalePixelSize(10), 0, 0, 0);
Chris@1195 279 #endif
Chris@1190 280 frame->setLayout(m_groupLayouts[groupName]);
Chris@1190 281 m_layout->addWidget(frame, row, 1, 1, 2);
Chris@1190 282 m_layout->setColumnStretch(1, 10);
Chris@1190 283 }
Chris@0 284 }
Chris@0 285
Chris@1204 286 QGridLayout *groupLayout = m_groupLayouts[groupName];
Chris@1204 287
Chris@1204 288 #ifdef DEBUG_PROPERTY_BOX
Chris@1204 289 cerr << "groupName becomes \"" << groupName << "\", groupLabel = \""
Chris@1204 290 << groupLabel << "\", groupLayout = " << groupLayout << endl;
Chris@1204 291 #endif
Chris@1204 292
Chris@1204 293 assert(groupLayout);
Chris@1204 294
Chris@1204 295 QWidget *existing = m_propertyControllers[name];
Chris@1204 296
Chris@0 297 switch (type) {
Chris@0 298
Chris@0 299 case PropertyContainer::ToggleProperty:
Chris@0 300 {
Chris@1204 301 QAbstractButton *button;
Chris@0 302
Chris@1204 303 if (!(button = qobject_cast<QAbstractButton *>(existing))) {
Chris@0 304 #ifdef DEBUG_PROPERTY_BOX
Chris@682 305 cerr << "PropertyBox: creating new checkbox" << endl;
Chris@0 306 #endif
Chris@335 307 if (iconName != "") {
Chris@335 308 button = new NotifyingPushButton();
Chris@335 309 button->setCheckable(true);
Chris@335 310 QIcon icon(IconLoader().load(iconName));
Chris@335 311 button->setIcon(icon);
Chris@335 312 button->setObjectName(name);
Chris@1174 313 button->setFixedSize(WidgetScale::scaleQSize(QSize(18, 18)));
Chris@335 314 } else {
Chris@335 315 button = new NotifyingCheckBox();
Chris@335 316 button->setObjectName(name);
Chris@335 317 }
Chris@335 318 connect(button, SIGNAL(toggled(bool)),
Chris@335 319 this, SLOT(propertyControllerChanged(bool)));
Chris@335 320 connect(button, SIGNAL(mouseEntered()),
Chris@189 321 this, SLOT(mouseEnteredWidget()));
Chris@335 322 connect(button, SIGNAL(mouseLeft()),
Chris@189 323 this, SLOT(mouseLeftWidget()));
Chris@1197 324 button->setToolTip(propertyLabel);
Chris@1204 325
Chris@1204 326 if (existing) {
Chris@1204 327 groupLayout->replaceWidget(existing, button);
Chris@1204 328 delete existing;
Chris@1204 329 } else {
Chris@1204 330 groupLayout->addWidget(button, 0, groupLayout->columnCount());
Chris@1204 331 }
Chris@1204 332
Chris@335 333 m_propertyControllers[name] = button;
Chris@0 334 }
Chris@0 335
Chris@335 336 if (button->isChecked() != (value > 0)) {
Chris@335 337 button->blockSignals(true);
Chris@335 338 button->setChecked(value > 0);
Chris@335 339 button->blockSignals(false);
Chris@55 340 }
Chris@0 341 break;
Chris@0 342 }
Chris@0 343
Chris@0 344 case PropertyContainer::RangeProperty:
Chris@0 345 {
Chris@0 346 AudioDial *dial;
Chris@0 347
Chris@1204 348 if ((dial = qobject_cast<AudioDial *>(existing))) {
Chris@197 349 if (rangeChanged) {
Chris@197 350 dial->blockSignals(true);
Chris@197 351 dial->setMinimum(min);
Chris@197 352 dial->setMaximum(max);
Chris@197 353 dial->setRangeMapper(m_container->getNewPropertyRangeMapper(name));
Chris@197 354 dial->blockSignals(false);
Chris@197 355 }
Chris@1204 356 } else {
Chris@0 357 #ifdef DEBUG_PROPERTY_BOX
Chris@682 358 cerr << "PropertyBox: creating new dial" << endl;
Chris@0 359 #endif
Chris@0 360 dial = new AudioDial();
Chris@0 361 dial->setObjectName(name);
Chris@0 362 dial->setMinimum(min);
Chris@0 363 dial->setMaximum(max);
Chris@0 364 dial->setPageStep(1);
Chris@34 365 dial->setNotchesVisible((max - min) <= 12);
Chris@1126 366 // important to set the range mapper before the default,
Chris@1126 367 // because the range mapper is used to map the default
Chris@1126 368 dial->setRangeMapper(m_container->getNewPropertyRangeMapper(name));
Chris@216 369 dial->setDefaultValue(deflt);
Chris@168 370 dial->setShowToolTip(true);
Chris@0 371 connect(dial, SIGNAL(valueChanged(int)),
Chris@0 372 this, SLOT(propertyControllerChanged(int)));
Chris@189 373 connect(dial, SIGNAL(mouseEntered()),
Chris@189 374 this, SLOT(mouseEnteredWidget()));
Chris@189 375 connect(dial, SIGNAL(mouseLeft()),
Chris@189 376 this, SLOT(mouseLeftWidget()));
Chris@0 377
Chris@1197 378 dial->setFixedWidth(WidgetScale::scalePixelSize(24));
Chris@1197 379 dial->setFixedHeight(WidgetScale::scalePixelSize(24));
Chris@1204 380
Chris@1204 381 if (existing) {
Chris@1204 382 groupLayout->replaceWidget(existing, dial);
Chris@1204 383 delete existing;
Chris@1204 384 } else {
Chris@1204 385 groupLayout->addWidget(dial, 0, groupLayout->columnCount());
Chris@1204 386 }
Chris@0 387
Chris@0 388 m_propertyControllers[name] = dial;
Chris@0 389 }
Chris@0 390
Chris@55 391 if (dial->value() != value) {
Chris@55 392 dial->blockSignals(true);
Chris@55 393 dial->setValue(value);
Chris@55 394 dial->blockSignals(false);
Chris@55 395 }
Chris@0 396 break;
Chris@0 397 }
Chris@0 398
Chris@1196 399 case PropertyContainer::ColourProperty:
Chris@1196 400 {
Chris@1196 401 ColourComboBox *cb;
Chris@1196 402
Chris@1204 403 if (!(cb = qobject_cast<ColourComboBox *>(existing))) {
Chris@1204 404
Chris@1196 405 #ifdef DEBUG_PROPERTY_BOX
Chris@1196 406 cerr << "PropertyBox: creating new colour combobox" << endl;
Chris@1196 407 #endif
Chris@1196 408 cb = new ColourComboBox(true);
Chris@1196 409 cb->setObjectName(name);
Chris@1196 410
Chris@1196 411 connect(cb, SIGNAL(colourChanged(int)),
Chris@1196 412 this, SLOT(propertyControllerChanged(int)));
Chris@1196 413 connect(cb, SIGNAL(mouseEntered()),
Chris@1196 414 this, SLOT(mouseEnteredWidget()));
Chris@1196 415 connect(cb, SIGNAL(mouseLeft()),
Chris@1196 416 this, SLOT(mouseLeftWidget()));
Chris@1196 417
Chris@1197 418 cb->setToolTip(propertyLabel);
Chris@1204 419
Chris@1204 420 if (existing) {
Chris@1204 421 groupLayout->replaceWidget(existing, cb);
Chris@1204 422 delete existing;
Chris@1204 423 } else {
Chris@1204 424 groupLayout->addWidget(cb, 0, groupLayout->columnCount());
Chris@1204 425 }
Chris@1204 426
Chris@1196 427 m_propertyControllers[name] = cb;
Chris@1196 428 }
Chris@1196 429
Chris@1196 430 if (cb->currentIndex() != value) {
Chris@1196 431 cb->blockSignals(true);
Chris@1196 432 cb->setCurrentIndex(value);
Chris@1196 433 cb->blockSignals(false);
Chris@1196 434 }
Chris@1196 435
Chris@1198 436 break;
Chris@1198 437 }
Chris@1198 438
Chris@1198 439 case PropertyContainer::ColourMapProperty:
Chris@1198 440 {
Chris@1198 441 ColourMapComboBox *cb;
Chris@1204 442
Chris@1204 443 if (!(cb = qobject_cast<ColourMapComboBox *>(existing))) {
Chris@1198 444 #ifdef DEBUG_PROPERTY_BOX
Chris@1198 445 cerr << "PropertyBox: creating new colourmap combobox" << endl;
Chris@1196 446 #endif
Chris@1199 447 cb = new ColourMapComboBox(false);
Chris@1198 448 cb->setObjectName(name);
Chris@1196 449
Chris@1198 450 connect(cb, SIGNAL(colourMapChanged(int)),
Chris@1198 451 this, SLOT(propertyControllerChanged(int)));
Chris@1198 452 connect(cb, SIGNAL(mouseEntered()),
Chris@1198 453 this, SLOT(mouseEnteredWidget()));
Chris@1198 454 connect(cb, SIGNAL(mouseLeft()),
Chris@1198 455 this, SLOT(mouseLeftWidget()));
Chris@1204 456
Chris@1204 457 cb->setToolTip(propertyLabel);
Chris@1198 458
Chris@1204 459 if (existing) {
Chris@1204 460 groupLayout->replaceWidget(existing, cb);
Chris@1204 461 delete existing;
Chris@1204 462 } else {
Chris@1204 463 groupLayout->addWidget(cb, 0, groupLayout->columnCount());
Chris@1204 464 }
Chris@1204 465
Chris@1198 466 m_propertyControllers[name] = cb;
Chris@1198 467 }
Chris@1198 468
Chris@1198 469 if (cb->currentIndex() != value) {
Chris@1198 470 cb->blockSignals(true);
Chris@1198 471 cb->setCurrentIndex(value);
Chris@1198 472 cb->blockSignals(false);
Chris@1198 473 }
Chris@1198 474
Chris@1196 475 break;
Chris@1196 476 }
Chris@1196 477
Chris@0 478 case PropertyContainer::ValueProperty:
Chris@100 479 case PropertyContainer::UnitsProperty:
Chris@0 480 {
Chris@189 481 NotifyingComboBox *cb;
Chris@0 482
Chris@1204 483 if (!(cb = qobject_cast<NotifyingComboBox *>(existing))) {
Chris@0 484 #ifdef DEBUG_PROPERTY_BOX
Chris@682 485 cerr << "PropertyBox: creating new combobox" << endl;
Chris@0 486 #endif
Chris@189 487 cb = new NotifyingComboBox();
Chris@0 488 cb->setObjectName(name);
Chris@100 489 cb->setDuplicatesEnabled(false);
Chris@197 490 }
Chris@100 491
Chris@197 492 if (!have || rangeChanged) {
Chris@285 493
Chris@197 494 cb->blockSignals(true);
Chris@197 495 cb->clear();
Chris@285 496 cb->setEditable(false);
Chris@285 497
Chris@100 498 if (type == PropertyContainer::ValueProperty) {
Chris@285 499
Chris@100 500 for (int i = min; i <= max; ++i) {
Chris@862 501
Chris@862 502 QString label = m_container->getPropertyValueLabel(name, i);
Chris@862 503 QString iname = m_container->getPropertyValueIconName(name, i);
Chris@862 504
Chris@862 505 if (iname != "") {
Chris@862 506 QIcon icon(IconLoader().load(iname));
Chris@862 507 cb->addItem(icon, label);
Chris@862 508 } else {
Chris@862 509 cb->addItem(label);
Chris@862 510 }
Chris@100 511 }
Chris@285 512
Chris@1196 513 } else { // PropertyContainer::UnitsProperty
Chris@285 514
Chris@100 515 QStringList units = UnitDatabase::getInstance()->getKnownUnits();
Chris@100 516 for (int i = 0; i < units.size(); ++i) {
Chris@100 517 cb->addItem(units[i]);
Chris@100 518 }
Chris@285 519
Chris@100 520 cb->setEditable(true);
Chris@280 521 }
Chris@197 522 }
Chris@100 523
Chris@197 524 if (!have) {
Chris@0 525 connect(cb, SIGNAL(activated(int)),
Chris@0 526 this, SLOT(propertyControllerChanged(int)));
Chris@189 527 connect(cb, SIGNAL(mouseEntered()),
Chris@189 528 this, SLOT(mouseEnteredWidget()));
Chris@189 529 connect(cb, SIGNAL(mouseLeft()),
Chris@189 530 this, SLOT(mouseLeftWidget()));
Chris@100 531
Chris@1197 532 cb->setToolTip(propertyLabel);
Chris@1204 533 groupLayout->addWidget(cb, 0, groupLayout->columnCount());
Chris@0 534 m_propertyControllers[name] = cb;
Chris@1204 535 } else if (existing != cb) {
Chris@1204 536 groupLayout->replaceWidget(existing, cb);
Chris@1204 537 delete existing;
Chris@1204 538 }
Chris@0 539
Chris@100 540 cb->blockSignals(true);
Chris@1196 541 if (type == PropertyContainer::ValueProperty) {
Chris@100 542 if (cb->currentIndex() != value) {
Chris@100 543 cb->setCurrentIndex(value);
Chris@100 544 }
Chris@100 545 } else {
Chris@100 546 QString unit = UnitDatabase::getInstance()->getUnitById(value);
Chris@100 547 if (cb->currentText() != unit) {
Chris@100 548 for (int i = 0; i < cb->count(); ++i) {
Chris@100 549 if (cb->itemText(i) == unit) {
Chris@100 550 cb->setCurrentIndex(i);
Chris@100 551 break;
Chris@100 552 }
Chris@100 553 }
Chris@100 554 }
Chris@100 555 }
Chris@100 556 cb->blockSignals(false);
Chris@0 557
Chris@0 558 break;
Chris@0 559 }
Chris@0 560
Chris@807 561 case PropertyContainer::InvalidProperty:
Chris@0 562 default:
Chris@0 563 break;
Chris@0 564 }
Chris@0 565 }
Chris@0 566
Chris@0 567 void
Chris@0 568 PropertyBox::propertyContainerPropertyChanged(PropertyContainer *pc)
Chris@0 569 {
Chris@0 570 if (pc != m_container) return;
Chris@0 571
Chris@55 572 #ifdef DEBUG_PROPERTY_BOX
Chris@587 573 SVDEBUG << "PropertyBox::propertyContainerPropertyChanged" << endl;
Chris@55 574 #endif
Chris@55 575
Chris@0 576 PropertyContainer::PropertyList properties = m_container->getProperties();
Chris@0 577 size_t i;
Chris@0 578
Chris@0 579 blockSignals(true);
Chris@0 580
Chris@0 581 for (i = 0; i < properties.size(); ++i) {
Chris@0 582 updatePropertyEditor(properties[i]);
Chris@0 583 }
Chris@0 584
Chris@0 585 blockSignals(false);
Chris@0 586 }
Chris@0 587
Chris@0 588 void
Chris@249 589 PropertyBox::propertyContainerPropertyRangeChanged(PropertyContainer *)
Chris@197 590 {
Chris@197 591 blockSignals(true);
Chris@197 592
Chris@197 593 PropertyContainer::PropertyList properties = m_container->getProperties();
Chris@197 594 for (size_t i = 0; i < properties.size(); ++i) {
Chris@197 595 updatePropertyEditor(properties[i], true);
Chris@197 596 }
Chris@197 597
Chris@197 598 blockSignals(false);
Chris@197 599 }
Chris@197 600
Chris@197 601 void
Chris@100 602 PropertyBox::unitDatabaseChanged()
Chris@100 603 {
Chris@729 604 #ifdef DEBUG_PROPERTY_BOX
Chris@682 605 cerr << "PropertyBox[" << this << "]: unitDatabaseChanged" << endl;
Chris@729 606 #endif
Chris@100 607 blockSignals(true);
Chris@100 608
Chris@682 609 // cerr << "my container is " << m_container << endl;
Chris@682 610 // cerr << "my container's name is... " << endl;
Chris@682 611 // cerr << m_container->objectName() << endl;
Chris@456 612
Chris@100 613 PropertyContainer::PropertyList properties = m_container->getProperties();
Chris@100 614 for (size_t i = 0; i < properties.size(); ++i) {
Chris@285 615 if (m_container->getPropertyType(properties[i]) ==
Chris@285 616 PropertyContainer::UnitsProperty) {
Chris@285 617 updatePropertyEditor(properties[i]);
Chris@285 618 }
Chris@285 619 }
Chris@285 620
Chris@285 621 blockSignals(false);
Chris@285 622 }
Chris@285 623
Chris@285 624 void
Chris@335 625 PropertyBox::propertyControllerChanged(bool on)
Chris@335 626 {
Chris@335 627 propertyControllerChanged(on ? 1 : 0);
Chris@335 628 }
Chris@335 629
Chris@335 630 void
Chris@0 631 PropertyBox::propertyControllerChanged(int value)
Chris@0 632 {
Chris@0 633 QObject *obj = sender();
Chris@0 634 QString name = obj->objectName();
Chris@0 635
Chris@34 636 #ifdef DEBUG_PROPERTY_BOX
Chris@587 637 SVDEBUG << "PropertyBox::propertyControllerChanged(" << name << ", " << value << ")" << endl;
Chris@34 638 #endif
Chris@0 639
Chris@0 640 PropertyContainer::PropertyType type = m_container->getPropertyType(name);
Chris@100 641
Chris@376 642 Command *c = 0;
Chris@376 643
Chris@100 644 if (type == PropertyContainer::UnitsProperty) {
Chris@285 645
Chris@1196 646 NotifyingComboBox *cb = qobject_cast<NotifyingComboBox *>(obj);
Chris@100 647 if (cb) {
Chris@100 648 QString unit = cb->currentText();
Chris@376 649 c = m_container->getSetPropertyCommand
Chris@100 650 (name, UnitDatabase::getInstance()->getUnitId(unit));
Chris@100 651 }
Chris@285 652
Chris@100 653 } else if (type != PropertyContainer::InvalidProperty) {
Chris@285 654
Chris@376 655 c = m_container->getSetPropertyCommand(name, value);
Chris@0 656 }
Chris@376 657
Chris@376 658 if (c) CommandHistory::getInstance()->addCommand(c, true, true);
Chris@218 659
Chris@218 660 updateContextHelp(obj);
Chris@0 661 }
Chris@285 662
Chris@285 663 void
Chris@377 664 PropertyBox::playAudibleChanged(bool audible)
Chris@377 665 {
Chris@1180 666 m_playButton->setChecked(audible);
Chris@377 667 }
Chris@377 668
Chris@377 669 void
Chris@377 670 PropertyBox::playAudibleButtonChanged(bool audible)
Chris@377 671 {
Chris@377 672 PlayParameters *params = m_container->getPlayParameters();
Chris@377 673 if (!params) return;
Chris@377 674
Chris@377 675 if (params->isPlayAudible() != audible) {
Chris@377 676 PlayParameterRepository::EditCommand *command =
Chris@377 677 new PlayParameterRepository::EditCommand(params);
Chris@377 678 command->setPlayAudible(audible);
Chris@377 679 CommandHistory::getInstance()->addCommand(command, true, true);
Chris@377 680 }
Chris@377 681 }
Chris@34 682
Chris@34 683 void
Chris@1178 684 PropertyBox::playGainControlChanged(float gain)
Chris@34 685 {
Chris@218 686 QObject *obj = sender();
Chris@377 687
Chris@377 688 PlayParameters *params = m_container->getPlayParameters();
Chris@377 689 if (!params) return;
Chris@377 690
Chris@377 691 if (params->getPlayGain() != gain) {
Chris@377 692 PlayParameterRepository::EditCommand *command =
Chris@377 693 new PlayParameterRepository::EditCommand(params);
Chris@377 694 command->setPlayGain(gain);
Chris@377 695 CommandHistory::getInstance()->addCommand(command, true, true);
Chris@377 696 }
Chris@377 697
Chris@218 698 updateContextHelp(obj);
Chris@34 699 }
Chris@34 700
Chris@34 701 void
Chris@1178 702 PropertyBox::playPanControlChanged(float pan)
Chris@34 703 {
Chris@218 704 QObject *obj = sender();
Chris@377 705
Chris@377 706 PlayParameters *params = m_container->getPlayParameters();
Chris@377 707 if (!params) return;
Chris@377 708
Chris@377 709 if (params->getPlayPan() != pan) {
Chris@377 710 PlayParameterRepository::EditCommand *command =
Chris@377 711 new PlayParameterRepository::EditCommand(params);
Chris@377 712 command->setPlayPan(pan);
Chris@377 713 CommandHistory::getInstance()->addCommand(command, true, true);
Chris@377 714 }
Chris@377 715
Chris@218 716 updateContextHelp(obj);
Chris@34 717 }
Chris@769 718
Chris@63 719 void
Chris@769 720 PropertyBox::editPlayParameters()
Chris@63 721 {
Chris@63 722 PlayParameters *params = m_container->getPlayParameters();
Chris@63 723 if (!params) return;
Chris@63 724
Chris@769 725 QString clip = params->getPlayClipId();
Chris@377 726
Chris@377 727 PlayParameterRepository::EditCommand *command =
Chris@377 728 new PlayParameterRepository::EditCommand(params);
Chris@63 729
Chris@769 730 QInputDialog *dialog = new QInputDialog(this);
Chris@63 731
Chris@769 732 QDir dir(":/samples");
Chris@769 733 QStringList clipFiles = dir.entryList(QStringList() << "*.wav", QDir::Files);
Chris@63 734
Chris@769 735 QStringList clips;
Chris@769 736 foreach (QString str, clipFiles) {
Chris@769 737 clips.push_back(str.replace(".wav", ""));
Chris@769 738 }
Chris@769 739 dialog->setComboBoxItems(clips);
Chris@63 740
Chris@769 741 dialog->setLabelText(tr("Set playback clip:"));
Chris@769 742
Chris@769 743 QComboBox *cb = dialog->findChild<QComboBox *>();
Chris@779 744 if (cb) {
Chris@779 745 for (int i = 0; i < cb->count(); ++i) {
Chris@779 746 if (cb->itemText(i) == clip) {
Chris@779 747 cb->setCurrentIndex(i);
Chris@779 748 }
Chris@779 749 }
Chris@779 750 }
Chris@769 751
Chris@769 752 connect(dialog, SIGNAL(textValueChanged(QString)),
Chris@769 753 this, SLOT(playClipChanged(QString)));
Chris@64 754
Chris@63 755 if (dialog->exec() == QDialog::Accepted) {
Chris@769 756 QString newClip = dialog->textValue();
Chris@769 757 command->setPlayClipId(newClip);
Chris@377 758 CommandHistory::getInstance()->addCommand(command, true);
Chris@64 759 } else {
Chris@377 760 delete command;
Chris@64 761 // restore in case we mucked about with the configuration
Chris@64 762 // as a consequence of signals from the dialog
Chris@769 763 params->setPlayClipId(clip);
Chris@63 764 }
Chris@63 765
Chris@63 766 delete dialog;
Chris@63 767 }
Chris@63 768
Chris@64 769 void
Chris@769 770 PropertyBox::playClipChanged(QString id)
Chris@64 771 {
Chris@64 772 PlayParameters *params = m_container->getPlayParameters();
Chris@64 773 if (!params) return;
Chris@64 774
Chris@769 775 params->setPlayClipId(id);
Chris@64 776 }
Chris@769 777
Chris@185 778 void
Chris@185 779 PropertyBox::layerVisibilityChanged(bool visible)
Chris@185 780 {
Chris@185 781 if (m_showButton) m_showButton->setState(visible);
Chris@185 782 }
Chris@189 783
Chris@189 784 void
Chris@189 785 PropertyBox::mouseEnteredWidget()
Chris@189 786 {
Chris@218 787 updateContextHelp(sender());
Chris@218 788 }
Chris@218 789
Chris@218 790 void
Chris@218 791 PropertyBox::updateContextHelp(QObject *o)
Chris@218 792 {
Chris@1196 793 QWidget *w = qobject_cast<QWidget *>(o);
Chris@189 794 if (!w) return;
Chris@218 795
Chris@189 796 if (!m_container) return;
Chris@190 797 QString cname = m_container->getPropertyContainerName();
Chris@189 798 if (cname == "") return;
Chris@189 799
Chris@1180 800 LevelPanToolButton *lp = qobject_cast<LevelPanToolButton *>(w);
Chris@1180 801 if (lp) {
Chris@1180 802 emit contextHelpChanged(tr("Adjust playback level and pan of %1").arg(cname));
Chris@1180 803 return;
Chris@1180 804 }
Chris@1180 805
Chris@189 806 QString wname = w->objectName();
Chris@189 807
Chris@1180 808 if (wname == "playParamButton") {
Chris@1180 809 PlayParameters *params = m_container->getPlayParameters();
Chris@1180 810 if (params) {
Chris@1180 811 emit contextHelpChanged
Chris@1180 812 (tr("Change sound used for playback (currently \"%1\")")
Chris@1180 813 .arg(params->getPlayClipId()));
Chris@1180 814 return;
Chris@1180 815 }
Chris@1180 816 }
Chris@1180 817
Chris@218 818 QString extraText;
Chris@1180 819
Chris@1180 820 AudioDial *dial = qobject_cast<AudioDial *>(w);
Chris@218 821 if (dial) {
Chris@908 822 double mv = dial->mappedValue();
Chris@218 823 QString unit = "";
Chris@218 824 if (dial->rangeMapper()) unit = dial->rangeMapper()->getUnit();
Chris@218 825 if (unit != "") {
Chris@218 826 extraText = tr(" (current value: %1%2)").arg(mv).arg(unit);
Chris@218 827 } else {
Chris@218 828 extraText = tr(" (current value: %1)").arg(mv);
Chris@218 829 }
Chris@218 830 }
Chris@218 831
Chris@189 832 if (w == m_showButton) {
Chris@190 833 emit contextHelpChanged(tr("Toggle Visibility of %1").arg(cname));
Chris@189 834 } else if (w == m_playButton) {
Chris@190 835 emit contextHelpChanged(tr("Toggle Playback of %1").arg(cname));
Chris@189 836 } else if (wname == "") {
Chris@189 837 return;
Chris@1196 838 } else if (qobject_cast<QAbstractButton *>(w)) {
Chris@190 839 emit contextHelpChanged(tr("Toggle %1 property of %2")
Chris@189 840 .arg(wname).arg(cname));
Chris@189 841 } else {
Chris@218 842 emit contextHelpChanged(tr("Adjust %1 property of %2%3")
Chris@218 843 .arg(wname).arg(cname).arg(extraText));
Chris@189 844 }
Chris@189 845 }
Chris@189 846
Chris@189 847 void
Chris@189 848 PropertyBox::mouseLeftWidget()
Chris@189 849 {
Chris@218 850 if (!(QApplication::mouseButtons() & Qt::LeftButton)) {
Chris@218 851 emit contextHelpChanged("");
Chris@218 852 }
Chris@189 853 }
Chris@189 854
Chris@64 855