annotate widgets/PropertyBox.cpp @ 1619:36634b427d61

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