annotate widgets/PropertyBox.cpp @ 473:4f4f943bfdfc

* Merge from one-fftdataserver-per-fftmodel branch. This bit of reworking (which is not described very accurately by the title of the branch) turns the MatrixFile object into something that either reads or writes, but not both, and separates the FFT file cache reader and writer implementations separately. This allows the FFT data server to have a single thread owning writers and one reader per "customer" thread, and for all locking to be vastly simplified and concentrated in the data server alone (because none of the classes it makes use of is used in more than one thread at a time). The result is faster and more trustworthy code.
author Chris Cannam
date Tue, 27 Jan 2009 13:25:10 +0000
parents 035d62c4cddf
children 4afdcecbd62e
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@376 23 #include "layer/ColourDatabase.h"
Chris@100 24 #include "base/UnitDatabase.h"
Chris@167 25 #include "base/RangeMapper.h"
Chris@0 26
Chris@63 27 #include "plugin/RealTimePluginFactory.h"
Chris@63 28 #include "plugin/RealTimePluginInstance.h"
Chris@71 29 #include "plugin/PluginXml.h"
Chris@63 30
Chris@0 31 #include "AudioDial.h"
Chris@33 32 #include "LEDButton.h"
Chris@335 33 #include "IconLoader.h"
Chris@0 34
Chris@189 35 #include "NotifyingCheckBox.h"
Chris@189 36 #include "NotifyingComboBox.h"
Chris@335 37 #include "NotifyingPushButton.h"
Chris@285 38 #include "ColourNameDialog.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@0 44 #include <QLabel>
Chris@33 45 #include <QFrame>
Chris@218 46 #include <QApplication>
Chris@285 47 #include <QColorDialog>
Chris@285 48 #include <QInputDialog>
Chris@0 49
Chris@0 50 #include <cassert>
Chris@0 51 #include <iostream>
Martin@46 52 #include <cmath>
Chris@0 53
Chris@456 54 //#define DEBUG_PROPERTY_BOX 1
Chris@0 55
Chris@0 56 PropertyBox::PropertyBox(PropertyContainer *container) :
Chris@185 57 m_container(container),
Chris@189 58 m_showButton(0),
Chris@189 59 m_playButton(0)
Chris@0 60 {
Chris@0 61 #ifdef DEBUG_PROPERTY_BOX
Chris@0 62 std::cerr << "PropertyBox[" << this << "(\"" <<
Chris@456 63 container->getPropertyContainerName().toStdString() << "\" at " << container << ")]::PropertyBox" << std::endl;
Chris@0 64 #endif
Chris@0 65
Chris@34 66 m_mainBox = new QVBoxLayout;
Chris@34 67 setLayout(m_mainBox);
Chris@33 68
Chris@107 69 // m_nameWidget = new QLabel;
Chris@107 70 // m_mainBox->addWidget(m_nameWidget);
Chris@107 71 // m_nameWidget->setText(container->objectName());
Chris@107 72
Chris@34 73 m_mainWidget = new QWidget;
Chris@34 74 m_mainBox->addWidget(m_mainWidget);
Chris@107 75 m_mainBox->insertStretch(2, 10);
Chris@33 76
Chris@34 77 m_viewPlayFrame = 0;
Chris@34 78 populateViewPlayFrame();
Chris@33 79
Chris@0 80 m_layout = new QGridLayout;
Chris@34 81 m_layout->setMargin(0);
Chris@33 82 m_mainWidget->setLayout(m_layout);
Chris@0 83
Chris@34 84 PropertyContainer::PropertyList properties = m_container->getProperties();
Chris@0 85
Chris@0 86 blockSignals(true);
Chris@0 87
Chris@0 88 size_t i;
Chris@0 89
Chris@0 90 for (i = 0; i < properties.size(); ++i) {
Chris@0 91 updatePropertyEditor(properties[i]);
Chris@0 92 }
Chris@0 93
Chris@0 94 blockSignals(false);
Chris@0 95
Chris@0 96 m_layout->setRowStretch(m_layout->rowCount(), 10);
Chris@0 97
Chris@100 98 connect(UnitDatabase::getInstance(), SIGNAL(unitDatabaseChanged()),
Chris@100 99 this, SLOT(unitDatabaseChanged()));
Chris@100 100
Chris@285 101 connect(ColourDatabase::getInstance(), SIGNAL(colourDatabaseChanged()),
Chris@285 102 this, SLOT(colourDatabaseChanged()));
Chris@285 103
Chris@0 104 #ifdef DEBUG_PROPERTY_BOX
Chris@0 105 std::cerr << "PropertyBox[" << this << "]::PropertyBox returning" << std::endl;
Chris@0 106 #endif
Chris@0 107 }
Chris@0 108
Chris@0 109 PropertyBox::~PropertyBox()
Chris@0 110 {
Chris@0 111 #ifdef DEBUG_PROPERTY_BOX
Chris@33 112 std::cerr << "PropertyBox[" << this << "]::~PropertyBox" << std::endl;
Chris@0 113 #endif
Chris@0 114 }
Chris@0 115
Chris@0 116 void
Chris@34 117 PropertyBox::populateViewPlayFrame()
Chris@33 118 {
Chris@36 119 #ifdef DEBUG_PROPERTY_BOX
Chris@34 120 std::cerr << "PropertyBox(" << m_container << ")::populateViewPlayFrame" << std::endl;
Chris@36 121 #endif
Chris@34 122
Chris@34 123 if (m_viewPlayFrame) {
Chris@34 124 delete m_viewPlayFrame;
Chris@34 125 m_viewPlayFrame = 0;
Chris@34 126 }
Chris@34 127
Chris@34 128 if (!m_container) return;
Chris@34 129
Chris@34 130 Layer *layer = dynamic_cast<Layer *>(m_container);
Chris@34 131 if (layer) {
Chris@193 132 disconnect(layer, SIGNAL(modelReplaced()),
Chris@193 133 this, SLOT(populateViewPlayFrame()));
Chris@34 134 connect(layer, SIGNAL(modelReplaced()),
Chris@34 135 this, SLOT(populateViewPlayFrame()));
Chris@34 136 }
Chris@34 137
Chris@34 138 PlayParameters *params = m_container->getPlayParameters();
Chris@33 139 if (!params && !layer) return;
Chris@33 140
Chris@34 141 m_viewPlayFrame = new QFrame;
Chris@34 142 m_viewPlayFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
Chris@34 143 m_mainBox->addWidget(m_viewPlayFrame);
Chris@34 144
Chris@34 145 QHBoxLayout *layout = new QHBoxLayout;
Chris@34 146 m_viewPlayFrame->setLayout(layout);
Chris@34 147
Chris@34 148 layout->setMargin(layout->margin() / 2);
Chris@34 149
Chris@36 150 #ifdef DEBUG_PROPERTY_BOX
Chris@34 151 std::cerr << "PropertyBox::populateViewPlayFrame: container " << m_container << " (name " << m_container->getPropertyContainerName().toStdString() << ") params " << params << std::endl;
Chris@36 152 #endif
Chris@36 153
Chris@33 154 if (layer) {
Chris@34 155 QLabel *showLabel = new QLabel(tr("Show"));
Chris@34 156 layout->addWidget(showLabel);
Chris@34 157 layout->setAlignment(showLabel, Qt::AlignVCenter);
Chris@34 158
Chris@185 159 m_showButton = new LEDButton(Qt::blue);
Chris@185 160 layout->addWidget(m_showButton);
Chris@185 161 connect(m_showButton, SIGNAL(stateChanged(bool)),
Chris@47 162 this, SIGNAL(showLayer(bool)));
Chris@189 163 connect(m_showButton, SIGNAL(mouseEntered()),
Chris@189 164 this, SLOT(mouseEnteredWidget()));
Chris@189 165 connect(m_showButton, SIGNAL(mouseLeft()),
Chris@189 166 this, SLOT(mouseLeftWidget()));
Chris@185 167 layout->setAlignment(m_showButton, Qt::AlignVCenter);
Chris@33 168 }
Chris@33 169
Chris@33 170 if (params) {
Chris@34 171
Chris@34 172 QLabel *playLabel = new QLabel(tr("Play"));
Chris@34 173 layout->addWidget(playLabel);
Chris@34 174 layout->setAlignment(playLabel, Qt::AlignVCenter);
Chris@34 175
Chris@189 176 m_playButton = new LEDButton(Qt::darkGreen);
Chris@189 177 m_playButton->setState(!params->isPlayMuted());
Chris@189 178 layout->addWidget(m_playButton);
Chris@189 179 connect(m_playButton, SIGNAL(stateChanged(bool)),
Chris@377 180 this, SLOT(playAudibleButtonChanged(bool)));
Chris@189 181 connect(m_playButton, SIGNAL(mouseEntered()),
Chris@189 182 this, SLOT(mouseEnteredWidget()));
Chris@189 183 connect(m_playButton, SIGNAL(mouseLeft()),
Chris@189 184 this, SLOT(mouseLeftWidget()));
Chris@34 185 connect(params, SIGNAL(playAudibleChanged(bool)),
Chris@377 186 this, SLOT(playAudibleChanged(bool)));
Chris@189 187 layout->setAlignment(m_playButton, Qt::AlignVCenter);
Chris@34 188
Chris@34 189 layout->insertStretch(-1, 10);
Chris@34 190
Chris@63 191 if (params->getPlayPluginId() != "") {
Chris@64 192 QPushButton *pluginButton = new QPushButton(QIcon(":icons/faders.png"), "");
Chris@64 193 pluginButton->setFixedWidth(24);
Chris@64 194 pluginButton->setFixedHeight(24);
Chris@63 195 layout->addWidget(pluginButton);
Chris@63 196 connect(pluginButton, SIGNAL(clicked()),
Chris@63 197 this, SLOT(editPlugin()));
Chris@63 198 }
Chris@63 199
Chris@34 200 AudioDial *gainDial = new AudioDial;
Chris@34 201 layout->addWidget(gainDial);
Chris@34 202 gainDial->setMeterColor(Qt::darkRed);
Chris@34 203 gainDial->setMinimum(-50);
Chris@34 204 gainDial->setMaximum(50);
Chris@34 205 gainDial->setPageStep(1);
Chris@34 206 gainDial->setFixedWidth(24);
Chris@34 207 gainDial->setFixedHeight(24);
Chris@34 208 gainDial->setNotchesVisible(false);
Chris@34 209 gainDial->setDefaultValue(0);
Chris@168 210 gainDial->setObjectName(tr("Playback Gain"));
Chris@167 211 gainDial->setRangeMapper(new LinearRangeMapper
Chris@167 212 (-50, 50, -25, 25, tr("dB")));
Chris@168 213 gainDial->setShowToolTip(true);
Chris@34 214 connect(gainDial, SIGNAL(valueChanged(int)),
Chris@34 215 this, SLOT(playGainDialChanged(int)));
Chris@34 216 connect(params, SIGNAL(playGainChanged(float)),
Chris@34 217 this, SLOT(playGainChanged(float)));
Chris@34 218 connect(this, SIGNAL(changePlayGainDial(int)),
Chris@34 219 gainDial, SLOT(setValue(int)));
Chris@189 220 connect(gainDial, SIGNAL(mouseEntered()),
Chris@189 221 this, SLOT(mouseEnteredWidget()));
Chris@189 222 connect(gainDial, SIGNAL(mouseLeft()),
Chris@189 223 this, SLOT(mouseLeftWidget()));
Chris@377 224 playGainChanged(params->getPlayGain());
Chris@34 225 layout->setAlignment(gainDial, Qt::AlignVCenter);
Chris@34 226
Chris@34 227 AudioDial *panDial = new AudioDial;
Chris@34 228 layout->addWidget(panDial);
Chris@34 229 panDial->setMeterColor(Qt::darkGreen);
Chris@34 230 panDial->setMinimum(-50);
Chris@34 231 panDial->setMaximum(50);
Chris@34 232 panDial->setPageStep(1);
Chris@34 233 panDial->setFixedWidth(24);
Chris@34 234 panDial->setFixedHeight(24);
Chris@34 235 panDial->setNotchesVisible(false);
Chris@57 236 panDial->setToolTip(tr("Playback Pan / Balance"));
Chris@34 237 panDial->setDefaultValue(0);
Chris@168 238 panDial->setObjectName(tr("Playback Pan / Balance"));
Chris@168 239 panDial->setShowToolTip(true);
Chris@34 240 connect(panDial, SIGNAL(valueChanged(int)),
Chris@34 241 this, SLOT(playPanDialChanged(int)));
Chris@34 242 connect(params, SIGNAL(playPanChanged(float)),
Chris@34 243 this, SLOT(playPanChanged(float)));
Chris@34 244 connect(this, SIGNAL(changePlayPanDial(int)),
Chris@34 245 panDial, SLOT(setValue(int)));
Chris@189 246 connect(panDial, SIGNAL(mouseEntered()),
Chris@189 247 this, SLOT(mouseEnteredWidget()));
Chris@189 248 connect(panDial, SIGNAL(mouseLeft()),
Chris@189 249 this, SLOT(mouseLeftWidget()));
Chris@377 250 playPanChanged(params->getPlayPan());
Chris@34 251 layout->setAlignment(panDial, Qt::AlignVCenter);
Chris@34 252
Chris@34 253 } else {
Chris@34 254
Chris@34 255 layout->insertStretch(-1, 10);
Chris@33 256 }
Chris@33 257 }
Chris@33 258
Chris@33 259 void
Chris@197 260 PropertyBox::updatePropertyEditor(PropertyContainer::PropertyName name,
Chris@197 261 bool rangeChanged)
Chris@0 262 {
Chris@0 263 PropertyContainer::PropertyType type = m_container->getPropertyType(name);
Chris@0 264 int row = m_layout->rowCount();
Chris@0 265
Chris@216 266 int min = 0, max = 0, value = 0, deflt = 0;
Chris@216 267 value = m_container->getPropertyRangeAndValue(name, &min, &max, &deflt);
Chris@0 268
Chris@0 269 bool have = (m_propertyControllers.find(name) !=
Chris@0 270 m_propertyControllers.end());
Chris@0 271
Chris@0 272 QString groupName = m_container->getPropertyGroupName(name);
Chris@87 273 QString propertyLabel = m_container->getPropertyLabel(name);
Chris@335 274 QString iconName = m_container->getPropertyIconName(name);
Chris@0 275
Chris@0 276 #ifdef DEBUG_PROPERTY_BOX
Chris@0 277 std::cerr << "PropertyBox[" << this
Chris@0 278 << "(\"" << m_container->getPropertyContainerName().toStdString()
Chris@0 279 << "\")]";
Chris@0 280 std::cerr << "::updatePropertyEditor(\"" << name.toStdString() << "\"):";
Chris@0 281 std::cerr << " value " << value << ", have " << have << ", group \""
Chris@0 282 << groupName.toStdString() << "\"" << std::endl;
Chris@0 283 #endif
Chris@0 284
Chris@0 285 bool inGroup = (groupName != QString());
Chris@0 286
Chris@0 287 if (!have) {
Chris@0 288 if (inGroup) {
Chris@0 289 if (m_groupLayouts.find(groupName) == m_groupLayouts.end()) {
Chris@0 290 #ifdef DEBUG_PROPERTY_BOX
Chris@0 291 std::cerr << "PropertyBox: adding label \"" << groupName.toStdString() << "\" and frame for group for \"" << name.toStdString() << "\"" << std::endl;
Chris@0 292 #endif
Chris@33 293 m_layout->addWidget(new QLabel(groupName, m_mainWidget), row, 0);
Chris@33 294 QFrame *frame = new QFrame(m_mainWidget);
Chris@0 295 m_layout->addWidget(frame, row, 1, 1, 2);
Chris@0 296 m_groupLayouts[groupName] = new QHBoxLayout;
Chris@0 297 m_groupLayouts[groupName]->setMargin(0);
Chris@0 298 frame->setLayout(m_groupLayouts[groupName]);
Chris@0 299 }
Chris@0 300 } else {
Chris@0 301 #ifdef DEBUG_PROPERTY_BOX
Chris@87 302 std::cerr << "PropertyBox: adding label \"" << propertyLabel.toStdString() << "\"" << std::endl;
Chris@0 303 #endif
Chris@87 304 m_layout->addWidget(new QLabel(propertyLabel, m_mainWidget), row, 0);
Chris@0 305 }
Chris@0 306 }
Chris@0 307
Chris@0 308 switch (type) {
Chris@0 309
Chris@0 310 case PropertyContainer::ToggleProperty:
Chris@0 311 {
Chris@335 312 QAbstractButton *button = 0;
Chris@0 313
Chris@0 314 if (have) {
Chris@335 315 button = dynamic_cast<QAbstractButton *>(m_propertyControllers[name]);
Chris@335 316 assert(button);
Chris@0 317 } else {
Chris@0 318 #ifdef DEBUG_PROPERTY_BOX
Chris@0 319 std::cerr << "PropertyBox: creating new checkbox" << std::endl;
Chris@0 320 #endif
Chris@335 321 if (iconName != "") {
Chris@335 322 button = new NotifyingPushButton();
Chris@335 323 button->setCheckable(true);
Chris@335 324 QIcon icon(IconLoader().load(iconName));
Chris@335 325 button->setIcon(icon);
Chris@335 326 button->setObjectName(name);
Chris@335 327 button->setFixedSize(QSize(18, 18));
Chris@335 328 } else {
Chris@335 329 button = new NotifyingCheckBox();
Chris@335 330 button->setObjectName(name);
Chris@335 331 }
Chris@335 332 connect(button, SIGNAL(toggled(bool)),
Chris@335 333 this, SLOT(propertyControllerChanged(bool)));
Chris@335 334 connect(button, SIGNAL(mouseEntered()),
Chris@189 335 this, SLOT(mouseEnteredWidget()));
Chris@335 336 connect(button, SIGNAL(mouseLeft()),
Chris@189 337 this, SLOT(mouseLeftWidget()));
Chris@0 338 if (inGroup) {
Chris@335 339 button->setToolTip(propertyLabel);
Chris@335 340 m_groupLayouts[groupName]->addWidget(button);
Chris@0 341 } else {
Chris@335 342 m_layout->addWidget(button, row, 1, 1, 2);
Chris@0 343 }
Chris@335 344 m_propertyControllers[name] = button;
Chris@0 345 }
Chris@0 346
Chris@335 347 if (button->isChecked() != (value > 0)) {
Chris@335 348 button->blockSignals(true);
Chris@335 349 button->setChecked(value > 0);
Chris@335 350 button->blockSignals(false);
Chris@55 351 }
Chris@0 352 break;
Chris@0 353 }
Chris@0 354
Chris@0 355 case PropertyContainer::RangeProperty:
Chris@0 356 {
Chris@0 357 AudioDial *dial;
Chris@0 358
Chris@0 359 if (have) {
Chris@0 360 dial = dynamic_cast<AudioDial *>(m_propertyControllers[name]);
Chris@0 361 assert(dial);
Chris@197 362 if (rangeChanged) {
Chris@197 363 dial->blockSignals(true);
Chris@197 364 dial->setMinimum(min);
Chris@197 365 dial->setMaximum(max);
Chris@197 366 dial->setRangeMapper(m_container->getNewPropertyRangeMapper(name));
Chris@197 367 dial->blockSignals(false);
Chris@197 368 }
Chris@197 369
Chris@0 370 } else {
Chris@0 371 #ifdef DEBUG_PROPERTY_BOX
Chris@0 372 std::cerr << "PropertyBox: creating new dial" << std::endl;
Chris@0 373 #endif
Chris@0 374 dial = new AudioDial();
Chris@0 375 dial->setObjectName(name);
Chris@0 376 dial->setMinimum(min);
Chris@0 377 dial->setMaximum(max);
Chris@0 378 dial->setPageStep(1);
Chris@34 379 dial->setNotchesVisible((max - min) <= 12);
Chris@216 380 dial->setDefaultValue(deflt);
Chris@167 381 dial->setRangeMapper(m_container->getNewPropertyRangeMapper(name));
Chris@168 382 dial->setShowToolTip(true);
Chris@0 383 connect(dial, SIGNAL(valueChanged(int)),
Chris@0 384 this, SLOT(propertyControllerChanged(int)));
Chris@189 385 connect(dial, SIGNAL(mouseEntered()),
Chris@189 386 this, SLOT(mouseEnteredWidget()));
Chris@189 387 connect(dial, SIGNAL(mouseLeft()),
Chris@189 388 this, SLOT(mouseLeftWidget()));
Chris@0 389
Chris@0 390 if (inGroup) {
Chris@0 391 dial->setFixedWidth(24);
Chris@0 392 dial->setFixedHeight(24);
Chris@0 393 m_groupLayouts[groupName]->addWidget(dial);
Chris@0 394 } else {
Chris@0 395 dial->setFixedWidth(32);
Chris@0 396 dial->setFixedHeight(32);
Chris@0 397 m_layout->addWidget(dial, row, 1);
Chris@33 398 QLabel *label = new QLabel(m_mainWidget);
Chris@0 399 connect(dial, SIGNAL(valueChanged(int)),
Chris@0 400 label, SLOT(setNum(int)));
Chris@0 401 label->setNum(value);
Chris@0 402 m_layout->addWidget(label, row, 2);
Chris@0 403 }
Chris@0 404
Chris@0 405 m_propertyControllers[name] = dial;
Chris@0 406 }
Chris@0 407
Chris@55 408 if (dial->value() != value) {
Chris@55 409 dial->blockSignals(true);
Chris@55 410 dial->setValue(value);
Chris@55 411 dial->blockSignals(false);
Chris@55 412 }
Chris@0 413 break;
Chris@0 414 }
Chris@0 415
Chris@0 416 case PropertyContainer::ValueProperty:
Chris@100 417 case PropertyContainer::UnitsProperty:
Chris@285 418 case PropertyContainer::ColourProperty:
Chris@0 419 {
Chris@189 420 NotifyingComboBox *cb;
Chris@0 421
Chris@0 422 if (have) {
Chris@189 423 cb = dynamic_cast<NotifyingComboBox *>(m_propertyControllers[name]);
Chris@0 424 assert(cb);
Chris@0 425 } else {
Chris@0 426 #ifdef DEBUG_PROPERTY_BOX
Chris@0 427 std::cerr << "PropertyBox: creating new combobox" << std::endl;
Chris@0 428 #endif
Chris@0 429
Chris@189 430 cb = new NotifyingComboBox();
Chris@0 431 cb->setObjectName(name);
Chris@100 432 cb->setDuplicatesEnabled(false);
Chris@197 433 }
Chris@100 434
Chris@197 435 if (!have || rangeChanged) {
Chris@285 436
Chris@197 437 cb->blockSignals(true);
Chris@197 438 cb->clear();
Chris@285 439 cb->setEditable(false);
Chris@285 440
Chris@100 441 if (type == PropertyContainer::ValueProperty) {
Chris@285 442
Chris@100 443 for (int i = min; i <= max; ++i) {
Chris@100 444 cb->addItem(m_container->getPropertyValueLabel(name, i));
Chris@100 445 }
Chris@285 446
Chris@285 447 } else if (type == PropertyContainer::UnitsProperty) {
Chris@285 448
Chris@100 449 QStringList units = UnitDatabase::getInstance()->getKnownUnits();
Chris@100 450 for (int i = 0; i < units.size(); ++i) {
Chris@100 451 cb->addItem(units[i]);
Chris@100 452 }
Chris@285 453
Chris@100 454 cb->setEditable(true);
Chris@285 455
Chris@285 456 } else { // ColourProperty
Chris@290 457
Chris@290 458 //!!! should be a proper colour combobox class that
Chris@290 459 // manages its own Add New Colour entry...
Chris@285 460
Chris@285 461 ColourDatabase *db = ColourDatabase::getInstance();
Chris@285 462 for (size_t i = 0; i < db->getColourCount(); ++i) {
Chris@285 463 QString name = db->getColourName(i);
Chris@287 464 cb->addItem(db->getExamplePixmap(i, QSize(12, 12)), name);
Chris@285 465 }
Chris@285 466 cb->addItem(tr("Add New Colour..."));
Chris@285 467 }
Chris@285 468
Chris@197 469 cb->blockSignals(false);
Chris@280 470 if (cb->count() < 20 && cb->count() > cb->maxVisibleItems()) {
Chris@280 471 cb->setMaxVisibleItems(cb->count());
Chris@280 472 }
Chris@197 473 }
Chris@100 474
Chris@197 475 if (!have) {
Chris@0 476 connect(cb, SIGNAL(activated(int)),
Chris@0 477 this, SLOT(propertyControllerChanged(int)));
Chris@189 478 connect(cb, SIGNAL(mouseEntered()),
Chris@189 479 this, SLOT(mouseEnteredWidget()));
Chris@189 480 connect(cb, SIGNAL(mouseLeft()),
Chris@189 481 this, SLOT(mouseLeftWidget()));
Chris@100 482
Chris@0 483 if (inGroup) {
Chris@108 484 cb->setToolTip(propertyLabel);
Chris@0 485 m_groupLayouts[groupName]->addWidget(cb);
Chris@0 486 } else {
Chris@0 487 m_layout->addWidget(cb, row, 1, 1, 2);
Chris@0 488 }
Chris@0 489 m_propertyControllers[name] = cb;
Chris@0 490 }
Chris@0 491
Chris@100 492 cb->blockSignals(true);
Chris@285 493 if (type == PropertyContainer::ValueProperty ||
Chris@285 494 type == PropertyContainer::ColourProperty) {
Chris@100 495 if (cb->currentIndex() != value) {
Chris@100 496 cb->setCurrentIndex(value);
Chris@100 497 }
Chris@100 498 } else {
Chris@100 499 QString unit = UnitDatabase::getInstance()->getUnitById(value);
Chris@100 500 if (cb->currentText() != unit) {
Chris@100 501 for (int i = 0; i < cb->count(); ++i) {
Chris@100 502 if (cb->itemText(i) == unit) {
Chris@100 503 cb->setCurrentIndex(i);
Chris@100 504 break;
Chris@100 505 }
Chris@100 506 }
Chris@100 507 }
Chris@100 508 }
Chris@100 509 cb->blockSignals(false);
Chris@0 510
Chris@0 511 #ifdef Q_WS_MAC
Chris@0 512 // Crashes on startup without this, for some reason
Chris@0 513 cb->setMinimumSize(QSize(10, 10));
Chris@0 514 #endif
Chris@0 515
Chris@0 516 break;
Chris@0 517 }
Chris@0 518
Chris@0 519 default:
Chris@0 520 break;
Chris@0 521 }
Chris@0 522 }
Chris@0 523
Chris@0 524 void
Chris@0 525 PropertyBox::propertyContainerPropertyChanged(PropertyContainer *pc)
Chris@0 526 {
Chris@0 527 if (pc != m_container) return;
Chris@0 528
Chris@55 529 #ifdef DEBUG_PROPERTY_BOX
Chris@55 530 std::cerr << "PropertyBox::propertyContainerPropertyChanged" << std::endl;
Chris@55 531 #endif
Chris@55 532
Chris@0 533 PropertyContainer::PropertyList properties = m_container->getProperties();
Chris@0 534 size_t i;
Chris@0 535
Chris@0 536 blockSignals(true);
Chris@0 537
Chris@0 538 for (i = 0; i < properties.size(); ++i) {
Chris@0 539 updatePropertyEditor(properties[i]);
Chris@0 540 }
Chris@0 541
Chris@0 542 blockSignals(false);
Chris@0 543 }
Chris@0 544
Chris@0 545 void
Chris@249 546 PropertyBox::propertyContainerPropertyRangeChanged(PropertyContainer *)
Chris@197 547 {
Chris@197 548 blockSignals(true);
Chris@197 549
Chris@197 550 PropertyContainer::PropertyList properties = m_container->getProperties();
Chris@197 551 for (size_t i = 0; i < properties.size(); ++i) {
Chris@197 552 updatePropertyEditor(properties[i], true);
Chris@197 553 }
Chris@197 554
Chris@197 555 blockSignals(false);
Chris@197 556 }
Chris@197 557
Chris@197 558 void
Chris@100 559 PropertyBox::unitDatabaseChanged()
Chris@100 560 {
Chris@454 561 std::cerr << "PropertyBox[" << this << "]: unitDatabaseChanged" << std::endl;
Chris@100 562 blockSignals(true);
Chris@100 563
Chris@456 564 // std::cerr << "my container is " << m_container << std::endl;
Chris@456 565 // std::cerr << "my container's name is... " << std::endl;
Chris@456 566 // std::cerr << m_container->objectName().toStdString() << std::endl;
Chris@456 567
Chris@100 568 PropertyContainer::PropertyList properties = m_container->getProperties();
Chris@100 569 for (size_t i = 0; i < properties.size(); ++i) {
Chris@285 570 if (m_container->getPropertyType(properties[i]) ==
Chris@285 571 PropertyContainer::UnitsProperty) {
Chris@285 572 updatePropertyEditor(properties[i]);
Chris@285 573 }
Chris@285 574 }
Chris@285 575
Chris@285 576 blockSignals(false);
Chris@285 577 }
Chris@285 578
Chris@285 579 void
Chris@285 580 PropertyBox::colourDatabaseChanged()
Chris@285 581 {
Chris@285 582 blockSignals(true);
Chris@285 583
Chris@285 584 PropertyContainer::PropertyList properties = m_container->getProperties();
Chris@285 585 for (size_t i = 0; i < properties.size(); ++i) {
Chris@285 586 if (m_container->getPropertyType(properties[i]) ==
Chris@285 587 PropertyContainer::ColourProperty) {
Chris@285 588 updatePropertyEditor(properties[i], true);
Chris@285 589 }
Chris@100 590 }
Chris@100 591
Chris@100 592 blockSignals(false);
Chris@100 593 }
Chris@100 594
Chris@100 595 void
Chris@335 596 PropertyBox::propertyControllerChanged(bool on)
Chris@335 597 {
Chris@335 598 propertyControllerChanged(on ? 1 : 0);
Chris@335 599 }
Chris@335 600
Chris@335 601 void
Chris@0 602 PropertyBox::propertyControllerChanged(int value)
Chris@0 603 {
Chris@0 604 QObject *obj = sender();
Chris@0 605 QString name = obj->objectName();
Chris@0 606
Chris@34 607 #ifdef DEBUG_PROPERTY_BOX
Chris@33 608 std::cerr << "PropertyBox::propertyControllerChanged(" << name.toStdString()
Chris@33 609 << ", " << value << ")" << std::endl;
Chris@34 610 #endif
Chris@0 611
Chris@0 612 PropertyContainer::PropertyType type = m_container->getPropertyType(name);
Chris@100 613
Chris@376 614 Command *c = 0;
Chris@376 615
Chris@100 616 if (type == PropertyContainer::UnitsProperty) {
Chris@285 617
Chris@189 618 NotifyingComboBox *cb = dynamic_cast<NotifyingComboBox *>(obj);
Chris@100 619 if (cb) {
Chris@100 620 QString unit = cb->currentText();
Chris@376 621 c = m_container->getSetPropertyCommand
Chris@100 622 (name, UnitDatabase::getInstance()->getUnitId(unit));
Chris@100 623 }
Chris@285 624
Chris@285 625 } else if (type == PropertyContainer::ColourProperty) {
Chris@285 626
Chris@285 627 if (value == int(ColourDatabase::getInstance()->getColourCount())) {
Chris@285 628 addNewColour();
Chris@285 629 if (value == int(ColourDatabase::getInstance()->getColourCount())) {
Chris@285 630 propertyContainerPropertyChanged(m_container);
Chris@285 631 return;
Chris@285 632 }
Chris@285 633 }
Chris@376 634 c = m_container->getSetPropertyCommand(name, value);
Chris@285 635
Chris@100 636 } else if (type != PropertyContainer::InvalidProperty) {
Chris@285 637
Chris@376 638 c = m_container->getSetPropertyCommand(name, value);
Chris@0 639 }
Chris@376 640
Chris@376 641 if (c) CommandHistory::getInstance()->addCommand(c, true, true);
Chris@218 642
Chris@218 643 updateContextHelp(obj);
Chris@0 644 }
Chris@285 645
Chris@285 646 void
Chris@285 647 PropertyBox::addNewColour()
Chris@285 648 {
Chris@285 649 QColor newColour = QColorDialog::getColor();
Chris@285 650 if (!newColour.isValid()) return;
Chris@285 651
Chris@285 652 ColourNameDialog dialog(tr("Name New Colour"),
Chris@361 653 tr("Enter a name for the new colour:"),
Chris@361 654 newColour, newColour.name(), this);
Chris@285 655 dialog.showDarkBackgroundCheckbox(tr("Prefer black background for this colour"));
Chris@285 656 if (dialog.exec() == QDialog::Accepted) {
Chris@285 657 //!!! command
Chris@285 658 ColourDatabase *db = ColourDatabase::getInstance();
Chris@285 659 int index = db->addColour(newColour, dialog.getColourName());
Chris@285 660 db->setUseDarkBackground(index, dialog.isDarkBackgroundChecked());
Chris@285 661 }
Chris@285 662 }
Chris@377 663
Chris@377 664 void
Chris@377 665 PropertyBox::playAudibleChanged(bool audible)
Chris@377 666 {
Chris@377 667 m_playButton->setState(audible);
Chris@377 668 }
Chris@377 669
Chris@377 670 void
Chris@377 671 PropertyBox::playAudibleButtonChanged(bool audible)
Chris@377 672 {
Chris@377 673 PlayParameters *params = m_container->getPlayParameters();
Chris@377 674 if (!params) return;
Chris@377 675
Chris@377 676 if (params->isPlayAudible() != audible) {
Chris@377 677 PlayParameterRepository::EditCommand *command =
Chris@377 678 new PlayParameterRepository::EditCommand(params);
Chris@377 679 command->setPlayAudible(audible);
Chris@377 680 CommandHistory::getInstance()->addCommand(command, true, true);
Chris@377 681 }
Chris@377 682 }
Chris@0 683
Chris@34 684 void
Chris@34 685 PropertyBox::playGainChanged(float gain)
Chris@34 686 {
Chris@34 687 int dialValue = lrint(log10(gain) * 20.0);
Chris@34 688 if (dialValue < -50) dialValue = -50;
Chris@34 689 if (dialValue > 50) dialValue = 50;
Chris@34 690 emit changePlayGainDial(dialValue);
Chris@34 691 }
Chris@34 692
Chris@34 693 void
Chris@34 694 PropertyBox::playGainDialChanged(int dialValue)
Chris@34 695 {
Chris@218 696 QObject *obj = sender();
Chris@377 697
Chris@377 698 PlayParameters *params = m_container->getPlayParameters();
Chris@377 699 if (!params) return;
Chris@377 700
Chris@34 701 float gain = pow(10, float(dialValue) / 20.0);
Chris@377 702
Chris@377 703 if (params->getPlayGain() != gain) {
Chris@377 704 PlayParameterRepository::EditCommand *command =
Chris@377 705 new PlayParameterRepository::EditCommand(params);
Chris@377 706 command->setPlayGain(gain);
Chris@377 707 CommandHistory::getInstance()->addCommand(command, true, true);
Chris@377 708 }
Chris@377 709
Chris@218 710 updateContextHelp(obj);
Chris@34 711 }
Chris@34 712
Chris@34 713 void
Chris@34 714 PropertyBox::playPanChanged(float pan)
Chris@34 715 {
Chris@34 716 int dialValue = lrint(pan * 50.0);
Chris@34 717 if (dialValue < -50) dialValue = -50;
Chris@34 718 if (dialValue > 50) dialValue = 50;
Chris@34 719 emit changePlayPanDial(dialValue);
Chris@34 720 }
Chris@34 721
Chris@34 722 void
Chris@34 723 PropertyBox::playPanDialChanged(int dialValue)
Chris@34 724 {
Chris@218 725 QObject *obj = sender();
Chris@377 726
Chris@377 727 PlayParameters *params = m_container->getPlayParameters();
Chris@377 728 if (!params) return;
Chris@377 729
Chris@34 730 float pan = float(dialValue) / 50.0;
Chris@34 731 if (pan < -1.0) pan = -1.0;
Chris@34 732 if (pan > 1.0) pan = 1.0;
Chris@377 733
Chris@377 734 if (params->getPlayPan() != pan) {
Chris@377 735 PlayParameterRepository::EditCommand *command =
Chris@377 736 new PlayParameterRepository::EditCommand(params);
Chris@377 737 command->setPlayPan(pan);
Chris@377 738 CommandHistory::getInstance()->addCommand(command, true, true);
Chris@377 739 }
Chris@377 740
Chris@218 741 updateContextHelp(obj);
Chris@34 742 }
Chris@0 743
Chris@63 744 void
Chris@63 745 PropertyBox::editPlugin()
Chris@63 746 {
Chris@63 747 //!!! should probably just emit and let something else do this
Chris@63 748
Chris@63 749 PlayParameters *params = m_container->getPlayParameters();
Chris@63 750 if (!params) return;
Chris@63 751
Chris@63 752 QString pluginId = params->getPlayPluginId();
Chris@63 753 QString configurationXml = params->getPlayPluginConfiguration();
Chris@377 754
Chris@377 755 PlayParameterRepository::EditCommand *command =
Chris@377 756 new PlayParameterRepository::EditCommand(params);
Chris@63 757
Chris@63 758 RealTimePluginFactory *factory =
Chris@63 759 RealTimePluginFactory::instanceFor(pluginId);
Chris@63 760 if (!factory) return;
Chris@63 761
Chris@63 762 RealTimePluginInstance *instance =
Chris@63 763 factory->instantiatePlugin(pluginId, 0, 0, 48000, 1024, 1);
Chris@63 764 if (!instance) return;
Chris@63 765
Chris@71 766 PluginXml(instance).setParametersFromXml(configurationXml);
Chris@63 767
Chris@163 768 PluginParameterDialog *dialog = new PluginParameterDialog(instance);
Chris@64 769 connect(dialog, SIGNAL(pluginConfigurationChanged(QString)),
Chris@64 770 this, SLOT(pluginConfigurationChanged(QString)));
Chris@64 771
Chris@63 772 if (dialog->exec() == QDialog::Accepted) {
Chris@377 773 QString newConfiguration = PluginXml(instance).toXmlString();
Chris@377 774 command->setPlayPluginConfiguration(newConfiguration);
Chris@377 775 CommandHistory::getInstance()->addCommand(command, true);
Chris@64 776 } else {
Chris@377 777 delete command;
Chris@64 778 // restore in case we mucked about with the configuration
Chris@64 779 // as a consequence of signals from the dialog
Chris@64 780 params->setPlayPluginConfiguration(configurationXml);
Chris@63 781 }
Chris@63 782
Chris@63 783 delete dialog;
Chris@63 784 delete instance;
Chris@63 785 }
Chris@63 786
Chris@64 787 void
Chris@64 788 PropertyBox::pluginConfigurationChanged(QString configurationXml)
Chris@64 789 {
Chris@64 790 PlayParameters *params = m_container->getPlayParameters();
Chris@64 791 if (!params) return;
Chris@64 792
Chris@64 793 params->setPlayPluginConfiguration(configurationXml);
Chris@64 794 }
Chris@185 795
Chris@185 796 void
Chris@185 797 PropertyBox::layerVisibilityChanged(bool visible)
Chris@185 798 {
Chris@185 799 if (m_showButton) m_showButton->setState(visible);
Chris@185 800 }
Chris@189 801
Chris@189 802 void
Chris@189 803 PropertyBox::mouseEnteredWidget()
Chris@189 804 {
Chris@218 805 updateContextHelp(sender());
Chris@218 806 }
Chris@218 807
Chris@218 808 void
Chris@218 809 PropertyBox::updateContextHelp(QObject *o)
Chris@218 810 {
Chris@218 811 QWidget *w = dynamic_cast<QWidget *>(o);
Chris@189 812 if (!w) return;
Chris@218 813
Chris@189 814 if (!m_container) return;
Chris@190 815 QString cname = m_container->getPropertyContainerName();
Chris@189 816 if (cname == "") return;
Chris@189 817
Chris@189 818 QString wname = w->objectName();
Chris@189 819
Chris@218 820 QString extraText;
Chris@218 821 AudioDial *dial = dynamic_cast<AudioDial *>(w);
Chris@218 822 if (dial) {
Chris@218 823 float mv = dial->mappedValue();
Chris@218 824 QString unit = "";
Chris@218 825 if (dial->rangeMapper()) unit = dial->rangeMapper()->getUnit();
Chris@218 826 if (unit != "") {
Chris@218 827 extraText = tr(" (current value: %1%2)").arg(mv).arg(unit);
Chris@218 828 } else {
Chris@218 829 extraText = tr(" (current value: %1)").arg(mv);
Chris@218 830 }
Chris@218 831 }
Chris@218 832
Chris@189 833 if (w == m_showButton) {
Chris@190 834 emit contextHelpChanged(tr("Toggle Visibility of %1").arg(cname));
Chris@189 835 } else if (w == m_playButton) {
Chris@190 836 emit contextHelpChanged(tr("Toggle Playback of %1").arg(cname));
Chris@189 837 } else if (wname == "") {
Chris@189 838 return;
Chris@335 839 } else if (dynamic_cast<QAbstractButton *>(w)) {
Chris@190 840 emit contextHelpChanged(tr("Toggle %1 property of %2")
Chris@189 841 .arg(wname).arg(cname));
Chris@189 842 } else {
Chris@218 843 emit contextHelpChanged(tr("Adjust %1 property of %2%3")
Chris@218 844 .arg(wname).arg(cname).arg(extraText));
Chris@189 845 }
Chris@189 846 }
Chris@189 847
Chris@189 848 void
Chris@189 849 PropertyBox::mouseLeftWidget()
Chris@189 850 {
Chris@218 851 if (!(QApplication::mouseButtons() & Qt::LeftButton)) {
Chris@218 852 emit contextHelpChanged("");
Chris@218 853 }
Chris@189 854 }
Chris@189 855
Chris@64 856