Chris@0
|
1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@0
|
2
|
Chris@0
|
3 /*
|
Chris@0
|
4 A waveform viewer and audio annotation editor.
|
Chris@0
|
5 Chris Cannam, Queen Mary University of London, 2005
|
Chris@0
|
6
|
Chris@0
|
7 This is experimental software. Not for distribution.
|
Chris@0
|
8 */
|
Chris@0
|
9
|
Chris@0
|
10 #include "PropertyBox.h"
|
Chris@0
|
11
|
Chris@0
|
12 #include "base/PropertyContainer.h"
|
Chris@0
|
13
|
Chris@0
|
14 #include "AudioDial.h"
|
Chris@0
|
15
|
Chris@0
|
16 #include <QGridLayout>
|
Chris@0
|
17 #include <QHBoxLayout>
|
Chris@0
|
18 #include <QCheckBox>
|
Chris@0
|
19 #include <QComboBox>
|
Chris@0
|
20 #include <QLabel>
|
Chris@0
|
21
|
Chris@0
|
22 #include <cassert>
|
Chris@0
|
23 #include <iostream>
|
Chris@0
|
24
|
Chris@0
|
25 //#define DEBUG_PROPERTY_BOX 1
|
Chris@0
|
26
|
Chris@0
|
27 PropertyBox::PropertyBox(PropertyContainer *container) :
|
Chris@0
|
28 m_container(container)
|
Chris@0
|
29 {
|
Chris@0
|
30 #ifdef DEBUG_PROPERTY_BOX
|
Chris@0
|
31 std::cerr << "PropertyBox[" << this << "(\"" <<
|
Chris@0
|
32 container->getPropertyContainerName().toStdString() << "\")]::PropertyBox" << std::endl;
|
Chris@0
|
33 #endif
|
Chris@0
|
34
|
Chris@0
|
35 m_layout = new QGridLayout;
|
Chris@0
|
36 setLayout(m_layout);
|
Chris@0
|
37
|
Chris@0
|
38 PropertyContainer::PropertyList properties = container->getProperties();
|
Chris@0
|
39
|
Chris@0
|
40 blockSignals(true);
|
Chris@0
|
41
|
Chris@0
|
42 size_t i;
|
Chris@0
|
43
|
Chris@0
|
44 for (i = 0; i < properties.size(); ++i) {
|
Chris@0
|
45 updatePropertyEditor(properties[i]);
|
Chris@0
|
46 }
|
Chris@0
|
47
|
Chris@0
|
48 blockSignals(false);
|
Chris@0
|
49
|
Chris@0
|
50 m_layout->setRowStretch(m_layout->rowCount(), 10);
|
Chris@0
|
51
|
Chris@0
|
52 #ifdef DEBUG_PROPERTY_BOX
|
Chris@0
|
53 std::cerr << "PropertyBox[" << this << "]::PropertyBox returning" << std::endl;
|
Chris@0
|
54 #endif
|
Chris@0
|
55 }
|
Chris@0
|
56
|
Chris@0
|
57 PropertyBox::~PropertyBox()
|
Chris@0
|
58 {
|
Chris@0
|
59 #ifdef DEBUG_PROPERTY_BOX
|
Chris@0
|
60 std::cerr << "PropertyBox[" << this << "(\"" << m_container->getPropertyContainerName().toStdString() << "\")]::~PropertyBox" << std::endl;
|
Chris@0
|
61 #endif
|
Chris@0
|
62 }
|
Chris@0
|
63
|
Chris@0
|
64 void
|
Chris@0
|
65 PropertyBox::updatePropertyEditor(PropertyContainer::PropertyName name)
|
Chris@0
|
66 {
|
Chris@0
|
67 PropertyContainer::PropertyType type = m_container->getPropertyType(name);
|
Chris@0
|
68 int row = m_layout->rowCount();
|
Chris@0
|
69
|
Chris@0
|
70 int min = 0, max = 0, value = 0;
|
Chris@0
|
71 value = m_container->getPropertyRangeAndValue(name, &min, &max);
|
Chris@0
|
72
|
Chris@0
|
73 bool have = (m_propertyControllers.find(name) !=
|
Chris@0
|
74 m_propertyControllers.end());
|
Chris@0
|
75
|
Chris@0
|
76 QString groupName = m_container->getPropertyGroupName(name);
|
Chris@0
|
77
|
Chris@0
|
78 #ifdef DEBUG_PROPERTY_BOX
|
Chris@0
|
79 std::cerr << "PropertyBox[" << this
|
Chris@0
|
80 << "(\"" << m_container->getPropertyContainerName().toStdString()
|
Chris@0
|
81 << "\")]";
|
Chris@0
|
82 std::cerr << "::updatePropertyEditor(\"" << name.toStdString() << "\"):";
|
Chris@0
|
83 std::cerr << " value " << value << ", have " << have << ", group \""
|
Chris@0
|
84 << groupName.toStdString() << "\"" << std::endl;
|
Chris@0
|
85 #endif
|
Chris@0
|
86
|
Chris@0
|
87 bool inGroup = (groupName != QString());
|
Chris@0
|
88
|
Chris@0
|
89 if (!have) {
|
Chris@0
|
90 if (inGroup) {
|
Chris@0
|
91 if (m_groupLayouts.find(groupName) == m_groupLayouts.end()) {
|
Chris@0
|
92 #ifdef DEBUG_PROPERTY_BOX
|
Chris@0
|
93 std::cerr << "PropertyBox: adding label \"" << groupName.toStdString() << "\" and frame for group for \"" << name.toStdString() << "\"" << std::endl;
|
Chris@0
|
94 #endif
|
Chris@0
|
95 m_layout->addWidget(new QLabel(groupName, this), row, 0);
|
Chris@0
|
96 QFrame *frame = new QFrame(this);
|
Chris@0
|
97 m_layout->addWidget(frame, row, 1, 1, 2);
|
Chris@0
|
98 m_groupLayouts[groupName] = new QHBoxLayout;
|
Chris@0
|
99 m_groupLayouts[groupName]->setMargin(0);
|
Chris@0
|
100 frame->setLayout(m_groupLayouts[groupName]);
|
Chris@0
|
101 }
|
Chris@0
|
102 } else {
|
Chris@0
|
103 #ifdef DEBUG_PROPERTY_BOX
|
Chris@0
|
104 std::cerr << "PropertyBox: adding label \"" << name.toStdString() << "\"" << std::endl;
|
Chris@0
|
105 #endif
|
Chris@0
|
106 m_layout->addWidget(new QLabel(name, this), row, 0);
|
Chris@0
|
107 }
|
Chris@0
|
108 }
|
Chris@0
|
109
|
Chris@0
|
110 switch (type) {
|
Chris@0
|
111
|
Chris@0
|
112 case PropertyContainer::ToggleProperty:
|
Chris@0
|
113 {
|
Chris@0
|
114 QCheckBox *cb;
|
Chris@0
|
115
|
Chris@0
|
116 if (have) {
|
Chris@0
|
117 cb = dynamic_cast<QCheckBox *>(m_propertyControllers[name]);
|
Chris@0
|
118 assert(cb);
|
Chris@0
|
119 } else {
|
Chris@0
|
120 #ifdef DEBUG_PROPERTY_BOX
|
Chris@0
|
121 std::cerr << "PropertyBox: creating new checkbox" << std::endl;
|
Chris@0
|
122 #endif
|
Chris@0
|
123 cb = new QCheckBox();
|
Chris@0
|
124 cb->setObjectName(name);
|
Chris@0
|
125 connect(cb, SIGNAL(stateChanged(int)),
|
Chris@0
|
126 this, SLOT(propertyControllerChanged(int)));
|
Chris@0
|
127 if (inGroup) {
|
Chris@0
|
128 cb->setToolTip(name);
|
Chris@0
|
129 m_groupLayouts[groupName]->addWidget(cb);
|
Chris@0
|
130 } else {
|
Chris@0
|
131 m_layout->addWidget(cb, row, 1, 1, 2);
|
Chris@0
|
132 }
|
Chris@0
|
133 m_propertyControllers[name] = cb;
|
Chris@0
|
134 }
|
Chris@0
|
135
|
Chris@0
|
136 if (cb->isChecked() != (value > 0)) cb->setChecked(value > 0);
|
Chris@0
|
137 break;
|
Chris@0
|
138 }
|
Chris@0
|
139
|
Chris@0
|
140 case PropertyContainer::RangeProperty:
|
Chris@0
|
141 {
|
Chris@0
|
142 AudioDial *dial;
|
Chris@0
|
143
|
Chris@0
|
144 if (have) {
|
Chris@0
|
145 dial = dynamic_cast<AudioDial *>(m_propertyControllers[name]);
|
Chris@0
|
146 assert(dial);
|
Chris@0
|
147 } else {
|
Chris@0
|
148 #ifdef DEBUG_PROPERTY_BOX
|
Chris@0
|
149 std::cerr << "PropertyBox: creating new dial" << std::endl;
|
Chris@0
|
150 #endif
|
Chris@0
|
151 dial = new AudioDial();
|
Chris@0
|
152 dial->setObjectName(name);
|
Chris@0
|
153 dial->setMinimum(min);
|
Chris@0
|
154 dial->setMaximum(max);
|
Chris@0
|
155 dial->setPageStep(1);
|
Chris@0
|
156 dial->setNotchesVisible(true);
|
Chris@0
|
157 connect(dial, SIGNAL(valueChanged(int)),
|
Chris@0
|
158 this, SLOT(propertyControllerChanged(int)));
|
Chris@0
|
159
|
Chris@0
|
160 if (inGroup) {
|
Chris@0
|
161 dial->setFixedWidth(24);
|
Chris@0
|
162 dial->setFixedHeight(24);
|
Chris@0
|
163 dial->setToolTip(name);
|
Chris@0
|
164 m_groupLayouts[groupName]->addWidget(dial);
|
Chris@0
|
165 } else {
|
Chris@0
|
166 dial->setFixedWidth(32);
|
Chris@0
|
167 dial->setFixedHeight(32);
|
Chris@0
|
168 m_layout->addWidget(dial, row, 1);
|
Chris@0
|
169 QLabel *label = new QLabel(this);
|
Chris@0
|
170 connect(dial, SIGNAL(valueChanged(int)),
|
Chris@0
|
171 label, SLOT(setNum(int)));
|
Chris@0
|
172 label->setNum(value);
|
Chris@0
|
173 m_layout->addWidget(label, row, 2);
|
Chris@0
|
174 }
|
Chris@0
|
175
|
Chris@0
|
176 m_propertyControllers[name] = dial;
|
Chris@0
|
177 }
|
Chris@0
|
178
|
Chris@0
|
179 if (dial->value() != value) dial->setValue(value);
|
Chris@0
|
180 break;
|
Chris@0
|
181 }
|
Chris@0
|
182
|
Chris@0
|
183 case PropertyContainer::ValueProperty:
|
Chris@0
|
184 {
|
Chris@0
|
185 QComboBox *cb;
|
Chris@0
|
186
|
Chris@0
|
187 if (have) {
|
Chris@0
|
188 cb = dynamic_cast<QComboBox *>(m_propertyControllers[name]);
|
Chris@0
|
189 assert(cb);
|
Chris@0
|
190 } else {
|
Chris@0
|
191 #ifdef DEBUG_PROPERTY_BOX
|
Chris@0
|
192 std::cerr << "PropertyBox: creating new combobox" << std::endl;
|
Chris@0
|
193 #endif
|
Chris@0
|
194
|
Chris@0
|
195 cb = new QComboBox();
|
Chris@0
|
196 cb->setObjectName(name);
|
Chris@0
|
197 for (int i = min; i <= max; ++i) {
|
Chris@0
|
198 cb->addItem(m_container->getPropertyValueLabel(name, i));
|
Chris@0
|
199 }
|
Chris@0
|
200 connect(cb, SIGNAL(activated(int)),
|
Chris@0
|
201 this, SLOT(propertyControllerChanged(int)));
|
Chris@0
|
202 if (inGroup) {
|
Chris@0
|
203 cb->setToolTip(name);
|
Chris@0
|
204 m_groupLayouts[groupName]->addWidget(cb);
|
Chris@0
|
205 } else {
|
Chris@0
|
206 m_layout->addWidget(cb, row, 1, 1, 2);
|
Chris@0
|
207 }
|
Chris@0
|
208 m_propertyControllers[name] = cb;
|
Chris@0
|
209 }
|
Chris@0
|
210
|
Chris@0
|
211 if (cb->currentIndex() != value) cb->setCurrentIndex(value);
|
Chris@0
|
212
|
Chris@0
|
213 #ifdef Q_WS_MAC
|
Chris@0
|
214 // Crashes on startup without this, for some reason
|
Chris@0
|
215 cb->setMinimumSize(QSize(10, 10));
|
Chris@0
|
216 #endif
|
Chris@0
|
217
|
Chris@0
|
218 break;
|
Chris@0
|
219 }
|
Chris@0
|
220
|
Chris@0
|
221 default:
|
Chris@0
|
222 break;
|
Chris@0
|
223 }
|
Chris@0
|
224 }
|
Chris@0
|
225
|
Chris@0
|
226 void
|
Chris@0
|
227 PropertyBox::propertyContainerPropertyChanged(PropertyContainer *pc)
|
Chris@0
|
228 {
|
Chris@0
|
229 if (pc != m_container) return;
|
Chris@0
|
230
|
Chris@0
|
231 PropertyContainer::PropertyList properties = m_container->getProperties();
|
Chris@0
|
232 size_t i;
|
Chris@0
|
233
|
Chris@0
|
234 blockSignals(true);
|
Chris@0
|
235
|
Chris@0
|
236 for (i = 0; i < properties.size(); ++i) {
|
Chris@0
|
237 updatePropertyEditor(properties[i]);
|
Chris@0
|
238 }
|
Chris@0
|
239
|
Chris@0
|
240 blockSignals(false);
|
Chris@0
|
241 }
|
Chris@0
|
242
|
Chris@0
|
243 void
|
Chris@0
|
244 PropertyBox::propertyControllerChanged(int value)
|
Chris@0
|
245 {
|
Chris@0
|
246 QObject *obj = sender();
|
Chris@0
|
247 QString name = obj->objectName();
|
Chris@0
|
248
|
Chris@0
|
249 // std::cerr << "PropertyBox::propertyControllerChanged(" << name.toStdString()
|
Chris@0
|
250 // << ", " << value << ")" << std::endl;
|
Chris@0
|
251
|
Chris@0
|
252 PropertyContainer::PropertyType type = m_container->getPropertyType(name);
|
Chris@0
|
253
|
Chris@0
|
254 if (type != PropertyContainer::InvalidProperty) {
|
Chris@0
|
255 m_container->setProperty(name, value);
|
Chris@0
|
256 }
|
Chris@0
|
257
|
Chris@0
|
258 if (type == PropertyContainer::RangeProperty) {
|
Chris@0
|
259 AudioDial *dial = dynamic_cast<AudioDial *>(m_propertyControllers[name]);
|
Chris@0
|
260 if (dial) {
|
Chris@0
|
261 dial->setToolTip(QString("%1: %2").arg(name).arg(value));
|
Chris@0
|
262 //!!! unfortunately this doesn't update an already-visible tooltip
|
Chris@0
|
263 }
|
Chris@0
|
264 }
|
Chris@0
|
265 }
|
Chris@0
|
266
|
Chris@0
|
267
|
Chris@0
|
268
|
Chris@0
|
269 #ifdef INCLUDE_MOCFILES
|
Chris@0
|
270 #include "PropertyBox.moc.cpp"
|
Chris@0
|
271 #endif
|
Chris@0
|
272
|