Mercurial > hg > svgui
comparison layer/TimeInstantLayer.cpp @ 0:2a4f26e85b4c
initial import
author | Chris Cannam |
---|---|
date | Tue, 10 Jan 2006 16:33:16 +0000 |
parents | |
children | 77dad696d740 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:2a4f26e85b4c |
---|---|
1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 A waveform viewer and audio annotation editor. | |
5 Chris Cannam, Queen Mary University of London, 2005 | |
6 | |
7 This is experimental software. Not for distribution. | |
8 */ | |
9 | |
10 #include "TimeInstantLayer.h" | |
11 | |
12 #include "base/Model.h" | |
13 #include "base/RealTime.h" | |
14 #include "base/View.h" | |
15 #include "base/Profiler.h" | |
16 | |
17 #include "model/SparseOneDimensionalModel.h" | |
18 | |
19 #include <QPainter> | |
20 | |
21 #include <iostream> | |
22 | |
23 TimeInstantLayer::TimeInstantLayer(View *w) : | |
24 Layer(w), | |
25 m_model(0), | |
26 m_colour(QColor(200, 50, 255)) | |
27 { | |
28 m_view->addLayer(this); | |
29 } | |
30 | |
31 void | |
32 TimeInstantLayer::setModel(SparseOneDimensionalModel *model) | |
33 { | |
34 if (m_model == model) return; | |
35 m_model = model; | |
36 | |
37 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged())); | |
38 connect(m_model, SIGNAL(modelChanged(size_t, size_t)), | |
39 this, SIGNAL(modelChanged(size_t, size_t))); | |
40 | |
41 connect(m_model, SIGNAL(completionChanged()), | |
42 this, SIGNAL(modelCompletionChanged())); | |
43 | |
44 std::cerr << "TimeInstantLayer::setModel(" << model << ")" << std::endl; | |
45 | |
46 emit modelReplaced(); | |
47 } | |
48 | |
49 Layer::PropertyList | |
50 TimeInstantLayer::getProperties() const | |
51 { | |
52 PropertyList list; | |
53 list.push_back(tr("Colour")); | |
54 return list; | |
55 } | |
56 | |
57 Layer::PropertyType | |
58 TimeInstantLayer::getPropertyType(const PropertyName &name) const | |
59 { | |
60 return ValueProperty; | |
61 } | |
62 | |
63 int | |
64 TimeInstantLayer::getPropertyRangeAndValue(const PropertyName &name, | |
65 int *min, int *max) const | |
66 { | |
67 int deft = 0; | |
68 | |
69 if (name == tr("Colour")) { | |
70 | |
71 *min = 0; | |
72 *max = 5; | |
73 | |
74 if (m_colour == Qt::black) deft = 0; | |
75 else if (m_colour == Qt::darkRed) deft = 1; | |
76 else if (m_colour == Qt::darkBlue) deft = 2; | |
77 else if (m_colour == Qt::darkGreen) deft = 3; | |
78 else if (m_colour == QColor(200, 50, 255)) deft = 4; | |
79 else if (m_colour == QColor(255, 150, 50)) deft = 5; | |
80 | |
81 } else { | |
82 | |
83 deft = Layer::getPropertyRangeAndValue(name, min, max); | |
84 } | |
85 | |
86 return deft; | |
87 } | |
88 | |
89 QString | |
90 TimeInstantLayer::getPropertyValueLabel(const PropertyName &name, | |
91 int value) const | |
92 { | |
93 if (name == tr("Colour")) { | |
94 switch (value) { | |
95 default: | |
96 case 0: return tr("Black"); | |
97 case 1: return tr("Red"); | |
98 case 2: return tr("Blue"); | |
99 case 3: return tr("Green"); | |
100 case 4: return tr("Purple"); | |
101 case 5: return tr("Orange"); | |
102 } | |
103 } | |
104 return tr("<unknown>"); | |
105 } | |
106 | |
107 void | |
108 TimeInstantLayer::setProperty(const PropertyName &name, int value) | |
109 { | |
110 if (name == tr("Colour")) { | |
111 switch (value) { | |
112 default: | |
113 case 0: setBaseColour(Qt::black); break; | |
114 case 1: setBaseColour(Qt::darkRed); break; | |
115 case 2: setBaseColour(Qt::darkBlue); break; | |
116 case 3: setBaseColour(Qt::darkGreen); break; | |
117 case 4: setBaseColour(QColor(200, 50, 255)); break; | |
118 case 5: setBaseColour(QColor(255, 150, 50)); break; | |
119 } | |
120 } | |
121 } | |
122 | |
123 void | |
124 TimeInstantLayer::setBaseColour(QColor colour) | |
125 { | |
126 if (m_colour == colour) return; | |
127 m_colour = colour; | |
128 emit layerParametersChanged(); | |
129 } | |
130 | |
131 bool | |
132 TimeInstantLayer::isLayerScrollable() const | |
133 { | |
134 QPoint discard; | |
135 return !m_view->shouldIlluminateLocalFeatures(this, discard); | |
136 } | |
137 | |
138 QRect | |
139 TimeInstantLayer::getFeatureDescriptionRect(QPainter &paint, QPoint pos) const | |
140 { | |
141 return QRect(0, 0, | |
142 std::max(100, paint.fontMetrics().width(tr("No local points"))), | |
143 50); //!!! cruddy | |
144 } | |
145 | |
146 SparseOneDimensionalModel::PointList | |
147 TimeInstantLayer::getLocalPoints(int x) const | |
148 { | |
149 if (!m_model) return SparseOneDimensionalModel::PointList(); | |
150 | |
151 long startFrame = m_view->getStartFrame(); | |
152 long endFrame = m_view->getEndFrame(); | |
153 int zoomLevel = m_view->getZoomLevel(); | |
154 long frame = startFrame + x * zoomLevel; | |
155 | |
156 SparseOneDimensionalModel::PointList onPoints = | |
157 m_model->getPoints(frame); | |
158 | |
159 if (!onPoints.empty()) { | |
160 return onPoints; | |
161 } | |
162 | |
163 SparseOneDimensionalModel::PointList prevPoints = | |
164 m_model->getPreviousPoints(frame); | |
165 SparseOneDimensionalModel::PointList nextPoints = | |
166 m_model->getNextPoints(frame); | |
167 | |
168 SparseOneDimensionalModel::PointList usePoints = prevPoints; | |
169 | |
170 if (prevPoints.empty()) { | |
171 usePoints = nextPoints; | |
172 } else if (prevPoints.begin()->frame < startFrame && | |
173 !(nextPoints.begin()->frame > endFrame)) { | |
174 usePoints = nextPoints; | |
175 } else if (nextPoints.begin()->frame - frame < | |
176 frame - prevPoints.begin()->frame) { | |
177 usePoints = nextPoints; | |
178 } | |
179 | |
180 return usePoints; | |
181 } | |
182 | |
183 void | |
184 TimeInstantLayer::paintLocalFeatureDescription(QPainter &paint, QRect rect, | |
185 QPoint pos) const | |
186 { | |
187 //!!! bleagh | |
188 | |
189 int x = pos.x(); | |
190 | |
191 if (!m_model || !m_model->getSampleRate()) return; | |
192 | |
193 SparseOneDimensionalModel::PointList points = getLocalPoints(x); | |
194 | |
195 QFontMetrics metrics = paint.fontMetrics(); | |
196 int xbase = rect.x() + 5; | |
197 int ybase = rect.y() + 5; | |
198 | |
199 if (points.empty()) { | |
200 QString label = tr("No local points"); | |
201 if (!m_model->isReady()) { | |
202 label = tr("In progress"); | |
203 } | |
204 paint.drawText(xbase + 5, ybase + 5 + metrics.ascent(), label); | |
205 return; | |
206 } | |
207 | |
208 long useFrame = points.begin()->frame; | |
209 | |
210 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate()); | |
211 QString timeText = QString("%1").arg(rt.toText(true).c_str()); | |
212 | |
213 int timewidth = metrics.width(timeText); | |
214 int labelwidth = metrics.width(points.begin()->label); | |
215 | |
216 int boxheight = metrics.height() * 2 + 3; | |
217 int boxwidth = std::max(timewidth, labelwidth); | |
218 | |
219 paint.drawRect(xbase, ybase, boxwidth + 10, | |
220 boxheight + 10 - metrics.descent() + 1); | |
221 | |
222 paint.drawText(xbase + 5, ybase + 5 + metrics.ascent(), timeText); | |
223 paint.drawText(xbase + 5, ybase + 7 + metrics.ascent() + metrics.height(), | |
224 points.begin()->label); | |
225 } | |
226 | |
227 void | |
228 TimeInstantLayer::paint(QPainter &paint, QRect rect) const | |
229 { | |
230 if (!m_model || !m_model->isOK()) return; | |
231 | |
232 // Profiler profiler("TimeInstantLayer::paint", true); | |
233 | |
234 long startFrame = m_view->getStartFrame(); | |
235 int zoomLevel = m_view->getZoomLevel(); | |
236 | |
237 int x0 = rect.left(), x1 = rect.right(); | |
238 long frame0 = startFrame + x0 * zoomLevel; | |
239 long frame1 = startFrame + x1 * zoomLevel; | |
240 | |
241 SparseOneDimensionalModel::PointList points(m_model->getPoints | |
242 (frame0, frame1)); | |
243 | |
244 paint.setPen(m_colour); | |
245 | |
246 QColor brushColour(m_colour); | |
247 brushColour.setAlpha(100); | |
248 paint.setBrush(brushColour); | |
249 | |
250 // std::cerr << "TimeInstantLayer::paint: resolution is " | |
251 // << m_model->getResolution() << " frames" << std::endl; | |
252 | |
253 QPoint localPos; | |
254 long illuminateFrame = -1; | |
255 | |
256 if (m_view->shouldIlluminateLocalFeatures(this, localPos)) { | |
257 SparseOneDimensionalModel::PointList localPoints = | |
258 getLocalPoints(localPos.x()); | |
259 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame; | |
260 } | |
261 | |
262 for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin(); | |
263 i != points.end(); ++i) { | |
264 | |
265 const SparseOneDimensionalModel::Point &p(*i); | |
266 | |
267 int x = (p.frame - startFrame) / zoomLevel; | |
268 int w = m_model->getResolution() / zoomLevel; | |
269 | |
270 if (w < 1) w = 1; | |
271 if (p.frame == illuminateFrame) { | |
272 paint.setPen(Qt::black); //!!! | |
273 } else { | |
274 paint.setPen(brushColour); | |
275 } | |
276 paint.drawRect(x, 0, w - 1, m_view->height() - 1); | |
277 paint.setPen(m_colour); | |
278 | |
279 if (p.label != "") { | |
280 | |
281 // only draw if there's enough room from here to the next point | |
282 | |
283 int lw = paint.fontMetrics().width(p.label); | |
284 bool good = true; | |
285 | |
286 SparseOneDimensionalModel::PointList::const_iterator j = i; | |
287 if (++j != points.end()) { | |
288 int nx = (j->frame - startFrame) / zoomLevel; | |
289 if (nx >= x && nx - x - w - 3 <= lw) good = false; | |
290 } | |
291 | |
292 if (good) { | |
293 paint.drawText(x + w + 2, | |
294 m_view->height() - paint.fontMetrics().height(), | |
295 p.label); | |
296 } | |
297 } | |
298 } | |
299 } | |
300 | |
301 | |
302 #ifdef INCLUDE_MOCFILES | |
303 #include "TimeInstantLayer.moc.cpp" | |
304 #endif | |
305 |