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