Mercurial > hg > svgui
comparison layer/TimeRulerLayer.cpp @ 0:2a4f26e85b4c
initial import
author | Chris Cannam |
---|---|
date | Tue, 10 Jan 2006 16:33:16 +0000 |
parents | |
children | 37b110168acf |
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 "TimeRulerLayer.h" | |
11 | |
12 #include "base/Model.h" | |
13 #include "base/RealTime.h" | |
14 #include "base/View.h" | |
15 | |
16 #include <QPainter> | |
17 | |
18 #include <iostream> | |
19 | |
20 using std::cerr; | |
21 using std::endl; | |
22 | |
23 TimeRulerLayer::TimeRulerLayer(View *w) : | |
24 Layer(w), | |
25 m_model(0), | |
26 m_colour(Qt::black), | |
27 m_labelHeight(LabelTop) | |
28 { | |
29 m_view->addLayer(this); | |
30 } | |
31 | |
32 void | |
33 TimeRulerLayer::setModel(Model *model) | |
34 { | |
35 if (m_model == model) return; | |
36 m_model = model; | |
37 emit modelReplaced(); | |
38 } | |
39 | |
40 void | |
41 TimeRulerLayer::setBaseColour(QColor colour) | |
42 { | |
43 if (m_colour == colour) return; | |
44 m_colour = colour; | |
45 emit layerParametersChanged(); | |
46 } | |
47 | |
48 Layer::PropertyList | |
49 TimeRulerLayer::getProperties() const | |
50 { | |
51 PropertyList list; | |
52 list.push_back(tr("Colour")); | |
53 return list; | |
54 } | |
55 | |
56 Layer::PropertyType | |
57 TimeRulerLayer::getPropertyType(const PropertyName &name) const | |
58 { | |
59 return ValueProperty; | |
60 } | |
61 | |
62 int | |
63 TimeRulerLayer::getPropertyRangeAndValue(const PropertyName &name, | |
64 int *min, int *max) const | |
65 { | |
66 int deft = 0; | |
67 | |
68 if (name == tr("Colour")) { | |
69 | |
70 *min = 0; | |
71 *max = 5; | |
72 | |
73 if (m_colour == Qt::black) deft = 0; | |
74 else if (m_colour == Qt::darkRed) deft = 1; | |
75 else if (m_colour == Qt::darkBlue) deft = 2; | |
76 else if (m_colour == Qt::darkGreen) deft = 3; | |
77 else if (m_colour == QColor(200, 50, 255)) deft = 4; | |
78 else if (m_colour == QColor(255, 150, 50)) deft = 5; | |
79 | |
80 } else { | |
81 | |
82 deft = Layer::getPropertyRangeAndValue(name, min, max); | |
83 } | |
84 | |
85 return deft; | |
86 } | |
87 | |
88 QString | |
89 TimeRulerLayer::getPropertyValueLabel(const PropertyName &name, | |
90 int value) const | |
91 { | |
92 if (name == tr("Colour")) { | |
93 switch (value) { | |
94 default: | |
95 case 0: return tr("Black"); | |
96 case 1: return tr("Red"); | |
97 case 2: return tr("Blue"); | |
98 case 3: return tr("Green"); | |
99 case 4: return tr("Purple"); | |
100 case 5: return tr("Orange"); | |
101 } | |
102 } | |
103 return tr("<unknown>"); | |
104 } | |
105 | |
106 void | |
107 TimeRulerLayer::setProperty(const PropertyName &name, int value) | |
108 { | |
109 if (name == tr("Colour")) { | |
110 switch (value) { | |
111 default: | |
112 case 0: setBaseColour(Qt::black); break; | |
113 case 1: setBaseColour(Qt::darkRed); break; | |
114 case 2: setBaseColour(Qt::darkBlue); break; | |
115 case 3: setBaseColour(Qt::darkGreen); break; | |
116 case 4: setBaseColour(QColor(200, 50, 255)); break; | |
117 case 5: setBaseColour(QColor(255, 150, 50)); break; | |
118 } | |
119 } | |
120 } | |
121 | |
122 void | |
123 TimeRulerLayer::paint(QPainter &paint, QRect rect) const | |
124 { | |
125 // std::cerr << "TimeRulerLayer::paint (" << rect.x() << "," << rect.y() | |
126 // << ") [" << rect.width() << "x" << rect.height() << "]" << std::endl; | |
127 | |
128 if (!m_model || !m_model->isOK()) return; | |
129 | |
130 int sampleRate = m_model->getSampleRate(); | |
131 if (!sampleRate) return; | |
132 | |
133 long startFrame = m_view->getStartFrame(); | |
134 long endFrame = m_view->getEndFrame(); | |
135 | |
136 int zoomLevel = m_view->getZoomLevel(); | |
137 | |
138 long rectStart = startFrame + (rect.x() - 100) * zoomLevel; | |
139 long rectEnd = startFrame + (rect.x() + rect.width() + 100) * zoomLevel; | |
140 if (rectStart < startFrame) rectStart = startFrame; | |
141 if (rectEnd > endFrame) rectEnd = endFrame; | |
142 | |
143 // std::cerr << "TimeRulerLayer::paint: calling paint.save()" << std::endl; | |
144 paint.save(); | |
145 //!!! paint.setClipRect(m_view->rect()); | |
146 | |
147 int minPixelSpacing = 50; | |
148 | |
149 RealTime rtStart = RealTime::frame2RealTime(startFrame, sampleRate); | |
150 RealTime rtEnd = RealTime::frame2RealTime(endFrame, sampleRate); | |
151 // cerr << "startFrame " << startFrame << ", endFrame " << m_view->getEndFrame() << ", rtStart " << rtStart << ", rtEnd " << rtEnd << endl; | |
152 int count = m_view->width() / minPixelSpacing; | |
153 if (count < 1) count = 1; | |
154 RealTime rtGap = (rtEnd - rtStart) / count; | |
155 // cerr << "rtGap is " << rtGap << endl; | |
156 | |
157 int incms; | |
158 bool quarter = false; | |
159 | |
160 if (rtGap.sec > 0) { | |
161 incms = 1000; | |
162 int s = rtGap.sec; | |
163 if (s > 0) { incms *= 5; s /= 5; } | |
164 if (s > 0) { incms *= 2; s /= 2; } | |
165 if (s > 0) { incms *= 6; s /= 6; quarter = true; } | |
166 if (s > 0) { incms *= 5; s /= 5; quarter = false; } | |
167 if (s > 0) { incms *= 2; s /= 2; } | |
168 if (s > 0) { incms *= 6; s /= 6; quarter = true; } | |
169 while (s > 0) { | |
170 incms *= 10; | |
171 s /= 10; | |
172 quarter = false; | |
173 } | |
174 } else { | |
175 incms = 1; | |
176 int ms = rtGap.msec(); | |
177 if (ms > 0) { incms *= 10; ms /= 10; } | |
178 if (ms > 0) { incms *= 10; ms /= 10; } | |
179 if (ms > 0) { incms *= 5; ms /= 5; } | |
180 if (ms > 0) { incms *= 2; ms /= 2; } | |
181 } | |
182 // cerr << "incms is " << incms << endl; | |
183 | |
184 RealTime rt = RealTime::frame2RealTime(rectStart, sampleRate); | |
185 long ms = rt.sec * 1000 + rt.msec(); | |
186 ms = (ms / incms) * incms - incms; | |
187 | |
188 RealTime incRt = RealTime(incms / 1000, (incms % 1000) * 1000000); | |
189 long incFrame = RealTime::realTime2Frame(incRt, sampleRate); | |
190 int incX = incFrame / zoomLevel; | |
191 int ticks = 10; | |
192 if (incX < minPixelSpacing * 2) { | |
193 ticks = quarter ? 4 : 5; | |
194 } | |
195 | |
196 QRect oldClipRect = rect; | |
197 QRect newClipRect(oldClipRect.x() - 25, oldClipRect.y(), | |
198 oldClipRect.width() + 50, oldClipRect.height()); | |
199 paint.setClipRect(newClipRect); | |
200 | |
201 QColor greyColour(m_colour); | |
202 if (m_colour == Qt::black) { | |
203 greyColour = QColor(200,200,200); | |
204 } else { | |
205 greyColour = m_colour.light(150); | |
206 } | |
207 | |
208 while (1) { | |
209 | |
210 rt = RealTime(ms / 1000, (ms % 1000) * 1000000); | |
211 ms += incms; | |
212 | |
213 long frame = RealTime::realTime2Frame(rt, sampleRate); | |
214 if (frame >= rectEnd) break; | |
215 | |
216 int x = (frame - startFrame) / zoomLevel; | |
217 if (x < rect.x() || x >= rect.x() + rect.width()) continue; | |
218 | |
219 paint.setPen(greyColour); | |
220 paint.drawLine(x, 0, x, m_view->height()); | |
221 | |
222 paint.setPen(m_colour); | |
223 paint.drawLine(x, 0, x, 5); | |
224 paint.drawLine(x, m_view->height() - 6, x, m_view->height() - 1); | |
225 | |
226 QString text(QString::fromStdString(rt.toText())); | |
227 | |
228 int y; | |
229 QFontMetrics metrics = paint.fontMetrics(); | |
230 switch (m_labelHeight) { | |
231 default: | |
232 case LabelTop: | |
233 y = 6 + metrics.ascent(); | |
234 break; | |
235 case LabelMiddle: | |
236 y = m_view->height() / 2 - metrics.height() / 2 + metrics.ascent(); | |
237 break; | |
238 case LabelBottom: | |
239 y = m_view->height() - metrics.height() + metrics.ascent() - 6; | |
240 } | |
241 | |
242 int tw = metrics.width(text); | |
243 | |
244 paint.setPen(m_view->palette().background().color()); | |
245 | |
246 //!!! simple drawing function for this please | |
247 //!!! and need getContrastingColour() in widget, or use the | |
248 //palette properly -- get the base class able to draw text | |
249 //using the proper colour (or this technique) automatically | |
250 for (int dx = -1; dx <= 1; ++dx) { | |
251 for (int dy = -1; dy <= 1; ++dy) { | |
252 if ((dx && dy) || !(dx || dy)) continue; | |
253 paint.drawText(x + 2 - tw / 2 + dx, y + dy, text); | |
254 } | |
255 } | |
256 | |
257 paint.setPen(m_colour); | |
258 paint.drawText(x + 2 - tw / 2, y, text); | |
259 | |
260 paint.setPen(greyColour); | |
261 | |
262 for (int i = 1; i < ticks; ++i) { | |
263 rt = rt + (incRt / ticks); | |
264 frame = RealTime::realTime2Frame(rt, sampleRate); | |
265 x = (frame - startFrame) / zoomLevel; | |
266 int sz = 5; | |
267 if (ticks == 10) { | |
268 if ((i % 2) == 1) { | |
269 if (i == 5) { | |
270 paint.drawLine(x, 0, x, m_view->height()); | |
271 } else sz = 3; | |
272 } else { | |
273 sz = 7; | |
274 } | |
275 } | |
276 paint.drawLine(x, 0, x, sz); | |
277 paint.drawLine(x, m_view->height() - sz - 1, x, m_view->height() - 1); | |
278 } | |
279 } | |
280 | |
281 paint.restore(); | |
282 } | |
283 | |
284 | |
285 #ifdef INCLUDE_MOCFILES | |
286 #include "TimeRulerLayer.moc.cpp" | |
287 #endif | |
288 |