annotate widgets/PropertyBox.cpp @ 1553:76e4302a3fc2

Fix note numbering - ensure stable across whole track (as it used to be, but without scanning all notes in paint in order to do that)
author Chris Cannam
date Fri, 22 Nov 2019 14:12:50 +0000
parents 284a38c43721
children 2108af725460
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@1408 60 m_showButton(nullptr),
Chris@1408 61 m_playButton(nullptr)
Chris@0 62 {
Chris@0 63 #ifdef DEBUG_PROPERTY_BOX
Chris@1525 64 SVDEBUG << "PropertyBox[" << this << "(\"" <<
Chris@1266 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@1408 85 m_viewPlayFrame = nullptr;
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@1266 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@1525 112 SVDEBUG << "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@1525 119 SVDEBUG << "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@1525 127 SVDEBUG << "PropertyBox[" << this << ":" << m_container << "]::populateViewPlayFrame" << endl;
Chris@36 128 #endif
Chris@34 129
Chris@34 130 if (m_viewPlayFrame) {
Chris@1266 131 delete m_viewPlayFrame;
Chris@1408 132 m_viewPlayFrame = nullptr;
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@1266 139 disconnect(layer, SIGNAL(modelReplaced()),
Chris@193 140 this, SLOT(populateViewPlayFrame()));
Chris@1266 141 connect(layer, SIGNAL(modelReplaced()),
Chris@1266 142 this, SLOT(populateViewPlayFrame()));
Chris@34 143 }
Chris@34 144
Chris@1480 145 auto 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@1266 172 connect(m_playButton, SIGNAL(toggled(bool)),
Chris@1266 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@1480 178 connect(params.get(), SIGNAL(playAudibleChanged(bool)),
Chris@1266 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@1480 189 connect(params.get(), SIGNAL(playGainChanged(float)),
Chris@1178 190 levelPan, SLOT(setLevel(float)));
Chris@1480 191 connect(params.get(), 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@1266 198 layout->addWidget(m_playButton, 0, col++, Qt::AlignCenter);
Chris@1189 199
Chris@1187 200 if (params->getPlayClipId() != "") {
Chris@1223 201 NotifyingToolButton *playParamButton = new NotifyingToolButton;
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@1266 219 QLabel *showLabel = new QLabel(tr("Show"));
Chris@1266 220 layout->addWidget(showLabel, 0, col++, Qt::AlignVCenter | Qt::AlignRight);
Chris@1187 221
Chris@1266 222 m_showButton = new LEDButton(palette().highlight().color());
Chris@1266 223 layout->addWidget(m_showButton, 0, col++, Qt::AlignVCenter | Qt::AlignLeft);
Chris@1266 224 connect(m_showButton, SIGNAL(stateChanged(bool)),
Chris@1266 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@1266 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@1525 251 SVDEBUG << "PropertyBox[" << this
Chris@1266 252 << "(\"" << m_container->getPropertyContainerName()
Chris@1266 253 << "\")]";
Chris@1525 254 SVDEBUG << "::updatePropertyEditor(\"" << name << "\", "
Chris@1281 255 << rangeChanged << "):";
Chris@1525 256 SVDEBUG << " type " << type << ", value " << value
Chris@1281 257 << ", have " << have << ", group \"" << groupName << "\"" << endl;
Chris@0 258 #endif
Chris@0 259
Chris@1204 260 QString groupLabel = groupName;
Chris@1204 261 if (groupName == QString()) {
Chris@1204 262 groupName = "ungrouped: " + name; // not tr(), this is internal id
Chris@1204 263 groupLabel = propertyLabel;
Chris@1204 264 }
Chris@1204 265
Chris@0 266 if (!have) {
Chris@1204 267 if (m_groupLayouts.find(groupName) == m_groupLayouts.end()) {
Chris@1204 268 QWidget *labelWidget = new QLabel(groupLabel, m_mainWidget);
Chris@1190 269 m_layout->addWidget(labelWidget, row, 0);
Chris@1190 270 QWidget *frame = new QWidget(m_mainWidget);
Chris@1190 271 frame->setMinimumSize(WidgetScale::scaleQSize(QSize(1, 24)));
Chris@1190 272 m_groupLayouts[groupName] = new QGridLayout;
Chris@1195 273 #ifdef Q_OS_MAC
Chris@1195 274 // Seems to be plenty of whitespace already
Chris@1195 275 m_groupLayouts[groupName]->setContentsMargins(0, 0, 0, 0);
Chris@1195 276 #else
Chris@1195 277 // Need a bit of padding on the left
Chris@1195 278 m_groupLayouts[groupName]->setContentsMargins
Chris@1195 279 (WidgetScale::scalePixelSize(10), 0, 0, 0);
Chris@1195 280 #endif
Chris@1190 281 frame->setLayout(m_groupLayouts[groupName]);
Chris@1190 282 m_layout->addWidget(frame, row, 1, 1, 2);
Chris@1190 283 m_layout->setColumnStretch(1, 10);
Chris@1190 284 }
Chris@0 285 }
Chris@0 286
Chris@1204 287 QGridLayout *groupLayout = m_groupLayouts[groupName];
Chris@1204 288
Chris@1204 289 #ifdef DEBUG_PROPERTY_BOX
Chris@1525 290 SVDEBUG << "groupName becomes \"" << groupName << "\", groupLabel = \""
Chris@1204 291 << groupLabel << "\", groupLayout = " << groupLayout << endl;
Chris@1204 292 #endif
Chris@1204 293
Chris@1204 294 assert(groupLayout);
Chris@1204 295
Chris@1204 296 QWidget *existing = m_propertyControllers[name];
Chris@1204 297
Chris@0 298 switch (type) {
Chris@0 299
Chris@0 300 case PropertyContainer::ToggleProperty:
Chris@0 301 {
Chris@1204 302 QAbstractButton *button;
Chris@0 303
Chris@1266 304 if (!(button = qobject_cast<QAbstractButton *>(existing))) {
Chris@0 305 #ifdef DEBUG_PROPERTY_BOX
Chris@1525 306 SVDEBUG << "PropertyBox: creating new checkbox" << endl;
Chris@0 307 #endif
Chris@335 308 if (iconName != "") {
cannam@1309 309 #ifdef Q_OS_MAC
cannam@1309 310 button = new NotifyingToolButton();
cannam@1309 311 #else
Chris@335 312 button = new NotifyingPushButton();
cannam@1309 313 #endif
Chris@335 314 button->setCheckable(true);
Chris@335 315 QIcon icon(IconLoader().load(iconName));
Chris@335 316 button->setIcon(icon);
Chris@335 317 button->setObjectName(name);
Chris@1174 318 button->setFixedSize(WidgetScale::scaleQSize(QSize(18, 18)));
Chris@335 319 } else {
Chris@335 320 button = new NotifyingCheckBox();
Chris@335 321 button->setObjectName(name);
Chris@335 322 }
Chris@1266 323 connect(button, SIGNAL(toggled(bool)),
Chris@1266 324 this, SLOT(propertyControllerChanged(bool)));
Chris@335 325 connect(button, SIGNAL(mouseEntered()),
Chris@189 326 this, SLOT(mouseEnteredWidget()));
Chris@335 327 connect(button, SIGNAL(mouseLeft()),
Chris@189 328 this, SLOT(mouseLeftWidget()));
Chris@1197 329 button->setToolTip(propertyLabel);
Chris@1204 330
Chris@1204 331 if (existing) {
Chris@1204 332 groupLayout->replaceWidget(existing, button);
Chris@1204 333 delete existing;
Chris@1204 334 } else {
Chris@1204 335 groupLayout->addWidget(button, 0, groupLayout->columnCount());
Chris@1204 336 }
Chris@1204 337
Chris@1266 338 m_propertyControllers[name] = button;
Chris@1266 339 }
Chris@0 340
Chris@335 341 if (button->isChecked() != (value > 0)) {
Chris@1266 342 button->blockSignals(true);
Chris@1266 343 button->setChecked(value > 0);
Chris@1266 344 button->blockSignals(false);
Chris@1266 345 }
Chris@1266 346 break;
Chris@0 347 }
Chris@0 348
Chris@0 349 case PropertyContainer::RangeProperty:
Chris@0 350 {
Chris@1266 351 AudioDial *dial;
Chris@0 352
Chris@1266 353 if ((dial = qobject_cast<AudioDial *>(existing))) {
Chris@197 354 if (rangeChanged) {
Chris@197 355 dial->blockSignals(true);
Chris@197 356 dial->setMinimum(min);
Chris@197 357 dial->setMaximum(max);
Chris@197 358 dial->setRangeMapper(m_container->getNewPropertyRangeMapper(name));
Chris@197 359 dial->blockSignals(false);
Chris@197 360 }
Chris@1204 361 } else {
Chris@0 362 #ifdef DEBUG_PROPERTY_BOX
Chris@1525 363 SVDEBUG << "PropertyBox: creating new dial" << endl;
Chris@0 364 #endif
Chris@1266 365 dial = new AudioDial();
Chris@1266 366 dial->setObjectName(name);
Chris@1266 367 dial->setMinimum(min);
Chris@1266 368 dial->setMaximum(max);
Chris@1266 369 dial->setPageStep(1);
Chris@1266 370 dial->setNotchesVisible((max - min) <= 12);
Chris@1126 371 // important to set the range mapper before the default,
Chris@1126 372 // because the range mapper is used to map the default
Chris@1126 373 dial->setRangeMapper(m_container->getNewPropertyRangeMapper(name));
Chris@1266 374 dial->setDefaultValue(deflt);
Chris@168 375 dial->setShowToolTip(true);
Chris@1266 376 connect(dial, SIGNAL(valueChanged(int)),
Chris@1266 377 this, SLOT(propertyControllerChanged(int)));
Chris@189 378 connect(dial, SIGNAL(mouseEntered()),
Chris@189 379 this, SLOT(mouseEnteredWidget()));
Chris@189 380 connect(dial, SIGNAL(mouseLeft()),
Chris@189 381 this, SLOT(mouseLeftWidget()));
Chris@0 382
Chris@1197 383 dial->setFixedWidth(WidgetScale::scalePixelSize(24));
Chris@1197 384 dial->setFixedHeight(WidgetScale::scalePixelSize(24));
Chris@1204 385
Chris@1204 386 if (existing) {
Chris@1204 387 groupLayout->replaceWidget(existing, dial);
Chris@1204 388 delete existing;
Chris@1204 389 } else {
Chris@1204 390 groupLayout->addWidget(dial, 0, groupLayout->columnCount());
Chris@1204 391 }
Chris@0 392
Chris@1266 393 m_propertyControllers[name] = dial;
Chris@1266 394 }
Chris@0 395
Chris@1266 396 if (dial->value() != value) {
Chris@1266 397 dial->blockSignals(true);
Chris@1266 398 dial->setValue(value);
Chris@1266 399 dial->blockSignals(false);
Chris@1266 400 }
Chris@1266 401 break;
Chris@0 402 }
Chris@0 403
Chris@1196 404 case PropertyContainer::ColourProperty:
Chris@1196 405 {
Chris@1196 406 ColourComboBox *cb;
Chris@1196 407
Chris@1266 408 if (!(cb = qobject_cast<ColourComboBox *>(existing))) {
Chris@1204 409
Chris@1196 410 #ifdef DEBUG_PROPERTY_BOX
Chris@1525 411 SVDEBUG << "PropertyBox: creating new colour combobox" << endl;
Chris@1196 412 #endif
Chris@1196 413 cb = new ColourComboBox(true);
Chris@1196 414 cb->setObjectName(name);
Chris@1196 415
Chris@1266 416 connect(cb, SIGNAL(colourChanged(int)),
Chris@1266 417 this, SLOT(propertyControllerChanged(int)));
Chris@1196 418 connect(cb, SIGNAL(mouseEntered()),
Chris@1196 419 this, SLOT(mouseEnteredWidget()));
Chris@1196 420 connect(cb, SIGNAL(mouseLeft()),
Chris@1196 421 this, SLOT(mouseLeftWidget()));
Chris@1196 422
Chris@1197 423 cb->setToolTip(propertyLabel);
Chris@1204 424
Chris@1204 425 if (existing) {
Chris@1204 426 groupLayout->replaceWidget(existing, cb);
Chris@1204 427 delete existing;
Chris@1204 428 } else {
Chris@1204 429 groupLayout->addWidget(cb, 0, groupLayout->columnCount());
Chris@1204 430 }
Chris@1204 431
Chris@1266 432 m_propertyControllers[name] = cb;
Chris@1266 433 }
Chris@1196 434
Chris@1196 435 if (cb->currentIndex() != value) {
Chris@1196 436 cb->blockSignals(true);
Chris@1196 437 cb->setCurrentIndex(value);
Chris@1196 438 cb->blockSignals(false);
Chris@1196 439 }
Chris@1196 440
Chris@1198 441 break;
Chris@1198 442 }
Chris@1198 443
Chris@1198 444 case PropertyContainer::ColourMapProperty:
Chris@1198 445 {
Chris@1198 446 ColourMapComboBox *cb;
Chris@1204 447
Chris@1204 448 if (!(cb = qobject_cast<ColourMapComboBox *>(existing))) {
Chris@1198 449 #ifdef DEBUG_PROPERTY_BOX
Chris@1525 450 SVDEBUG << "PropertyBox: creating new colourmap combobox" << endl;
Chris@1196 451 #endif
Chris@1199 452 cb = new ColourMapComboBox(false);
Chris@1198 453 cb->setObjectName(name);
Chris@1196 454
Chris@1266 455 connect(cb, SIGNAL(colourMapChanged(int)),
Chris@1266 456 this, SLOT(propertyControllerChanged(int)));
Chris@1198 457 connect(cb, SIGNAL(mouseEntered()),
Chris@1198 458 this, SLOT(mouseEnteredWidget()));
Chris@1198 459 connect(cb, SIGNAL(mouseLeft()),
Chris@1198 460 this, SLOT(mouseLeftWidget()));
Chris@1204 461
Chris@1204 462 cb->setToolTip(propertyLabel);
Chris@1198 463
Chris@1204 464 if (existing) {
Chris@1204 465 groupLayout->replaceWidget(existing, cb);
Chris@1204 466 delete existing;
Chris@1204 467 } else {
Chris@1204 468 groupLayout->addWidget(cb, 0, groupLayout->columnCount());
Chris@1204 469 }
Chris@1204 470
Chris@1266 471 m_propertyControllers[name] = cb;
Chris@1266 472 }
Chris@1198 473
Chris@1198 474 if (cb->currentIndex() != value) {
Chris@1198 475 cb->blockSignals(true);
Chris@1198 476 cb->setCurrentIndex(value);
Chris@1198 477 cb->blockSignals(false);
Chris@1198 478 }
Chris@1198 479
Chris@1196 480 break;
Chris@1196 481 }
Chris@1196 482
Chris@0 483 case PropertyContainer::ValueProperty:
Chris@100 484 case PropertyContainer::UnitsProperty:
Chris@0 485 {
Chris@1266 486 NotifyingComboBox *cb;
Chris@0 487
Chris@1266 488 if (!(cb = qobject_cast<NotifyingComboBox *>(existing))) {
Chris@0 489 #ifdef DEBUG_PROPERTY_BOX
Chris@1525 490 SVDEBUG << "PropertyBox: creating new combobox" << endl;
Chris@0 491 #endif
Chris@1266 492 cb = new NotifyingComboBox();
Chris@1266 493 cb->setObjectName(name);
Chris@100 494 cb->setDuplicatesEnabled(false);
Chris@197 495 }
Chris@100 496
Chris@197 497 if (!have || rangeChanged) {
Chris@285 498
Chris@197 499 cb->blockSignals(true);
Chris@197 500 cb->clear();
Chris@285 501 cb->setEditable(false);
Chris@285 502
Chris@100 503 if (type == PropertyContainer::ValueProperty) {
Chris@285 504
Chris@100 505 for (int i = min; i <= max; ++i) {
Chris@862 506
Chris@862 507 QString label = m_container->getPropertyValueLabel(name, i);
Chris@862 508 QString iname = m_container->getPropertyValueIconName(name, i);
Chris@862 509
Chris@862 510 if (iname != "") {
Chris@862 511 QIcon icon(IconLoader().load(iname));
Chris@862 512 cb->addItem(icon, label);
Chris@862 513 } else {
Chris@862 514 cb->addItem(label);
Chris@862 515 }
Chris@100 516 }
Chris@285 517
Chris@1196 518 } else { // PropertyContainer::UnitsProperty
Chris@285 519
Chris@100 520 QStringList units = UnitDatabase::getInstance()->getKnownUnits();
Chris@100 521 for (int i = 0; i < units.size(); ++i) {
Chris@100 522 cb->addItem(units[i]);
Chris@100 523 }
Chris@285 524
Chris@100 525 cb->setEditable(true);
Chris@280 526 }
Chris@197 527 }
Chris@100 528
Chris@197 529 if (!have) {
Chris@1266 530 connect(cb, SIGNAL(activated(int)),
Chris@1266 531 this, SLOT(propertyControllerChanged(int)));
Chris@189 532 connect(cb, SIGNAL(mouseEntered()),
Chris@189 533 this, SLOT(mouseEnteredWidget()));
Chris@189 534 connect(cb, SIGNAL(mouseLeft()),
Chris@189 535 this, SLOT(mouseLeftWidget()));
Chris@100 536
Chris@1197 537 cb->setToolTip(propertyLabel);
Chris@1204 538 groupLayout->addWidget(cb, 0, groupLayout->columnCount());
Chris@1266 539 m_propertyControllers[name] = cb;
Chris@1266 540 } else if (existing != cb) {
Chris@1204 541 groupLayout->replaceWidget(existing, cb);
Chris@1204 542 delete existing;
Chris@1204 543 }
Chris@0 544
Chris@100 545 cb->blockSignals(true);
Chris@1196 546 if (type == PropertyContainer::ValueProperty) {
Chris@100 547 if (cb->currentIndex() != value) {
Chris@100 548 cb->setCurrentIndex(value);
Chris@100 549 }
Chris@100 550 } else {
Chris@100 551 QString unit = UnitDatabase::getInstance()->getUnitById(value);
Chris@100 552 if (cb->currentText() != unit) {
Chris@100 553 for (int i = 0; i < cb->count(); ++i) {
Chris@100 554 if (cb->itemText(i) == unit) {
Chris@100 555 cb->setCurrentIndex(i);
Chris@100 556 break;
Chris@100 557 }
Chris@100 558 }
Chris@100 559 }
Chris@100 560 }
Chris@100 561 cb->blockSignals(false);
Chris@0 562
Chris@1266 563 break;
Chris@0 564 }
Chris@0 565
Chris@807 566 case PropertyContainer::InvalidProperty:
Chris@0 567 default:
Chris@1266 568 break;
Chris@0 569 }
Chris@0 570 }
Chris@0 571
Chris@0 572 void
Chris@0 573 PropertyBox::propertyContainerPropertyChanged(PropertyContainer *pc)
Chris@0 574 {
Chris@0 575 if (pc != m_container) return;
Chris@0 576
Chris@55 577 #ifdef DEBUG_PROPERTY_BOX
Chris@587 578 SVDEBUG << "PropertyBox::propertyContainerPropertyChanged" << endl;
Chris@55 579 #endif
Chris@55 580
Chris@0 581 PropertyContainer::PropertyList properties = m_container->getProperties();
Chris@0 582 size_t i;
Chris@0 583
Chris@0 584 blockSignals(true);
Chris@0 585
Chris@0 586 for (i = 0; i < properties.size(); ++i) {
Chris@1266 587 updatePropertyEditor(properties[i]);
Chris@0 588 }
Chris@0 589
Chris@0 590 blockSignals(false);
Chris@0 591 }
Chris@0 592
Chris@0 593 void
Chris@249 594 PropertyBox::propertyContainerPropertyRangeChanged(PropertyContainer *)
Chris@197 595 {
Chris@197 596 blockSignals(true);
Chris@197 597
Chris@197 598 PropertyContainer::PropertyList properties = m_container->getProperties();
Chris@197 599 for (size_t i = 0; i < properties.size(); ++i) {
Chris@1266 600 updatePropertyEditor(properties[i], true);
Chris@197 601 }
Chris@197 602
Chris@197 603 blockSignals(false);
Chris@197 604 }
Chris@197 605
Chris@197 606 void
Chris@100 607 PropertyBox::unitDatabaseChanged()
Chris@100 608 {
Chris@729 609 #ifdef DEBUG_PROPERTY_BOX
Chris@1525 610 SVDEBUG << "PropertyBox[" << this << "]: unitDatabaseChanged" << endl;
Chris@729 611 #endif
Chris@100 612 blockSignals(true);
Chris@100 613
Chris@1525 614 // SVDEBUG << "my container is " << m_container << endl;
Chris@1525 615 // SVDEBUG << "my container's name is... " << endl;
Chris@1525 616 // SVDEBUG << m_container->objectName() << endl;
Chris@456 617
Chris@100 618 PropertyContainer::PropertyList properties = m_container->getProperties();
Chris@100 619 for (size_t i = 0; i < properties.size(); ++i) {
Chris@285 620 if (m_container->getPropertyType(properties[i]) ==
Chris@285 621 PropertyContainer::UnitsProperty) {
Chris@285 622 updatePropertyEditor(properties[i]);
Chris@285 623 }
Chris@285 624 }
Chris@285 625
Chris@285 626 blockSignals(false);
Chris@285 627 }
Chris@285 628
Chris@285 629 void
Chris@335 630 PropertyBox::propertyControllerChanged(bool on)
Chris@335 631 {
Chris@335 632 propertyControllerChanged(on ? 1 : 0);
Chris@335 633 }
Chris@335 634
Chris@335 635 void
Chris@0 636 PropertyBox::propertyControllerChanged(int value)
Chris@0 637 {
Chris@0 638 QObject *obj = sender();
Chris@0 639 QString name = obj->objectName();
Chris@0 640
Chris@34 641 #ifdef DEBUG_PROPERTY_BOX
Chris@1498 642 SVDEBUG << "PropertyBox::propertyControllerChanged(" << name
Chris@1498 643 << ", " << value << ")" << endl;
Chris@34 644 #endif
Chris@0 645
Chris@0 646 PropertyContainer::PropertyType type = m_container->getPropertyType(name);
Chris@100 647
Chris@1408 648 Command *c = nullptr;
Chris@376 649
Chris@100 650 if (type == PropertyContainer::UnitsProperty) {
Chris@285 651
Chris@1196 652 NotifyingComboBox *cb = qobject_cast<NotifyingComboBox *>(obj);
Chris@100 653 if (cb) {
Chris@100 654 QString unit = cb->currentText();
Chris@376 655 c = m_container->getSetPropertyCommand
Chris@100 656 (name, UnitDatabase::getInstance()->getUnitId(unit));
Chris@100 657 }
Chris@285 658
Chris@100 659 } else if (type != PropertyContainer::InvalidProperty) {
Chris@285 660
Chris@1266 661 c = m_container->getSetPropertyCommand(name, value);
Chris@0 662 }
Chris@376 663
Chris@376 664 if (c) CommandHistory::getInstance()->addCommand(c, true, true);
Chris@218 665
Chris@218 666 updateContextHelp(obj);
Chris@0 667 }
Chris@285 668
Chris@285 669 void
Chris@377 670 PropertyBox::playAudibleChanged(bool audible)
Chris@377 671 {
Chris@1180 672 m_playButton->setChecked(audible);
Chris@377 673 }
Chris@377 674
Chris@377 675 void
Chris@377 676 PropertyBox::playAudibleButtonChanged(bool audible)
Chris@377 677 {
Chris@1480 678 auto params = m_container->getPlayParameters();
Chris@377 679 if (!params) return;
Chris@377 680
Chris@377 681 if (params->isPlayAudible() != audible) {
Chris@377 682 PlayParameterRepository::EditCommand *command =
Chris@377 683 new PlayParameterRepository::EditCommand(params);
Chris@377 684 command->setPlayAudible(audible);
Chris@377 685 CommandHistory::getInstance()->addCommand(command, true, true);
Chris@377 686 }
Chris@377 687 }
Chris@34 688
Chris@34 689 void
Chris@1178 690 PropertyBox::playGainControlChanged(float gain)
Chris@34 691 {
Chris@218 692 QObject *obj = sender();
Chris@377 693
Chris@1480 694 auto params = m_container->getPlayParameters();
Chris@377 695 if (!params) return;
Chris@377 696
Chris@377 697 if (params->getPlayGain() != gain) {
Chris@377 698 PlayParameterRepository::EditCommand *command =
Chris@377 699 new PlayParameterRepository::EditCommand(params);
Chris@377 700 command->setPlayGain(gain);
Chris@377 701 CommandHistory::getInstance()->addCommand(command, true, true);
Chris@377 702 }
Chris@377 703
Chris@218 704 updateContextHelp(obj);
Chris@34 705 }
Chris@34 706
Chris@34 707 void
Chris@1178 708 PropertyBox::playPanControlChanged(float pan)
Chris@34 709 {
Chris@218 710 QObject *obj = sender();
Chris@377 711
Chris@1480 712 auto params = m_container->getPlayParameters();
Chris@377 713 if (!params) return;
Chris@377 714
Chris@377 715 if (params->getPlayPan() != pan) {
Chris@377 716 PlayParameterRepository::EditCommand *command =
Chris@377 717 new PlayParameterRepository::EditCommand(params);
Chris@377 718 command->setPlayPan(pan);
Chris@377 719 CommandHistory::getInstance()->addCommand(command, true, true);
Chris@377 720 }
Chris@377 721
Chris@218 722 updateContextHelp(obj);
Chris@34 723 }
Chris@769 724
Chris@63 725 void
Chris@769 726 PropertyBox::editPlayParameters()
Chris@63 727 {
Chris@1480 728 auto params = m_container->getPlayParameters();
Chris@63 729 if (!params) return;
Chris@63 730
Chris@769 731 QString clip = params->getPlayClipId();
Chris@377 732
Chris@377 733 PlayParameterRepository::EditCommand *command =
Chris@377 734 new PlayParameterRepository::EditCommand(params);
Chris@63 735
Chris@769 736 QInputDialog *dialog = new QInputDialog(this);
Chris@63 737
Chris@769 738 QDir dir(":/samples");
Chris@769 739 QStringList clipFiles = dir.entryList(QStringList() << "*.wav", QDir::Files);
Chris@63 740
Chris@769 741 QStringList clips;
Chris@769 742 foreach (QString str, clipFiles) {
Chris@769 743 clips.push_back(str.replace(".wav", ""));
Chris@769 744 }
Chris@769 745 dialog->setComboBoxItems(clips);
Chris@63 746
Chris@769 747 dialog->setLabelText(tr("Set playback clip:"));
Chris@769 748
Chris@769 749 QComboBox *cb = dialog->findChild<QComboBox *>();
Chris@779 750 if (cb) {
Chris@779 751 for (int i = 0; i < cb->count(); ++i) {
Chris@779 752 if (cb->itemText(i) == clip) {
Chris@779 753 cb->setCurrentIndex(i);
Chris@779 754 }
Chris@779 755 }
Chris@779 756 }
Chris@769 757
Chris@769 758 connect(dialog, SIGNAL(textValueChanged(QString)),
Chris@769 759 this, SLOT(playClipChanged(QString)));
Chris@64 760
Chris@63 761 if (dialog->exec() == QDialog::Accepted) {
Chris@769 762 QString newClip = dialog->textValue();
Chris@769 763 command->setPlayClipId(newClip);
Chris@377 764 CommandHistory::getInstance()->addCommand(command, true);
Chris@64 765 } else {
Chris@377 766 delete command;
Chris@64 767 // restore in case we mucked about with the configuration
Chris@64 768 // as a consequence of signals from the dialog
Chris@769 769 params->setPlayClipId(clip);
Chris@63 770 }
Chris@63 771
Chris@63 772 delete dialog;
Chris@63 773 }
Chris@63 774
Chris@64 775 void
Chris@769 776 PropertyBox::playClipChanged(QString id)
Chris@64 777 {
Chris@1480 778 auto params = m_container->getPlayParameters();
Chris@64 779 if (!params) return;
Chris@64 780
Chris@769 781 params->setPlayClipId(id);
Chris@64 782 }
Chris@769 783
Chris@185 784 void
Chris@185 785 PropertyBox::layerVisibilityChanged(bool visible)
Chris@185 786 {
Chris@185 787 if (m_showButton) m_showButton->setState(visible);
Chris@185 788 }
Chris@189 789
Chris@189 790 void
Chris@189 791 PropertyBox::mouseEnteredWidget()
Chris@189 792 {
Chris@218 793 updateContextHelp(sender());
Chris@218 794 }
Chris@218 795
Chris@218 796 void
Chris@218 797 PropertyBox::updateContextHelp(QObject *o)
Chris@218 798 {
Chris@1196 799 QWidget *w = qobject_cast<QWidget *>(o);
Chris@189 800 if (!w) return;
Chris@218 801
Chris@189 802 if (!m_container) return;
Chris@190 803 QString cname = m_container->getPropertyContainerName();
Chris@189 804 if (cname == "") return;
Chris@189 805
Chris@1380 806 QString help;
Chris@1380 807 QString mainText;
Chris@1380 808 QString extraText;
Chris@1380 809 QString editText;
Chris@1380 810
Chris@1380 811 QString wname = w->objectName();
Chris@1380 812 QString propertyLabel;
Chris@1380 813 if (wname != "") {
Chris@1380 814 propertyLabel = m_container->getPropertyLabel(wname);
Chris@1180 815 }
Chris@1180 816
Chris@1380 817 LevelPanToolButton *lp = qobject_cast<LevelPanToolButton *>(w);
Chris@1380 818 AudioDial *dial = qobject_cast<AudioDial *>(w);
Chris@189 819
Chris@1380 820 if (lp) {
Chris@1380 821
Chris@1380 822 mainText = tr("Adjust playback level and pan of %1").arg(cname);
Chris@1380 823 editText = tr("click then drag to adjust, ctrl+click to reset");
Chris@1380 824
Chris@1380 825 } else if (wname == "playParamButton") {
Chris@1380 826
Chris@1480 827 auto params = m_container->getPlayParameters();
Chris@1180 828 if (params) {
Chris@1380 829 help = tr("Change sound used for playback (currently \"%1\")")
Chris@1380 830 .arg(params->getPlayClipId());
Chris@1180 831 }
Chris@1380 832
Chris@1380 833 } else if (dial) {
Chris@1380 834
Chris@908 835 double mv = dial->mappedValue();
Chris@218 836 QString unit = "";
Chris@218 837 if (dial->rangeMapper()) unit = dial->rangeMapper()->getUnit();
Chris@218 838 if (unit != "") {
Chris@218 839 extraText = tr(" (current value: %1%2)").arg(mv).arg(unit);
Chris@218 840 } else {
Chris@218 841 extraText = tr(" (current value: %1)").arg(mv);
Chris@218 842 }
Chris@1380 843 editText = tr("drag up/down to adjust, ctrl+click to reset");
Chris@1380 844
Chris@1380 845 } else if (w == m_showButton) {
Chris@1380 846 help = tr("Toggle Visibility of %1").arg(cname);
Chris@1380 847
Chris@1380 848 } else if (w == m_playButton) {
Chris@1380 849 help = tr("Toggle Playback of %1").arg(cname);
Chris@1380 850
Chris@218 851 }
Chris@218 852
Chris@1380 853 if (help == "" && wname != "") {
Chris@1380 854
Chris@1380 855 if (qobject_cast<QAbstractButton *>(w)) {
Chris@1380 856 mainText = tr("Toggle %1 property of %2")
Chris@1380 857 .arg(propertyLabel).arg(cname);
Chris@1380 858
Chris@1380 859 } else {
Chris@1380 860
Chris@1380 861 // Last param empty for historical reasons, to avoid
Chris@1380 862 // changing tr() string
Chris@1380 863 mainText = tr("Adjust %1 property of %2%3")
Chris@1380 864 .arg(propertyLabel).arg(cname).arg("");
Chris@1380 865 }
Chris@1377 866 }
Chris@1380 867
Chris@1380 868 if (help == "") {
Chris@1380 869 if (mainText != "") {
Chris@1380 870 if (editText != "") {
Chris@1380 871 help = tr("%1%2: %3")
Chris@1380 872 .arg(mainText).arg(extraText).arg(editText);
Chris@1380 873 } else {
Chris@1380 874 help = tr("%1%2")
Chris@1380 875 .arg(mainText).arg(extraText);
Chris@1380 876 }
Chris@1380 877 }
Chris@1380 878 }
Chris@1380 879
Chris@1380 880 if (help != "") {
Chris@1380 881 emit contextHelpChanged(help);
Chris@189 882 }
Chris@189 883 }
Chris@189 884
Chris@189 885 void
Chris@189 886 PropertyBox::mouseLeftWidget()
Chris@189 887 {
Chris@218 888 if (!(QApplication::mouseButtons() & Qt::LeftButton)) {
Chris@218 889 emit contextHelpChanged("");
Chris@218 890 }
Chris@189 891 }
Chris@189 892
Chris@64 893