annotate layer/TimeRulerLayer.cpp @ 11:2d5005f2b3d9

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