comparison widgets/PropertyBox.cpp @ 1324:13d9b422f7fe zoom

Merge from default branch
author Chris Cannam
date Mon, 17 Sep 2018 13:51:31 +0100
parents 13e17e61f898
children 47f35694d603 d18ca558049e
comparison
equal deleted inserted replaced
1183:57d192e26331 1324:13d9b422f7fe
18 18
19 #include "base/PropertyContainer.h" 19 #include "base/PropertyContainer.h"
20 #include "base/PlayParameters.h" 20 #include "base/PlayParameters.h"
21 #include "base/PlayParameterRepository.h" 21 #include "base/PlayParameterRepository.h"
22 #include "layer/Layer.h" 22 #include "layer/Layer.h"
23 #include "layer/ColourDatabase.h"
24 #include "base/UnitDatabase.h" 23 #include "base/UnitDatabase.h"
25 #include "base/RangeMapper.h" 24 #include "base/RangeMapper.h"
26 25
27 #include "AudioDial.h" 26 #include "AudioDial.h"
28 #include "LEDButton.h" 27 #include "LEDButton.h"
29 #include "IconLoader.h" 28 #include "IconLoader.h"
29 #include "LevelPanWidget.h"
30 #include "LevelPanToolButton.h"
31 #include "WidgetScale.h"
30 32
31 #include "NotifyingCheckBox.h" 33 #include "NotifyingCheckBox.h"
32 #include "NotifyingComboBox.h" 34 #include "NotifyingComboBox.h"
33 #include "NotifyingPushButton.h" 35 #include "NotifyingPushButton.h"
34 #include "ColourNameDialog.h" 36 #include "NotifyingToolButton.h"
37 #include "ColourComboBox.h"
38 #include "ColourMapComboBox.h"
35 39
36 #include <QGridLayout> 40 #include <QGridLayout>
37 #include <QHBoxLayout> 41 #include <QHBoxLayout>
38 #include <QVBoxLayout> 42 #include <QVBoxLayout>
39 #include <QPushButton> 43 #include <QPushButton>
44 #include <QToolButton>
40 #include <QLabel> 45 #include <QLabel>
41 #include <QFrame> 46 #include <QFrame>
42 #include <QApplication> 47 #include <QApplication>
43 #include <QColorDialog> 48 #include <QColorDialog>
44 #include <QInputDialog> 49 #include <QInputDialog>
55 m_showButton(0), 60 m_showButton(0),
56 m_playButton(0) 61 m_playButton(0)
57 { 62 {
58 #ifdef DEBUG_PROPERTY_BOX 63 #ifdef DEBUG_PROPERTY_BOX
59 cerr << "PropertyBox[" << this << "(\"" << 64 cerr << "PropertyBox[" << this << "(\"" <<
60 container->getPropertyContainerName() << "\" at " << container << ")]::PropertyBox" << endl; 65 container->getPropertyContainerName() << "\" at " << container << ")]::PropertyBox" << endl;
61 #endif 66 #endif
62 67
63 m_mainBox = new QVBoxLayout; 68 m_mainBox = new QVBoxLayout;
64 setLayout(m_mainBox); 69 setLayout(m_mainBox);
65 70
91 blockSignals(true); 96 blockSignals(true);
92 97
93 size_t i; 98 size_t i;
94 99
95 for (i = 0; i < properties.size(); ++i) { 100 for (i = 0; i < properties.size(); ++i) {
96 updatePropertyEditor(properties[i]); 101 updatePropertyEditor(properties[i]);
97 } 102 }
98 103
99 blockSignals(false); 104 blockSignals(false);
100 105
101 m_layout->setRowStretch(m_layout->rowCount(), 10); 106 m_layout->setRowStretch(m_layout->rowCount(), 10);
102 107
103 connect(UnitDatabase::getInstance(), SIGNAL(unitDatabaseChanged()), 108 connect(UnitDatabase::getInstance(), SIGNAL(unitDatabaseChanged()),
104 this, SLOT(unitDatabaseChanged())); 109 this, SLOT(unitDatabaseChanged()));
105 110
106 connect(ColourDatabase::getInstance(), SIGNAL(colourDatabaseChanged()),
107 this, SLOT(colourDatabaseChanged()));
108
109 #ifdef DEBUG_PROPERTY_BOX 111 #ifdef DEBUG_PROPERTY_BOX
110 cerr << "PropertyBox[" << this << "]::PropertyBox returning" << endl; 112 cerr << "PropertyBox[" << this << "]::PropertyBox returning" << endl;
111 #endif 113 #endif
112 } 114 }
113 115
124 #ifdef DEBUG_PROPERTY_BOX 126 #ifdef DEBUG_PROPERTY_BOX
125 cerr << "PropertyBox[" << this << ":" << m_container << "]::populateViewPlayFrame" << endl; 127 cerr << "PropertyBox[" << this << ":" << m_container << "]::populateViewPlayFrame" << endl;
126 #endif 128 #endif
127 129
128 if (m_viewPlayFrame) { 130 if (m_viewPlayFrame) {
129 delete m_viewPlayFrame; 131 delete m_viewPlayFrame;
130 m_viewPlayFrame = 0; 132 m_viewPlayFrame = 0;
131 } 133 }
132 134
133 if (!m_container) return; 135 if (!m_container) return;
134 136
135 Layer *layer = dynamic_cast<Layer *>(m_container); 137 Layer *layer = dynamic_cast<Layer *>(m_container);
136 if (layer) { 138 if (layer) {
137 disconnect(layer, SIGNAL(modelReplaced()), 139 disconnect(layer, SIGNAL(modelReplaced()),
138 this, SLOT(populateViewPlayFrame())); 140 this, SLOT(populateViewPlayFrame()));
139 connect(layer, SIGNAL(modelReplaced()), 141 connect(layer, SIGNAL(modelReplaced()),
140 this, SLOT(populateViewPlayFrame())); 142 this, SLOT(populateViewPlayFrame()));
141 } 143 }
142 144
143 PlayParameters *params = m_container->getPlayParameters(); 145 PlayParameters *params = m_container->getPlayParameters();
144 if (!params && !layer) return; 146 if (!params && !layer) return;
145 147
146 m_viewPlayFrame = new QFrame; 148 m_viewPlayFrame = new QFrame;
147 m_viewPlayFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); 149 m_viewPlayFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
148 m_mainBox->addWidget(m_viewPlayFrame); 150 m_mainBox->addWidget(m_viewPlayFrame);
149 151
150 QHBoxLayout *layout = new QHBoxLayout; 152 QGridLayout *layout = new QGridLayout;
151 m_viewPlayFrame->setLayout(layout); 153 m_viewPlayFrame->setLayout(layout);
152 154
153 layout->setMargin(layout->margin() / 2); 155 layout->setMargin(layout->margin() / 2);
154 156
155 #ifdef DEBUG_PROPERTY_BOX 157 #ifdef DEBUG_PROPERTY_BOX
156 SVDEBUG << "PropertyBox::populateViewPlayFrame: container " << m_container << " (name " << m_container->getPropertyContainerName() << ") params " << params << endl; 158 SVDEBUG << "PropertyBox::populateViewPlayFrame: container " << m_container << " (name " << m_container->getPropertyContainerName() << ") params " << params << endl;
157 #endif 159 #endif
158 160
161 QSize buttonSize = WidgetScale::scaleQSize(QSize(26, 26));
162 int col = 0;
163
164 if (params) {
165
166 m_playButton = new NotifyingToolButton;
167 m_playButton->setCheckable(true);
168 m_playButton->setIcon(IconLoader().load("speaker"));
169 m_playButton->setToolTip(tr("Click to toggle playback"));
170 m_playButton->setChecked(!params->isPlayMuted());
171 m_playButton->setFixedSize(buttonSize);
172 connect(m_playButton, SIGNAL(toggled(bool)),
173 this, SLOT(playAudibleButtonChanged(bool)));
174 connect(m_playButton, SIGNAL(mouseEntered()),
175 this, SLOT(mouseEnteredWidget()));
176 connect(m_playButton, SIGNAL(mouseLeft()),
177 this, SLOT(mouseLeftWidget()));
178 connect(params, SIGNAL(playAudibleChanged(bool)),
179 this, SLOT(playAudibleChanged(bool)));
180
181 LevelPanToolButton *levelPan = new LevelPanToolButton;
182 levelPan->setFixedSize(buttonSize);
183 levelPan->setImageSize((buttonSize.height() * 3) / 4);
184 layout->addWidget(levelPan, 0, col++, Qt::AlignCenter);
185 connect(levelPan, SIGNAL(levelChanged(float)),
186 this, SLOT(playGainControlChanged(float)));
187 connect(levelPan, SIGNAL(panChanged(float)),
188 this, SLOT(playPanControlChanged(float)));
189 connect(params, SIGNAL(playGainChanged(float)),
190 levelPan, SLOT(setLevel(float)));
191 connect(params, SIGNAL(playPanChanged(float)),
192 levelPan, SLOT(setPan(float)));
193 connect(levelPan, SIGNAL(mouseEntered()),
194 this, SLOT(mouseEnteredWidget()));
195 connect(levelPan, SIGNAL(mouseLeft()),
196 this, SLOT(mouseLeftWidget()));
197
198 layout->addWidget(m_playButton, 0, col++, Qt::AlignCenter);
199
200 if (params->getPlayClipId() != "") {
201 NotifyingToolButton *playParamButton = new NotifyingToolButton;
202 playParamButton->setObjectName("playParamButton");
203 playParamButton->setIcon(IconLoader().load("faders"));
204 playParamButton->setFixedSize(buttonSize);
205 layout->addWidget(playParamButton, 0, col++, Qt::AlignCenter);
206 connect(playParamButton, SIGNAL(clicked()),
207 this, SLOT(editPlayParameters()));
208 connect(playParamButton, SIGNAL(mouseEntered()),
209 this, SLOT(mouseEnteredWidget()));
210 connect(playParamButton, SIGNAL(mouseLeft()),
211 this, SLOT(mouseLeftWidget()));
212 }
213 }
214
215 layout->setColumnStretch(col++, 10);
216
159 if (layer) { 217 if (layer) {
160 QLabel *showLabel = new QLabel(tr("Show")); 218
161 layout->addWidget(showLabel); 219 QLabel *showLabel = new QLabel(tr("Show"));
162 layout->setAlignment(showLabel, Qt::AlignVCenter); 220 layout->addWidget(showLabel, 0, col++, Qt::AlignVCenter | Qt::AlignRight);
163 221
164 m_showButton = new LEDButton(Qt::blue); 222 m_showButton = new LEDButton(palette().highlight().color());
165 layout->addWidget(m_showButton); 223 layout->addWidget(m_showButton, 0, col++, Qt::AlignVCenter | Qt::AlignLeft);
166 connect(m_showButton, SIGNAL(stateChanged(bool)), 224 connect(m_showButton, SIGNAL(stateChanged(bool)),
167 this, SIGNAL(showLayer(bool))); 225 this, SIGNAL(showLayer(bool)));
168 connect(m_showButton, SIGNAL(mouseEntered()), 226 connect(m_showButton, SIGNAL(mouseEntered()),
169 this, SLOT(mouseEnteredWidget())); 227 this, SLOT(mouseEnteredWidget()));
170 connect(m_showButton, SIGNAL(mouseLeft()), 228 connect(m_showButton, SIGNAL(mouseLeft()),
171 this, SLOT(mouseLeftWidget())); 229 this, SLOT(mouseLeftWidget()));
172 layout->setAlignment(m_showButton, Qt::AlignVCenter);
173 }
174
175 if (params) {
176
177 QLabel *playLabel = new QLabel(tr("Play"));
178 layout->addWidget(playLabel);
179 layout->setAlignment(playLabel, Qt::AlignVCenter);
180
181 m_playButton = new LEDButton(Qt::darkGreen);
182 m_playButton->setState(!params->isPlayMuted());
183 layout->addWidget(m_playButton);
184 connect(m_playButton, SIGNAL(stateChanged(bool)),
185 this, SLOT(playAudibleButtonChanged(bool)));
186 connect(m_playButton, SIGNAL(mouseEntered()),
187 this, SLOT(mouseEnteredWidget()));
188 connect(m_playButton, SIGNAL(mouseLeft()),
189 this, SLOT(mouseLeftWidget()));
190 connect(params, SIGNAL(playAudibleChanged(bool)),
191 this, SLOT(playAudibleChanged(bool)));
192 layout->setAlignment(m_playButton, Qt::AlignVCenter);
193
194 layout->insertStretch(-1, 10);
195
196 if (params->getPlayClipId() != "") {
197 QPushButton *playParamButton =
198 new QPushButton(QIcon(":icons/faders.png"), "");
199 playParamButton->setFixedWidth(24);
200 playParamButton->setFixedHeight(24);
201 layout->addWidget(playParamButton);
202 connect(playParamButton, SIGNAL(clicked()),
203 this, SLOT(editPlayParameters()));
204 }
205
206 AudioDial *gainDial = new AudioDial;
207 layout->addWidget(gainDial);
208 gainDial->setMeterColor(Qt::darkRed);
209 gainDial->setMinimum(-50);
210 gainDial->setMaximum(50);
211 gainDial->setPageStep(1);
212 gainDial->setFixedWidth(24);
213 gainDial->setFixedHeight(24);
214 gainDial->setNotchesVisible(false);
215 gainDial->setObjectName(tr("Playback Gain"));
216 gainDial->setRangeMapper(new LinearRangeMapper
217 (-50, 50, -25, 25, tr("dB")));
218 gainDial->setDefaultValue(0);
219 gainDial->setShowToolTip(true);
220 connect(gainDial, SIGNAL(valueChanged(int)),
221 this, SLOT(playGainDialChanged(int)));
222 connect(params, SIGNAL(playGainChanged(float)),
223 this, SLOT(playGainChanged(float)));
224 connect(this, SIGNAL(changePlayGainDial(int)),
225 gainDial, SLOT(setValue(int)));
226 connect(gainDial, SIGNAL(mouseEntered()),
227 this, SLOT(mouseEnteredWidget()));
228 connect(gainDial, SIGNAL(mouseLeft()),
229 this, SLOT(mouseLeftWidget()));
230 playGainChanged(params->getPlayGain());
231 layout->setAlignment(gainDial, Qt::AlignVCenter);
232
233 AudioDial *panDial = new AudioDial;
234 layout->addWidget(panDial);
235 panDial->setMeterColor(Qt::darkGreen);
236 panDial->setMinimum(-50);
237 panDial->setMaximum(50);
238 panDial->setPageStep(1);
239 panDial->setFixedWidth(24);
240 panDial->setFixedHeight(24);
241 panDial->setNotchesVisible(false);
242 panDial->setToolTip(tr("Playback Pan / Balance"));
243 panDial->setDefaultValue(0);
244 panDial->setObjectName(tr("Playback Pan / Balance"));
245 panDial->setShowToolTip(true);
246 connect(panDial, SIGNAL(valueChanged(int)),
247 this, SLOT(playPanDialChanged(int)));
248 connect(params, SIGNAL(playPanChanged(float)),
249 this, SLOT(playPanChanged(float)));
250 connect(this, SIGNAL(changePlayPanDial(int)),
251 panDial, SLOT(setValue(int)));
252 connect(panDial, SIGNAL(mouseEntered()),
253 this, SLOT(mouseEnteredWidget()));
254 connect(panDial, SIGNAL(mouseLeft()),
255 this, SLOT(mouseLeftWidget()));
256 playPanChanged(params->getPlayPan());
257 layout->setAlignment(panDial, Qt::AlignVCenter);
258
259 } else {
260
261 layout->insertStretch(-1, 10);
262 } 230 }
263 } 231 }
264 232
265 void 233 void
266 PropertyBox::updatePropertyEditor(PropertyContainer::PropertyName name, 234 PropertyBox::updatePropertyEditor(PropertyContainer::PropertyName name,
271 239
272 int min = 0, max = 0, value = 0, deflt = 0; 240 int min = 0, max = 0, value = 0, deflt = 0;
273 value = m_container->getPropertyRangeAndValue(name, &min, &max, &deflt); 241 value = m_container->getPropertyRangeAndValue(name, &min, &max, &deflt);
274 242
275 bool have = (m_propertyControllers.find(name) != 243 bool have = (m_propertyControllers.find(name) !=
276 m_propertyControllers.end()); 244 m_propertyControllers.end());
277 245
278 QString groupName = m_container->getPropertyGroupName(name); 246 QString groupName = m_container->getPropertyGroupName(name);
279 QString propertyLabel = m_container->getPropertyLabel(name); 247 QString propertyLabel = m_container->getPropertyLabel(name);
280 QString iconName = m_container->getPropertyIconName(name); 248 QString iconName = m_container->getPropertyIconName(name);
281 249
282 #ifdef DEBUG_PROPERTY_BOX 250 #ifdef DEBUG_PROPERTY_BOX
283 cerr << "PropertyBox[" << this 251 cerr << "PropertyBox[" << this
284 << "(\"" << m_container->getPropertyContainerName() 252 << "(\"" << m_container->getPropertyContainerName()
285 << "\")]"; 253 << "\")]";
286 cerr << "::updatePropertyEditor(\"" << name << "\"):"; 254 cerr << "::updatePropertyEditor(\"" << name << "\", "
287 cerr << " value " << value << ", have " << have << ", group \"" 255 << rangeChanged << "):";
288 << groupName << "\"" << endl; 256 cerr << " type " << type << ", value " << value
289 #endif 257 << ", have " << have << ", group \"" << groupName << "\"" << endl;
290 258 #endif
291 bool inGroup = (groupName != QString()); 259
292 260 QString groupLabel = groupName;
261 if (groupName == QString()) {
262 groupName = "ungrouped: " + name; // not tr(), this is internal id
263 groupLabel = propertyLabel;
264 }
265
293 if (!have) { 266 if (!have) {
294 if (inGroup) { 267 if (m_groupLayouts.find(groupName) == m_groupLayouts.end()) {
295 if (m_groupLayouts.find(groupName) == m_groupLayouts.end()) { 268 QWidget *labelWidget = new QLabel(groupLabel, m_mainWidget);
296 #ifdef DEBUG_PROPERTY_BOX 269 m_layout->addWidget(labelWidget, row, 0);
297 cerr << "PropertyBox: adding label \"" << groupName << "\" and frame for group for \"" << name << "\"" << endl; 270 QWidget *frame = new QWidget(m_mainWidget);
298 #endif 271 frame->setMinimumSize(WidgetScale::scaleQSize(QSize(1, 24)));
299 m_layout->addWidget(new QLabel(groupName, m_mainWidget), row, 0); 272 m_groupLayouts[groupName] = new QGridLayout;
300 QFrame *frame = new QFrame(m_mainWidget); 273 #ifdef Q_OS_MAC
301 m_layout->addWidget(frame, row, 1, 1, 2); 274 // Seems to be plenty of whitespace already
302 m_groupLayouts[groupName] = new QGridLayout; 275 m_groupLayouts[groupName]->setContentsMargins(0, 0, 0, 0);
303 m_groupLayouts[groupName]->setMargin(0); 276 #else
304 frame->setLayout(m_groupLayouts[groupName]); 277 // Need a bit of padding on the left
305 } 278 m_groupLayouts[groupName]->setContentsMargins
306 } else { 279 (WidgetScale::scalePixelSize(10), 0, 0, 0);
307 #ifdef DEBUG_PROPERTY_BOX 280 #endif
308 cerr << "PropertyBox: adding label \"" << propertyLabel << "\"" << endl; 281 frame->setLayout(m_groupLayouts[groupName]);
309 #endif 282 m_layout->addWidget(frame, row, 1, 1, 2);
310 m_layout->addWidget(new QLabel(propertyLabel, m_mainWidget), row, 0); 283 m_layout->setColumnStretch(1, 10);
311 } 284 }
312 } 285 }
313 286
287 QGridLayout *groupLayout = m_groupLayouts[groupName];
288
289 #ifdef DEBUG_PROPERTY_BOX
290 cerr << "groupName becomes \"" << groupName << "\", groupLabel = \""
291 << groupLabel << "\", groupLayout = " << groupLayout << endl;
292 #endif
293
294 assert(groupLayout);
295
296 QWidget *existing = m_propertyControllers[name];
297
314 switch (type) { 298 switch (type) {
315 299
316 case PropertyContainer::ToggleProperty: 300 case PropertyContainer::ToggleProperty:
317 { 301 {
318 QAbstractButton *button = 0; 302 QAbstractButton *button;
319 303
320 if (have) { 304 if (!(button = qobject_cast<QAbstractButton *>(existing))) {
321 button = dynamic_cast<QAbstractButton *>(m_propertyControllers[name]);
322 assert(button);
323 } else {
324 #ifdef DEBUG_PROPERTY_BOX 305 #ifdef DEBUG_PROPERTY_BOX
325 cerr << "PropertyBox: creating new checkbox" << endl; 306 cerr << "PropertyBox: creating new checkbox" << endl;
326 #endif 307 #endif
327 if (iconName != "") { 308 if (iconName != "") {
309 #ifdef Q_OS_MAC
310 button = new NotifyingToolButton();
311 #else
328 button = new NotifyingPushButton(); 312 button = new NotifyingPushButton();
313 #endif
329 button->setCheckable(true); 314 button->setCheckable(true);
330 QIcon icon(IconLoader().load(iconName)); 315 QIcon icon(IconLoader().load(iconName));
331 button->setIcon(icon); 316 button->setIcon(icon);
332 button->setObjectName(name); 317 button->setObjectName(name);
333 button->setFixedSize(QSize(18, 18)); 318 button->setFixedSize(WidgetScale::scaleQSize(QSize(18, 18)));
334 } else { 319 } else {
335 button = new NotifyingCheckBox(); 320 button = new NotifyingCheckBox();
336 button->setObjectName(name); 321 button->setObjectName(name);
337 } 322 }
338 connect(button, SIGNAL(toggled(bool)), 323 connect(button, SIGNAL(toggled(bool)),
339 this, SLOT(propertyControllerChanged(bool))); 324 this, SLOT(propertyControllerChanged(bool)));
340 connect(button, SIGNAL(mouseEntered()), 325 connect(button, SIGNAL(mouseEntered()),
341 this, SLOT(mouseEnteredWidget())); 326 this, SLOT(mouseEnteredWidget()));
342 connect(button, SIGNAL(mouseLeft()), 327 connect(button, SIGNAL(mouseLeft()),
343 this, SLOT(mouseLeftWidget())); 328 this, SLOT(mouseLeftWidget()));
344 if (inGroup) { 329 button->setToolTip(propertyLabel);
345 button->setToolTip(propertyLabel); 330
346 m_groupLayouts[groupName]->addWidget 331 if (existing) {
347 (button, 0, m_groupLayouts[groupName]->columnCount()); 332 groupLayout->replaceWidget(existing, button);
348 } else { 333 delete existing;
349 m_layout->addWidget(button, row, 1, 1, 2); 334 } else {
350 } 335 groupLayout->addWidget(button, 0, groupLayout->columnCount());
351 m_propertyControllers[name] = button; 336 }
352 } 337
338 m_propertyControllers[name] = button;
339 }
353 340
354 if (button->isChecked() != (value > 0)) { 341 if (button->isChecked() != (value > 0)) {
355 button->blockSignals(true); 342 button->blockSignals(true);
356 button->setChecked(value > 0); 343 button->setChecked(value > 0);
357 button->blockSignals(false); 344 button->blockSignals(false);
358 } 345 }
359 break; 346 break;
360 } 347 }
361 348
362 case PropertyContainer::RangeProperty: 349 case PropertyContainer::RangeProperty:
363 { 350 {
364 AudioDial *dial; 351 AudioDial *dial;
365 352
366 if (have) { 353 if ((dial = qobject_cast<AudioDial *>(existing))) {
367 dial = dynamic_cast<AudioDial *>(m_propertyControllers[name]);
368 assert(dial);
369 if (rangeChanged) { 354 if (rangeChanged) {
370 dial->blockSignals(true); 355 dial->blockSignals(true);
371 dial->setMinimum(min); 356 dial->setMinimum(min);
372 dial->setMaximum(max); 357 dial->setMaximum(max);
373 dial->setRangeMapper(m_container->getNewPropertyRangeMapper(name)); 358 dial->setRangeMapper(m_container->getNewPropertyRangeMapper(name));
374 dial->blockSignals(false); 359 dial->blockSignals(false);
375 } 360 }
376 361 } else {
377 } else {
378 #ifdef DEBUG_PROPERTY_BOX 362 #ifdef DEBUG_PROPERTY_BOX
379 cerr << "PropertyBox: creating new dial" << endl; 363 cerr << "PropertyBox: creating new dial" << endl;
380 #endif 364 #endif
381 dial = new AudioDial(); 365 dial = new AudioDial();
382 dial->setObjectName(name); 366 dial->setObjectName(name);
383 dial->setMinimum(min); 367 dial->setMinimum(min);
384 dial->setMaximum(max); 368 dial->setMaximum(max);
385 dial->setPageStep(1); 369 dial->setPageStep(1);
386 dial->setNotchesVisible((max - min) <= 12); 370 dial->setNotchesVisible((max - min) <= 12);
387 // important to set the range mapper before the default, 371 // important to set the range mapper before the default,
388 // because the range mapper is used to map the default 372 // because the range mapper is used to map the default
389 dial->setRangeMapper(m_container->getNewPropertyRangeMapper(name)); 373 dial->setRangeMapper(m_container->getNewPropertyRangeMapper(name));
390 dial->setDefaultValue(deflt); 374 dial->setDefaultValue(deflt);
391 dial->setShowToolTip(true); 375 dial->setShowToolTip(true);
392 connect(dial, SIGNAL(valueChanged(int)), 376 connect(dial, SIGNAL(valueChanged(int)),
393 this, SLOT(propertyControllerChanged(int))); 377 this, SLOT(propertyControllerChanged(int)));
394 connect(dial, SIGNAL(mouseEntered()), 378 connect(dial, SIGNAL(mouseEntered()),
395 this, SLOT(mouseEnteredWidget())); 379 this, SLOT(mouseEnteredWidget()));
396 connect(dial, SIGNAL(mouseLeft()), 380 connect(dial, SIGNAL(mouseLeft()),
397 this, SLOT(mouseLeftWidget())); 381 this, SLOT(mouseLeftWidget()));
398 382
399 if (inGroup) { 383 dial->setFixedWidth(WidgetScale::scalePixelSize(24));
400 dial->setFixedWidth(24); 384 dial->setFixedHeight(WidgetScale::scalePixelSize(24));
401 dial->setFixedHeight(24); 385
402 m_groupLayouts[groupName]->addWidget 386 if (existing) {
403 (dial, 0, m_groupLayouts[groupName]->columnCount()); 387 groupLayout->replaceWidget(existing, dial);
404 } else { 388 delete existing;
405 dial->setFixedWidth(32); 389 } else {
406 dial->setFixedHeight(32); 390 groupLayout->addWidget(dial, 0, groupLayout->columnCount());
407 m_layout->addWidget(dial, row, 1); 391 }
408 QLabel *label = new QLabel(m_mainWidget); 392
409 connect(dial, SIGNAL(valueChanged(int)), 393 m_propertyControllers[name] = dial;
410 label, SLOT(setNum(int))); 394 }
411 label->setNum(value); 395
412 m_layout->addWidget(label, row, 2); 396 if (dial->value() != value) {
413 } 397 dial->blockSignals(true);
414 398 dial->setValue(value);
415 m_propertyControllers[name] = dial; 399 dial->blockSignals(false);
416 } 400 }
417 401 break;
418 if (dial->value() != value) { 402 }
419 dial->blockSignals(true); 403
420 dial->setValue(value); 404 case PropertyContainer::ColourProperty:
421 dial->blockSignals(false); 405 {
422 } 406 ColourComboBox *cb;
423 break; 407
424 } 408 if (!(cb = qobject_cast<ColourComboBox *>(existing))) {
409
410 #ifdef DEBUG_PROPERTY_BOX
411 cerr << "PropertyBox: creating new colour combobox" << endl;
412 #endif
413 cb = new ColourComboBox(true);
414 cb->setObjectName(name);
415
416 connect(cb, SIGNAL(colourChanged(int)),
417 this, SLOT(propertyControllerChanged(int)));
418 connect(cb, SIGNAL(mouseEntered()),
419 this, SLOT(mouseEnteredWidget()));
420 connect(cb, SIGNAL(mouseLeft()),
421 this, SLOT(mouseLeftWidget()));
422
423 cb->setToolTip(propertyLabel);
424
425 if (existing) {
426 groupLayout->replaceWidget(existing, cb);
427 delete existing;
428 } else {
429 groupLayout->addWidget(cb, 0, groupLayout->columnCount());
430 }
431
432 m_propertyControllers[name] = cb;
433 }
434
435 if (cb->currentIndex() != value) {
436 cb->blockSignals(true);
437 cb->setCurrentIndex(value);
438 cb->blockSignals(false);
439 }
440
441 break;
442 }
443
444 case PropertyContainer::ColourMapProperty:
445 {
446 ColourMapComboBox *cb;
447
448 if (!(cb = qobject_cast<ColourMapComboBox *>(existing))) {
449 #ifdef DEBUG_PROPERTY_BOX
450 cerr << "PropertyBox: creating new colourmap combobox" << endl;
451 #endif
452 cb = new ColourMapComboBox(false);
453 cb->setObjectName(name);
454
455 connect(cb, SIGNAL(colourMapChanged(int)),
456 this, SLOT(propertyControllerChanged(int)));
457 connect(cb, SIGNAL(mouseEntered()),
458 this, SLOT(mouseEnteredWidget()));
459 connect(cb, SIGNAL(mouseLeft()),
460 this, SLOT(mouseLeftWidget()));
461
462 cb->setToolTip(propertyLabel);
463
464 if (existing) {
465 groupLayout->replaceWidget(existing, cb);
466 delete existing;
467 } else {
468 groupLayout->addWidget(cb, 0, groupLayout->columnCount());
469 }
470
471 m_propertyControllers[name] = cb;
472 }
473
474 if (cb->currentIndex() != value) {
475 cb->blockSignals(true);
476 cb->setCurrentIndex(value);
477 cb->blockSignals(false);
478 }
479
480 break;
481 }
425 482
426 case PropertyContainer::ValueProperty: 483 case PropertyContainer::ValueProperty:
427 case PropertyContainer::UnitsProperty: 484 case PropertyContainer::UnitsProperty:
428 case PropertyContainer::ColourProperty:
429 { 485 {
430 NotifyingComboBox *cb; 486 NotifyingComboBox *cb;
431 487
432 if (have) { 488 if (!(cb = qobject_cast<NotifyingComboBox *>(existing))) {
433 cb = dynamic_cast<NotifyingComboBox *>(m_propertyControllers[name]);
434 assert(cb);
435 } else {
436 #ifdef DEBUG_PROPERTY_BOX 489 #ifdef DEBUG_PROPERTY_BOX
437 cerr << "PropertyBox: creating new combobox" << endl; 490 cerr << "PropertyBox: creating new combobox" << endl;
438 #endif 491 #endif
439 492 cb = new NotifyingComboBox();
440 cb = new NotifyingComboBox(); 493 cb->setObjectName(name);
441 cb->setObjectName(name);
442 cb->setDuplicatesEnabled(false); 494 cb->setDuplicatesEnabled(false);
443 } 495 }
444 496
445 if (!have || rangeChanged) { 497 if (!have || rangeChanged) {
446 498
461 } else { 513 } else {
462 cb->addItem(label); 514 cb->addItem(label);
463 } 515 }
464 } 516 }
465 517
466 } else if (type == PropertyContainer::UnitsProperty) { 518 } else { // PropertyContainer::UnitsProperty
467 519
468 QStringList units = UnitDatabase::getInstance()->getKnownUnits(); 520 QStringList units = UnitDatabase::getInstance()->getKnownUnits();
469 for (int i = 0; i < units.size(); ++i) { 521 for (int i = 0; i < units.size(); ++i) {
470 cb->addItem(units[i]); 522 cb->addItem(units[i]);
471 } 523 }
472 524
473 cb->setEditable(true); 525 cb->setEditable(true);
474
475 } else { // ColourProperty
476
477 //!!! should be a proper colour combobox class that
478 // manages its own Add New Colour entry...
479
480 int size = (QFontMetrics(QFont()).height() * 2) / 3;
481 if (size < 12) size = 12;
482
483 ColourDatabase *db = ColourDatabase::getInstance();
484 for (int i = 0; i < db->getColourCount(); ++i) {
485 QString name = db->getColourName(i);
486 cb->addItem(db->getExamplePixmap(i, QSize(size, size)), name);
487 }
488 cb->addItem(tr("Add New Colour..."));
489 }
490
491 cb->blockSignals(false);
492 if (cb->count() < 20 && cb->count() > cb->maxVisibleItems()) {
493 cb->setMaxVisibleItems(cb->count());
494 } 526 }
495 } 527 }
496 528
497 if (!have) { 529 if (!have) {
498 connect(cb, SIGNAL(activated(int)), 530 connect(cb, SIGNAL(activated(int)),
499 this, SLOT(propertyControllerChanged(int))); 531 this, SLOT(propertyControllerChanged(int)));
500 connect(cb, SIGNAL(mouseEntered()), 532 connect(cb, SIGNAL(mouseEntered()),
501 this, SLOT(mouseEnteredWidget())); 533 this, SLOT(mouseEnteredWidget()));
502 connect(cb, SIGNAL(mouseLeft()), 534 connect(cb, SIGNAL(mouseLeft()),
503 this, SLOT(mouseLeftWidget())); 535 this, SLOT(mouseLeftWidget()));
504 536
505 if (inGroup) { 537 cb->setToolTip(propertyLabel);
506 cb->setToolTip(propertyLabel); 538 groupLayout->addWidget(cb, 0, groupLayout->columnCount());
507 m_groupLayouts[groupName]->addWidget 539 m_propertyControllers[name] = cb;
508 (cb, 0, m_groupLayouts[groupName]->columnCount()); 540 } else if (existing != cb) {
509 } else { 541 groupLayout->replaceWidget(existing, cb);
510 m_layout->addWidget(cb, row, 1, 1, 2); 542 delete existing;
511 } 543 }
512 m_propertyControllers[name] = cb;
513 }
514 544
515 cb->blockSignals(true); 545 cb->blockSignals(true);
516 if (type == PropertyContainer::ValueProperty || 546 if (type == PropertyContainer::ValueProperty) {
517 type == PropertyContainer::ColourProperty) {
518 if (cb->currentIndex() != value) { 547 if (cb->currentIndex() != value) {
519 cb->setCurrentIndex(value); 548 cb->setCurrentIndex(value);
520 } 549 }
521 } else { 550 } else {
522 QString unit = UnitDatabase::getInstance()->getUnitById(value); 551 QString unit = UnitDatabase::getInstance()->getUnitById(value);
529 } 558 }
530 } 559 }
531 } 560 }
532 cb->blockSignals(false); 561 cb->blockSignals(false);
533 562
534 #ifdef Q_OS_MAC 563 break;
535 // Crashes on startup without this, for some reason; also
536 // prevents combo boxes from getting weirdly squished
537 // vertically
538 cb->setMinimumSize(QSize(10, cb->font().pixelSize() * 2));
539 #endif
540
541 break;
542 } 564 }
543 565
544 case PropertyContainer::InvalidProperty: 566 case PropertyContainer::InvalidProperty:
545 default: 567 default:
546 break; 568 break;
547 } 569 }
548 } 570 }
549 571
550 void 572 void
551 PropertyBox::propertyContainerPropertyChanged(PropertyContainer *pc) 573 PropertyBox::propertyContainerPropertyChanged(PropertyContainer *pc)
560 size_t i; 582 size_t i;
561 583
562 blockSignals(true); 584 blockSignals(true);
563 585
564 for (i = 0; i < properties.size(); ++i) { 586 for (i = 0; i < properties.size(); ++i) {
565 updatePropertyEditor(properties[i]); 587 updatePropertyEditor(properties[i]);
566 } 588 }
567 589
568 blockSignals(false); 590 blockSignals(false);
569 } 591 }
570 592
573 { 595 {
574 blockSignals(true); 596 blockSignals(true);
575 597
576 PropertyContainer::PropertyList properties = m_container->getProperties(); 598 PropertyContainer::PropertyList properties = m_container->getProperties();
577 for (size_t i = 0; i < properties.size(); ++i) { 599 for (size_t i = 0; i < properties.size(); ++i) {
578 updatePropertyEditor(properties[i], true); 600 updatePropertyEditor(properties[i], true);
579 } 601 }
580 602
581 blockSignals(false); 603 blockSignals(false);
582 } 604 }
583 605
603 625
604 blockSignals(false); 626 blockSignals(false);
605 } 627 }
606 628
607 void 629 void
608 PropertyBox::colourDatabaseChanged()
609 {
610 blockSignals(true);
611
612 PropertyContainer::PropertyList properties = m_container->getProperties();
613 for (size_t i = 0; i < properties.size(); ++i) {
614 if (m_container->getPropertyType(properties[i]) ==
615 PropertyContainer::ColourProperty) {
616 updatePropertyEditor(properties[i], true);
617 }
618 }
619
620 blockSignals(false);
621 }
622
623 void
624 PropertyBox::propertyControllerChanged(bool on) 630 PropertyBox::propertyControllerChanged(bool on)
625 { 631 {
626 propertyControllerChanged(on ? 1 : 0); 632 propertyControllerChanged(on ? 1 : 0);
627 } 633 }
628 634
631 { 637 {
632 QObject *obj = sender(); 638 QObject *obj = sender();
633 QString name = obj->objectName(); 639 QString name = obj->objectName();
634 640
635 #ifdef DEBUG_PROPERTY_BOX 641 #ifdef DEBUG_PROPERTY_BOX
636 SVDEBUG << "PropertyBox::propertyControllerChanged(" << name << ", " << value << ")" << endl; 642 SVDEBUG << "PropertyBox::propertyControllerChanged(" << name << ", " << value << ")" << endl;
637 #endif 643 #endif
638 644
639 PropertyContainer::PropertyType type = m_container->getPropertyType(name); 645 PropertyContainer::PropertyType type = m_container->getPropertyType(name);
640 646
641 Command *c = 0; 647 Command *c = 0;
642 648
643 if (type == PropertyContainer::UnitsProperty) { 649 if (type == PropertyContainer::UnitsProperty) {
644 650
645 NotifyingComboBox *cb = dynamic_cast<NotifyingComboBox *>(obj); 651 NotifyingComboBox *cb = qobject_cast<NotifyingComboBox *>(obj);
646 if (cb) { 652 if (cb) {
647 QString unit = cb->currentText(); 653 QString unit = cb->currentText();
648 c = m_container->getSetPropertyCommand 654 c = m_container->getSetPropertyCommand
649 (name, UnitDatabase::getInstance()->getUnitId(unit)); 655 (name, UnitDatabase::getInstance()->getUnitId(unit));
650 } 656 }
651 657
652 } else if (type == PropertyContainer::ColourProperty) { 658 } else if (type != PropertyContainer::InvalidProperty) {
653 659
654 if (value == int(ColourDatabase::getInstance()->getColourCount())) {
655 addNewColour();
656 if (value == int(ColourDatabase::getInstance()->getColourCount())) {
657 propertyContainerPropertyChanged(m_container);
658 return;
659 }
660 }
661 c = m_container->getSetPropertyCommand(name, value); 660 c = m_container->getSetPropertyCommand(name, value);
662
663 } else if (type != PropertyContainer::InvalidProperty) {
664
665 c = m_container->getSetPropertyCommand(name, value);
666 } 661 }
667 662
668 if (c) CommandHistory::getInstance()->addCommand(c, true, true); 663 if (c) CommandHistory::getInstance()->addCommand(c, true, true);
669 664
670 updateContextHelp(obj); 665 updateContextHelp(obj);
671 } 666 }
672 667
673 void 668 void
674 PropertyBox::addNewColour()
675 {
676 QColor newColour = QColorDialog::getColor();
677 if (!newColour.isValid()) return;
678
679 ColourNameDialog dialog(tr("Name New Colour"),
680 tr("Enter a name for the new colour:"),
681 newColour, newColour.name(), this);
682 dialog.showDarkBackgroundCheckbox(tr("Prefer black background for this colour"));
683 if (dialog.exec() == QDialog::Accepted) {
684 //!!! command
685 ColourDatabase *db = ColourDatabase::getInstance();
686 int index = db->addColour(newColour, dialog.getColourName());
687 db->setUseDarkBackground(index, dialog.isDarkBackgroundChecked());
688 }
689 }
690
691 void
692 PropertyBox::playAudibleChanged(bool audible) 669 PropertyBox::playAudibleChanged(bool audible)
693 { 670 {
694 m_playButton->setState(audible); 671 m_playButton->setChecked(audible);
695 } 672 }
696 673
697 void 674 void
698 PropertyBox::playAudibleButtonChanged(bool audible) 675 PropertyBox::playAudibleButtonChanged(bool audible)
699 { 676 {
705 new PlayParameterRepository::EditCommand(params); 682 new PlayParameterRepository::EditCommand(params);
706 command->setPlayAudible(audible); 683 command->setPlayAudible(audible);
707 CommandHistory::getInstance()->addCommand(command, true, true); 684 CommandHistory::getInstance()->addCommand(command, true, true);
708 } 685 }
709 } 686 }
710 687
711 void 688 void
712 PropertyBox::playGainChanged(float gain) 689 PropertyBox::playGainControlChanged(float gain)
713 {
714 int dialValue = int(lrint(log10(gain) * 20.0));
715 if (dialValue < -50) dialValue = -50;
716 if (dialValue > 50) dialValue = 50;
717 emit changePlayGainDial(dialValue);
718 }
719
720 void
721 PropertyBox::playGainDialChanged(int dialValue)
722 { 690 {
723 QObject *obj = sender(); 691 QObject *obj = sender();
724 692
725 PlayParameters *params = m_container->getPlayParameters(); 693 PlayParameters *params = m_container->getPlayParameters();
726 if (!params) return; 694 if (!params) return;
727
728 float gain = float(pow(10, float(dialValue) / 20.0));
729 695
730 if (params->getPlayGain() != gain) { 696 if (params->getPlayGain() != gain) {
731 PlayParameterRepository::EditCommand *command = 697 PlayParameterRepository::EditCommand *command =
732 new PlayParameterRepository::EditCommand(params); 698 new PlayParameterRepository::EditCommand(params);
733 command->setPlayGain(gain); 699 command->setPlayGain(gain);
734 CommandHistory::getInstance()->addCommand(command, true, true); 700 CommandHistory::getInstance()->addCommand(command, true, true);
735 } 701 }
736 702
737 updateContextHelp(obj); 703 updateContextHelp(obj);
738 } 704 }
739 705
740 void 706 void
741 PropertyBox::playPanChanged(float pan) 707 PropertyBox::playPanControlChanged(float pan)
742 {
743 int dialValue = int(lrint(pan * 50.0));
744 if (dialValue < -50) dialValue = -50;
745 if (dialValue > 50) dialValue = 50;
746 emit changePlayPanDial(dialValue);
747 }
748
749 void
750 PropertyBox::playPanDialChanged(int dialValue)
751 { 708 {
752 QObject *obj = sender(); 709 QObject *obj = sender();
753 710
754 PlayParameters *params = m_container->getPlayParameters(); 711 PlayParameters *params = m_container->getPlayParameters();
755 if (!params) return; 712 if (!params) return;
756
757 float pan = float(dialValue) / 50.f;
758 if (pan < -1.f) pan = -1.f;
759 if (pan > 1.f) pan = 1.f;
760 713
761 if (params->getPlayPan() != pan) { 714 if (params->getPlayPan() != pan) {
762 PlayParameterRepository::EditCommand *command = 715 PlayParameterRepository::EditCommand *command =
763 new PlayParameterRepository::EditCommand(params); 716 new PlayParameterRepository::EditCommand(params);
764 command->setPlayPan(pan); 717 command->setPlayPan(pan);
840 } 793 }
841 794
842 void 795 void
843 PropertyBox::updateContextHelp(QObject *o) 796 PropertyBox::updateContextHelp(QObject *o)
844 { 797 {
845 QWidget *w = dynamic_cast<QWidget *>(o); 798 QWidget *w = qobject_cast<QWidget *>(o);
846 if (!w) return; 799 if (!w) return;
847 800
848 if (!m_container) return; 801 if (!m_container) return;
849 QString cname = m_container->getPropertyContainerName(); 802 QString cname = m_container->getPropertyContainerName();
850 if (cname == "") return; 803 if (cname == "") return;
851 804
805 LevelPanToolButton *lp = qobject_cast<LevelPanToolButton *>(w);
806 if (lp) {
807 emit contextHelpChanged(tr("Adjust playback level and pan of %1").arg(cname));
808 return;
809 }
810
852 QString wname = w->objectName(); 811 QString wname = w->objectName();
853 812
813 if (wname == "playParamButton") {
814 PlayParameters *params = m_container->getPlayParameters();
815 if (params) {
816 emit contextHelpChanged
817 (tr("Change sound used for playback (currently \"%1\")")
818 .arg(params->getPlayClipId()));
819 return;
820 }
821 }
822
854 QString extraText; 823 QString extraText;
855 AudioDial *dial = dynamic_cast<AudioDial *>(w); 824
825 AudioDial *dial = qobject_cast<AudioDial *>(w);
856 if (dial) { 826 if (dial) {
857 double mv = dial->mappedValue(); 827 double mv = dial->mappedValue();
858 QString unit = ""; 828 QString unit = "";
859 if (dial->rangeMapper()) unit = dial->rangeMapper()->getUnit(); 829 if (dial->rangeMapper()) unit = dial->rangeMapper()->getUnit();
860 if (unit != "") { 830 if (unit != "") {
868 emit contextHelpChanged(tr("Toggle Visibility of %1").arg(cname)); 838 emit contextHelpChanged(tr("Toggle Visibility of %1").arg(cname));
869 } else if (w == m_playButton) { 839 } else if (w == m_playButton) {
870 emit contextHelpChanged(tr("Toggle Playback of %1").arg(cname)); 840 emit contextHelpChanged(tr("Toggle Playback of %1").arg(cname));
871 } else if (wname == "") { 841 } else if (wname == "") {
872 return; 842 return;
873 } else if (dynamic_cast<QAbstractButton *>(w)) { 843 } else if (qobject_cast<QAbstractButton *>(w)) {
874 emit contextHelpChanged(tr("Toggle %1 property of %2") 844 emit contextHelpChanged(tr("Toggle %1 property of %2")
875 .arg(wname).arg(cname)); 845 .arg(wname).arg(cname));
876 } else { 846 } else {
877 emit contextHelpChanged(tr("Adjust %1 property of %2%3") 847 emit contextHelpChanged(tr("Adjust %1 property of %2%3")
878 .arg(wname).arg(cname).arg(extraText)); 848 .arg(wname).arg(cname).arg(extraText));