annotate layer/TextLayer.cpp @ 282:d9319859a4cf tip

(none)
author benoitrigolleau
date Fri, 31 Oct 2008 11:00:24 +0000
parents d8e6709e9075
children
rev   line source
lbajardsilogic@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
lbajardsilogic@0 2
lbajardsilogic@0 3 /*
lbajardsilogic@0 4 Sonic Visualiser
lbajardsilogic@0 5 An audio file viewer and annotation editor.
lbajardsilogic@0 6 Centre for Digital Music, Queen Mary, University of London.
lbajardsilogic@0 7 This file copyright 2006 Chris Cannam.
lbajardsilogic@0 8
lbajardsilogic@0 9 This program is free software; you can redistribute it and/or
lbajardsilogic@0 10 modify it under the terms of the GNU General Public License as
lbajardsilogic@0 11 published by the Free Software Foundation; either version 2 of the
lbajardsilogic@0 12 License, or (at your option) any later version. See the file
lbajardsilogic@0 13 COPYING included with this distribution for more information.
lbajardsilogic@0 14 */
lbajardsilogic@0 15
lbajardsilogic@0 16 #include "TextLayer.h"
lbajardsilogic@0 17
lbajardsilogic@0 18 #include "data/model/Model.h"
lbajardsilogic@0 19 #include "base/RealTime.h"
lbajardsilogic@0 20 #include "base/Profiler.h"
lbajardsilogic@0 21 #include "view/View.h"
lbajardsilogic@0 22
lbajardsilogic@0 23 #include "data/model/TextModel.h"
lbajardsilogic@0 24
lbajardsilogic@0 25 #include <QPainter>
lbajardsilogic@0 26 #include <QMouseEvent>
lbajardsilogic@0 27 #include <QInputDialog>
lbajardsilogic@0 28
lbajardsilogic@0 29 #include <iostream>
lbajardsilogic@0 30 #include <cmath>
lbajardsilogic@0 31
lbajardsilogic@0 32 TextLayer::TextLayer() :
lbajardsilogic@0 33 Layer(),
lbajardsilogic@0 34 m_model(0),
lbajardsilogic@0 35 m_editing(false),
lbajardsilogic@0 36 m_originalPoint(0, 0.0, tr("Empty Label")),
lbajardsilogic@0 37 m_editingPoint(0, 0.0, tr("Empty Label")),
lbajardsilogic@0 38 m_editingCommand(0),
lbajardsilogic@0 39 m_colour(255, 150, 50) // orange
lbajardsilogic@0 40 {
lbajardsilogic@0 41
lbajardsilogic@0 42 }
lbajardsilogic@0 43
lbajardsilogic@0 44 void
lbajardsilogic@0 45 TextLayer::setModel(TextModel *model)
lbajardsilogic@0 46 {
lbajardsilogic@0 47 if (m_model == model) return;
lbajardsilogic@0 48 m_model = model;
lbajardsilogic@0 49
lbajardsilogic@0 50 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
lbajardsilogic@0 51 connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
lbajardsilogic@0 52 this, SIGNAL(modelChanged(size_t, size_t)));
lbajardsilogic@0 53
lbajardsilogic@0 54 connect(m_model, SIGNAL(completionChanged()),
lbajardsilogic@0 55 this, SIGNAL(modelCompletionChanged()));
lbajardsilogic@0 56
lbajardsilogic@0 57 // std::cerr << "TextLayer::setModel(" << model << ")" << std::endl;
lbajardsilogic@0 58
lbajardsilogic@0 59 emit modelReplaced();
lbajardsilogic@0 60 }
lbajardsilogic@0 61
lbajardsilogic@0 62 Layer::PropertyList
lbajardsilogic@0 63 TextLayer::getProperties() const
lbajardsilogic@0 64 {
lbajardsilogic@0 65 PropertyList list;
lbajardsilogic@0 66 list.push_back("Colour");
lbajardsilogic@0 67 return list;
lbajardsilogic@0 68 }
lbajardsilogic@0 69
lbajardsilogic@0 70 QString
lbajardsilogic@0 71 TextLayer::getPropertyLabel(const PropertyName &name) const
lbajardsilogic@0 72 {
lbajardsilogic@0 73 if (name == "Colour") return tr("Colour");
lbajardsilogic@0 74 return "";
lbajardsilogic@0 75 }
lbajardsilogic@0 76
lbajardsilogic@0 77 Layer::PropertyType
lbajardsilogic@0 78 TextLayer::getPropertyType(const PropertyName &) const
lbajardsilogic@0 79 {
lbajardsilogic@0 80 return ValueProperty;
lbajardsilogic@0 81 }
lbajardsilogic@0 82
lbajardsilogic@0 83 int
lbajardsilogic@0 84 TextLayer::getPropertyRangeAndValue(const PropertyName &name,
lbajardsilogic@0 85 int *min, int *max, int *deflt) const
lbajardsilogic@0 86 {
lbajardsilogic@0 87 //!!! factor this colour handling stuff out into a colour manager class
lbajardsilogic@0 88
lbajardsilogic@0 89 int val = 0;
lbajardsilogic@0 90
lbajardsilogic@0 91 if (name == "Colour") {
lbajardsilogic@0 92
lbajardsilogic@0 93 if (min) *min = 0;
lbajardsilogic@0 94 if (max) *max = 5;
lbajardsilogic@0 95 if (deflt) *deflt = 0;
lbajardsilogic@0 96
lbajardsilogic@0 97 if (m_colour == Qt::black) val = 0;
lbajardsilogic@0 98 else if (m_colour == Qt::darkRed) val = 1;
lbajardsilogic@0 99 else if (m_colour == Qt::darkBlue) val = 2;
lbajardsilogic@0 100 else if (m_colour == Qt::darkGreen) val = 3;
lbajardsilogic@0 101 else if (m_colour == QColor(200, 50, 255)) val = 4;
lbajardsilogic@0 102 else if (m_colour == QColor(255, 150, 50)) val = 5;
lbajardsilogic@0 103
lbajardsilogic@0 104 } else {
lbajardsilogic@0 105
lbajardsilogic@0 106 val = Layer::getPropertyRangeAndValue(name, min, max, deflt);
lbajardsilogic@0 107 }
lbajardsilogic@0 108
lbajardsilogic@0 109 return val;
lbajardsilogic@0 110 }
lbajardsilogic@0 111
lbajardsilogic@0 112 QString
lbajardsilogic@0 113 TextLayer::getPropertyValueLabel(const PropertyName &name,
lbajardsilogic@0 114 int value) const
lbajardsilogic@0 115 {
lbajardsilogic@0 116 if (name == "Colour") {
lbajardsilogic@0 117 switch (value) {
lbajardsilogic@0 118 default:
lbajardsilogic@0 119 case 0: return tr("Black");
lbajardsilogic@0 120 case 1: return tr("Red");
lbajardsilogic@0 121 case 2: return tr("Blue");
lbajardsilogic@0 122 case 3: return tr("Green");
lbajardsilogic@0 123 case 4: return tr("Purple");
lbajardsilogic@0 124 case 5: return tr("Orange");
lbajardsilogic@0 125 }
lbajardsilogic@0 126 }
lbajardsilogic@0 127 return tr("<unknown>");
lbajardsilogic@0 128 }
lbajardsilogic@0 129
lbajardsilogic@0 130 void
lbajardsilogic@0 131 TextLayer::setProperty(const PropertyName &name, int value)
lbajardsilogic@0 132 {
lbajardsilogic@0 133 if (name == "Colour") {
lbajardsilogic@0 134 switch (value) {
lbajardsilogic@0 135 default:
lbajardsilogic@0 136 case 0: setBaseColour(Qt::black); break;
lbajardsilogic@0 137 case 1: setBaseColour(Qt::darkRed); break;
lbajardsilogic@0 138 case 2: setBaseColour(Qt::darkBlue); break;
lbajardsilogic@0 139 case 3: setBaseColour(Qt::darkGreen); break;
lbajardsilogic@0 140 case 4: setBaseColour(QColor(200, 50, 255)); break;
lbajardsilogic@0 141 case 5: setBaseColour(QColor(255, 150, 50)); break;
lbajardsilogic@0 142 }
lbajardsilogic@0 143 }
lbajardsilogic@0 144 }
lbajardsilogic@0 145
lbajardsilogic@0 146 bool
lbajardsilogic@0 147 TextLayer::getValueExtents(float &, float &, bool &, QString &) const
lbajardsilogic@0 148 {
lbajardsilogic@0 149 return false;
lbajardsilogic@0 150 }
lbajardsilogic@0 151
lbajardsilogic@0 152 void
lbajardsilogic@0 153 TextLayer::setBaseColour(QColor colour)
lbajardsilogic@0 154 {
lbajardsilogic@0 155 if (m_colour == colour) return;
lbajardsilogic@0 156 m_colour = colour;
lbajardsilogic@0 157 emit layerParametersChanged();
lbajardsilogic@0 158 }
lbajardsilogic@0 159
lbajardsilogic@0 160 bool
lbajardsilogic@0 161 TextLayer::isLayerScrollable(const View *v) const
lbajardsilogic@0 162 {
lbajardsilogic@0 163 QPoint discard;
lbajardsilogic@0 164 return !v->shouldIlluminateLocalFeatures(this, discard);
lbajardsilogic@0 165 }
lbajardsilogic@0 166
lbajardsilogic@0 167
lbajardsilogic@0 168 TextModel::PointList
lbajardsilogic@0 169 TextLayer::getLocalPoints(View *v, int x, int y) const
lbajardsilogic@0 170 {
lbajardsilogic@0 171 if (!m_model) return TextModel::PointList();
lbajardsilogic@0 172
lbajardsilogic@0 173 long frame0 = v->getFrameForX(-150);
lbajardsilogic@0 174 long frame1 = v->getFrameForX(v->width() + 150);
lbajardsilogic@0 175
lbajardsilogic@0 176 TextModel::PointList points(m_model->getPoints(frame0, frame1));
lbajardsilogic@0 177
lbajardsilogic@0 178 TextModel::PointList rv;
lbajardsilogic@0 179 QFontMetrics metrics = QPainter().fontMetrics();
lbajardsilogic@0 180
lbajardsilogic@0 181 for (TextModel::PointList::iterator i = points.begin();
lbajardsilogic@0 182 i != points.end(); ++i) {
lbajardsilogic@0 183
lbajardsilogic@0 184 const TextModel::Point &p(*i);
lbajardsilogic@0 185
lbajardsilogic@0 186 int px = v->getXForFrame(p.frame);
lbajardsilogic@0 187 int py = getYForHeight(v, p.height);
lbajardsilogic@0 188
lbajardsilogic@0 189 QString label = p.label;
lbajardsilogic@0 190 if (label == "") {
lbajardsilogic@0 191 label = tr("<no text>");
lbajardsilogic@0 192 }
lbajardsilogic@0 193
lbajardsilogic@0 194 QRect rect = metrics.boundingRect
lbajardsilogic@0 195 (QRect(0, 0, 150, 200),
lbajardsilogic@0 196 Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, label);
lbajardsilogic@0 197
lbajardsilogic@0 198 if (py + rect.height() > v->height()) {
lbajardsilogic@0 199 if (rect.height() > v->height()) py = 0;
lbajardsilogic@0 200 else py = v->height() - rect.height() - 1;
lbajardsilogic@0 201 }
lbajardsilogic@0 202
lbajardsilogic@0 203 if (x >= px && x < px + rect.width() &&
lbajardsilogic@0 204 y >= py && y < py + rect.height()) {
lbajardsilogic@0 205 rv.insert(p);
lbajardsilogic@0 206 }
lbajardsilogic@0 207 }
lbajardsilogic@0 208
lbajardsilogic@0 209 return rv;
lbajardsilogic@0 210 }
lbajardsilogic@0 211
lbajardsilogic@0 212 QString
lbajardsilogic@0 213 TextLayer::getFeatureDescription(View *v, QPoint &pos) const
lbajardsilogic@0 214 {
lbajardsilogic@0 215 int x = pos.x();
lbajardsilogic@0 216
lbajardsilogic@0 217 if (!m_model || !m_model->getSampleRate()) return "";
lbajardsilogic@0 218
lbajardsilogic@0 219 TextModel::PointList points = getLocalPoints(v, x, pos.y());
lbajardsilogic@0 220
lbajardsilogic@0 221 if (points.empty()) {
lbajardsilogic@0 222 if (!m_model->isReady()) {
lbajardsilogic@0 223 return tr("In progress");
lbajardsilogic@0 224 } else {
lbajardsilogic@0 225 return "";
lbajardsilogic@0 226 }
lbajardsilogic@0 227 }
lbajardsilogic@0 228
lbajardsilogic@0 229 long useFrame = points.begin()->frame;
lbajardsilogic@0 230
lbajardsilogic@0 231 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate());
lbajardsilogic@0 232
lbajardsilogic@0 233 QString text;
lbajardsilogic@0 234
lbajardsilogic@0 235 if (points.begin()->label == "") {
lbajardsilogic@0 236 text = QString(tr("Time:\t%1\nHeight:\t%2\nLabel:\t%3"))
lbajardsilogic@0 237 .arg(rt.toText(true).c_str())
lbajardsilogic@0 238 .arg(points.begin()->height)
lbajardsilogic@0 239 .arg(points.begin()->label);
lbajardsilogic@0 240 }
lbajardsilogic@0 241
lbajardsilogic@0 242 pos = QPoint(v->getXForFrame(useFrame),
lbajardsilogic@0 243 getYForHeight(v, points.begin()->height));
lbajardsilogic@0 244 return text;
lbajardsilogic@0 245 }
lbajardsilogic@0 246
lbajardsilogic@0 247
lbajardsilogic@0 248 //!!! too much overlap with TimeValueLayer/TimeInstantLayer
lbajardsilogic@0 249
lbajardsilogic@0 250 bool
lbajardsilogic@0 251 TextLayer::snapToFeatureFrame(View *v, int &frame,
lbajardsilogic@0 252 size_t &resolution,
lbajardsilogic@0 253 SnapType snap) const
lbajardsilogic@0 254 {
lbajardsilogic@0 255 if (!m_model) {
lbajardsilogic@0 256 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
lbajardsilogic@0 257 }
lbajardsilogic@0 258
lbajardsilogic@0 259 resolution = m_model->getResolution();
lbajardsilogic@0 260 TextModel::PointList points;
lbajardsilogic@0 261
lbajardsilogic@0 262 if (snap == SnapNeighbouring) {
lbajardsilogic@0 263
lbajardsilogic@0 264 points = getLocalPoints(v, v->getXForFrame(frame), -1);
lbajardsilogic@0 265 if (points.empty()) return false;
lbajardsilogic@0 266 frame = points.begin()->frame;
lbajardsilogic@0 267 return true;
lbajardsilogic@0 268 }
lbajardsilogic@0 269
lbajardsilogic@0 270 points = m_model->getPoints(frame, frame);
lbajardsilogic@0 271 int snapped = frame;
lbajardsilogic@0 272 bool found = false;
lbajardsilogic@0 273
lbajardsilogic@0 274 for (TextModel::PointList::const_iterator i = points.begin();
lbajardsilogic@0 275 i != points.end(); ++i) {
lbajardsilogic@0 276
lbajardsilogic@0 277 if (snap == SnapRight) {
lbajardsilogic@0 278
lbajardsilogic@0 279 if (i->frame > frame) {
lbajardsilogic@0 280 snapped = i->frame;
lbajardsilogic@0 281 found = true;
lbajardsilogic@0 282 break;
lbajardsilogic@0 283 }
lbajardsilogic@0 284
lbajardsilogic@0 285 } else if (snap == SnapLeft) {
lbajardsilogic@0 286
lbajardsilogic@0 287 if (i->frame <= frame) {
lbajardsilogic@0 288 snapped = i->frame;
lbajardsilogic@0 289 found = true; // don't break, as the next may be better
lbajardsilogic@0 290 } else {
lbajardsilogic@0 291 break;
lbajardsilogic@0 292 }
lbajardsilogic@0 293
lbajardsilogic@0 294 } else { // nearest
lbajardsilogic@0 295
lbajardsilogic@0 296 TextModel::PointList::const_iterator j = i;
lbajardsilogic@0 297 ++j;
lbajardsilogic@0 298
lbajardsilogic@0 299 if (j == points.end()) {
lbajardsilogic@0 300
lbajardsilogic@0 301 snapped = i->frame;
lbajardsilogic@0 302 found = true;
lbajardsilogic@0 303 break;
lbajardsilogic@0 304
lbajardsilogic@0 305 } else if (j->frame >= frame) {
lbajardsilogic@0 306
lbajardsilogic@0 307 if (j->frame - frame < frame - i->frame) {
lbajardsilogic@0 308 snapped = j->frame;
lbajardsilogic@0 309 } else {
lbajardsilogic@0 310 snapped = i->frame;
lbajardsilogic@0 311 }
lbajardsilogic@0 312 found = true;
lbajardsilogic@0 313 break;
lbajardsilogic@0 314 }
lbajardsilogic@0 315 }
lbajardsilogic@0 316 }
lbajardsilogic@0 317
lbajardsilogic@0 318 frame = snapped;
lbajardsilogic@0 319 return found;
lbajardsilogic@0 320 }
lbajardsilogic@0 321
lbajardsilogic@0 322 int
lbajardsilogic@0 323 TextLayer::getYForHeight(View *v, float height) const
lbajardsilogic@0 324 {
lbajardsilogic@0 325 int h = v->height();
lbajardsilogic@0 326 return h - int(height * h);
lbajardsilogic@0 327 }
lbajardsilogic@0 328
lbajardsilogic@0 329 float
lbajardsilogic@0 330 TextLayer::getHeightForY(View *v, int y) const
lbajardsilogic@0 331 {
lbajardsilogic@0 332 int h = v->height();
lbajardsilogic@0 333 return float(h - y) / h;
lbajardsilogic@0 334 }
lbajardsilogic@0 335
lbajardsilogic@0 336 void
lbajardsilogic@0 337 TextLayer::paint(View *v, QPainter &paint, QRect rect) const
lbajardsilogic@0 338 {
lbajardsilogic@0 339 if (!m_model || !m_model->isOK()) return;
lbajardsilogic@0 340
lbajardsilogic@0 341 int sampleRate = m_model->getSampleRate();
lbajardsilogic@0 342 if (!sampleRate) return;
lbajardsilogic@0 343
lbajardsilogic@0 344 // Profiler profiler("TextLayer::paint", true);
lbajardsilogic@0 345
lbajardsilogic@0 346 int x0 = rect.left(), x1 = rect.right();
lbajardsilogic@0 347 long frame0 = v->getFrameForX(x0);
lbajardsilogic@0 348 long frame1 = v->getFrameForX(x1);
lbajardsilogic@0 349
lbajardsilogic@0 350 TextModel::PointList points(m_model->getPoints(frame0, frame1));
lbajardsilogic@0 351 if (points.empty()) return;
lbajardsilogic@0 352
lbajardsilogic@0 353 QColor brushColour(m_colour);
lbajardsilogic@0 354
lbajardsilogic@0 355 int h, s, val;
lbajardsilogic@0 356 brushColour.getHsv(&h, &s, &val);
lbajardsilogic@0 357 brushColour.setHsv(h, s, 255, 100);
lbajardsilogic@0 358
lbajardsilogic@0 359 QColor penColour;
lbajardsilogic@0 360 if (v->hasLightBackground()) {
lbajardsilogic@0 361 penColour = Qt::black;
lbajardsilogic@0 362 } else {
lbajardsilogic@0 363 penColour = Qt::white;
lbajardsilogic@0 364 }
lbajardsilogic@0 365
lbajardsilogic@0 366 // std::cerr << "TextLayer::paint: resolution is "
lbajardsilogic@0 367 // << m_model->getResolution() << " frames" << std::endl;
lbajardsilogic@0 368
lbajardsilogic@0 369 QPoint localPos;
lbajardsilogic@0 370 long illuminateFrame = -1;
lbajardsilogic@0 371
lbajardsilogic@0 372 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
lbajardsilogic@0 373 TextModel::PointList localPoints = getLocalPoints(v, localPos.x(),
lbajardsilogic@0 374 localPos.y());
lbajardsilogic@0 375 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame;
lbajardsilogic@0 376 }
lbajardsilogic@0 377
lbajardsilogic@0 378 int boxMaxWidth = 150;
lbajardsilogic@0 379 int boxMaxHeight = 200;
lbajardsilogic@0 380
lbajardsilogic@0 381 paint.save();
lbajardsilogic@0 382 paint.setClipRect(rect.x(), 0, rect.width() + boxMaxWidth, v->height());
lbajardsilogic@0 383
lbajardsilogic@0 384 for (TextModel::PointList::const_iterator i = points.begin();
lbajardsilogic@0 385 i != points.end(); ++i) {
lbajardsilogic@0 386
lbajardsilogic@0 387 const TextModel::Point &p(*i);
lbajardsilogic@0 388
lbajardsilogic@0 389 int x = v->getXForFrame(p.frame);
lbajardsilogic@0 390 int y = getYForHeight(v, p.height);
lbajardsilogic@0 391
lbajardsilogic@0 392 if (illuminateFrame == p.frame) {
lbajardsilogic@0 393 paint.setBrush(penColour);
lbajardsilogic@0 394 if (v->hasLightBackground()) {
lbajardsilogic@0 395 paint.setPen(Qt::white);
lbajardsilogic@0 396 } else {
lbajardsilogic@0 397 paint.setPen(Qt::black);
lbajardsilogic@0 398 }
lbajardsilogic@0 399 } else {
lbajardsilogic@0 400 paint.setPen(penColour);
lbajardsilogic@0 401 paint.setBrush(brushColour);
lbajardsilogic@0 402 }
lbajardsilogic@0 403
lbajardsilogic@0 404 QString label = p.label;
lbajardsilogic@0 405 if (label == "") {
lbajardsilogic@0 406 label = tr("<no text>");
lbajardsilogic@0 407 }
lbajardsilogic@0 408
lbajardsilogic@0 409 QRect boxRect = paint.fontMetrics().boundingRect
lbajardsilogic@0 410 (QRect(0, 0, boxMaxWidth, boxMaxHeight),
lbajardsilogic@0 411 Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, label);
lbajardsilogic@0 412
lbajardsilogic@0 413 QRect textRect = QRect(3, 2, boxRect.width(), boxRect.height());
lbajardsilogic@0 414 boxRect = QRect(0, 0, boxRect.width() + 6, boxRect.height() + 2);
lbajardsilogic@0 415
lbajardsilogic@0 416 if (y + boxRect.height() > v->height()) {
lbajardsilogic@0 417 if (boxRect.height() > v->height()) y = 0;
lbajardsilogic@0 418 else y = v->height() - boxRect.height() - 1;
lbajardsilogic@0 419 }
lbajardsilogic@0 420
lbajardsilogic@0 421 boxRect = QRect(x, y, boxRect.width(), boxRect.height());
lbajardsilogic@0 422 textRect = QRect(x + 3, y + 2, textRect.width(), textRect.height());
lbajardsilogic@0 423
lbajardsilogic@0 424 // boxRect = QRect(x, y, boxRect.width(), boxRect.height());
lbajardsilogic@0 425 // textRect = QRect(x + 3, y + 2, textRect.width(), textRect.height());
lbajardsilogic@0 426
lbajardsilogic@0 427 paint.setRenderHint(QPainter::Antialiasing, false);
lbajardsilogic@0 428 paint.drawRect(boxRect);
lbajardsilogic@0 429
lbajardsilogic@0 430 paint.setRenderHint(QPainter::Antialiasing, true);
lbajardsilogic@0 431 paint.drawText(textRect,
lbajardsilogic@0 432 Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap,
lbajardsilogic@0 433 label);
lbajardsilogic@0 434
lbajardsilogic@0 435 /// if (p.label != "") {
lbajardsilogic@0 436 /// paint.drawText(x + 5, y - paint.fontMetrics().height() + paint.fontMetrics().ascent(), p.label);
lbajardsilogic@0 437 /// }
lbajardsilogic@0 438 }
lbajardsilogic@0 439
lbajardsilogic@0 440 paint.restore();
lbajardsilogic@0 441
lbajardsilogic@0 442 // looks like save/restore doesn't deal with this:
lbajardsilogic@0 443 paint.setRenderHint(QPainter::Antialiasing, false);
lbajardsilogic@0 444 }
lbajardsilogic@0 445
lbajardsilogic@0 446 void
lbajardsilogic@0 447 TextLayer::drawStart(View *v, QMouseEvent *e)
lbajardsilogic@0 448 {
lbajardsilogic@0 449 // std::cerr << "TextLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 450
lbajardsilogic@0 451 if (!m_model) {
lbajardsilogic@0 452 std::cerr << "TextLayer::drawStart: no model" << std::endl;
lbajardsilogic@0 453 return;
lbajardsilogic@0 454 }
lbajardsilogic@0 455
lbajardsilogic@0 456 long frame = v->getFrameForX(e->x());
lbajardsilogic@0 457 if (frame < 0) frame = 0;
lbajardsilogic@0 458 frame = frame / m_model->getResolution() * m_model->getResolution();
lbajardsilogic@0 459
lbajardsilogic@0 460 float height = getHeightForY(v, e->y());
lbajardsilogic@0 461
lbajardsilogic@0 462 m_editingPoint = TextModel::Point(frame, height, "");
lbajardsilogic@0 463 m_originalPoint = m_editingPoint;
lbajardsilogic@0 464
lbajardsilogic@0 465 if (m_editingCommand) m_editingCommand->finish();
lbajardsilogic@0 466 m_editingCommand = new TextModel::EditCommand(m_model, "Add Label");
lbajardsilogic@0 467 m_editingCommand->addPoint(m_editingPoint);
lbajardsilogic@0 468
lbajardsilogic@0 469 m_editing = true;
lbajardsilogic@0 470 }
lbajardsilogic@0 471
lbajardsilogic@0 472 void
lbajardsilogic@0 473 TextLayer::drawDrag(View *v, QMouseEvent *e)
lbajardsilogic@0 474 {
lbajardsilogic@0 475 // std::cerr << "TextLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 476
lbajardsilogic@0 477 if (!m_model || !m_editing) return;
lbajardsilogic@0 478
lbajardsilogic@0 479 long frame = v->getFrameForX(e->x());
lbajardsilogic@0 480 if (frame < 0) frame = 0;
lbajardsilogic@0 481 frame = frame / m_model->getResolution() * m_model->getResolution();
lbajardsilogic@0 482
lbajardsilogic@0 483 float height = getHeightForY(v, e->y());
lbajardsilogic@0 484
lbajardsilogic@0 485 m_editingCommand->deletePoint(m_editingPoint);
lbajardsilogic@0 486 m_editingPoint.frame = frame;
lbajardsilogic@0 487 m_editingPoint.height = height;
lbajardsilogic@0 488 m_editingCommand->addPoint(m_editingPoint);
lbajardsilogic@0 489 }
lbajardsilogic@0 490
lbajardsilogic@0 491 void
lbajardsilogic@0 492 TextLayer::drawEnd(View *v, QMouseEvent *)
lbajardsilogic@0 493 {
lbajardsilogic@0 494 // std::cerr << "TextLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 495 if (!m_model || !m_editing) return;
lbajardsilogic@0 496
lbajardsilogic@0 497 bool ok = false;
lbajardsilogic@0 498 QString label = QInputDialog::getText(v, tr("Enter label"),
lbajardsilogic@0 499 tr("Please enter a new label:"),
lbajardsilogic@0 500 QLineEdit::Normal, "", &ok);
lbajardsilogic@0 501
lbajardsilogic@0 502 if (ok) {
lbajardsilogic@0 503 TextModel::RelabelCommand *command =
lbajardsilogic@0 504 new TextModel::RelabelCommand(m_model, m_editingPoint, label);
lbajardsilogic@0 505 m_editingCommand->addCommand(command);
lbajardsilogic@0 506 }
lbajardsilogic@0 507
lbajardsilogic@0 508 m_editingCommand->finish();
lbajardsilogic@0 509 m_editingCommand = 0;
lbajardsilogic@0 510 m_editing = false;
lbajardsilogic@0 511 }
lbajardsilogic@0 512
lbajardsilogic@0 513 void
lbajardsilogic@0 514 TextLayer::editStart(View *v, QMouseEvent *e)
lbajardsilogic@0 515 {
lbajardsilogic@0 516 // std::cerr << "TextLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 517
lbajardsilogic@0 518 if (!m_model) return;
lbajardsilogic@0 519
lbajardsilogic@0 520 TextModel::PointList points = getLocalPoints(v, e->x(), e->y());
lbajardsilogic@0 521 if (points.empty()) return;
lbajardsilogic@0 522
lbajardsilogic@0 523 m_editOrigin = e->pos();
lbajardsilogic@0 524 m_editingPoint = *points.begin();
lbajardsilogic@0 525 m_originalPoint = m_editingPoint;
lbajardsilogic@0 526
lbajardsilogic@0 527 if (m_editingCommand) {
lbajardsilogic@0 528 m_editingCommand->finish();
lbajardsilogic@0 529 m_editingCommand = 0;
lbajardsilogic@0 530 }
lbajardsilogic@0 531
lbajardsilogic@0 532 m_editing = true;
lbajardsilogic@0 533 }
lbajardsilogic@0 534
lbajardsilogic@0 535 void
lbajardsilogic@0 536 TextLayer::editDrag(View *v, QMouseEvent *e)
lbajardsilogic@0 537 {
lbajardsilogic@0 538 if (!m_model || !m_editing) return;
lbajardsilogic@0 539
lbajardsilogic@0 540 long frameDiff = v->getFrameForX(e->x()) - v->getFrameForX(m_editOrigin.x());
lbajardsilogic@0 541 float heightDiff = getHeightForY(v, e->y()) - getHeightForY(v, m_editOrigin.y());
lbajardsilogic@0 542
lbajardsilogic@0 543 long frame = m_originalPoint.frame + frameDiff;
lbajardsilogic@0 544 float height = m_originalPoint.height + heightDiff;
lbajardsilogic@0 545
lbajardsilogic@0 546 // long frame = v->getFrameForX(e->x());
lbajardsilogic@0 547 if (frame < 0) frame = 0;
lbajardsilogic@0 548 frame = (frame / m_model->getResolution()) * m_model->getResolution();
lbajardsilogic@0 549
lbajardsilogic@0 550 // float height = getHeightForY(v, e->y());
lbajardsilogic@0 551
lbajardsilogic@0 552 if (!m_editingCommand) {
lbajardsilogic@0 553 m_editingCommand = new TextModel::EditCommand(m_model, tr("Drag Label"));
lbajardsilogic@0 554 }
lbajardsilogic@0 555
lbajardsilogic@0 556 m_editingCommand->deletePoint(m_editingPoint);
lbajardsilogic@0 557 m_editingPoint.frame = frame;
lbajardsilogic@0 558 m_editingPoint.height = height;
lbajardsilogic@0 559 m_editingCommand->addPoint(m_editingPoint);
lbajardsilogic@0 560 }
lbajardsilogic@0 561
lbajardsilogic@0 562 void
lbajardsilogic@0 563 TextLayer::editEnd(View *, QMouseEvent *)
lbajardsilogic@0 564 {
lbajardsilogic@0 565 // std::cerr << "TextLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 566 if (!m_model || !m_editing) return;
lbajardsilogic@0 567
lbajardsilogic@0 568 if (m_editingCommand) {
lbajardsilogic@0 569
lbajardsilogic@0 570 QString newName = m_editingCommand->getName();
lbajardsilogic@0 571
lbajardsilogic@0 572 if (m_editingPoint.frame != m_originalPoint.frame) {
lbajardsilogic@0 573 if (m_editingPoint.height != m_originalPoint.height) {
lbajardsilogic@0 574 newName = tr("Move Label");
lbajardsilogic@0 575 } else {
lbajardsilogic@0 576 newName = tr("Move Label Horizontally");
lbajardsilogic@0 577 }
lbajardsilogic@0 578 } else {
lbajardsilogic@0 579 newName = tr("Move Label Vertically");
lbajardsilogic@0 580 }
lbajardsilogic@0 581
lbajardsilogic@0 582 m_editingCommand->setName(newName);
lbajardsilogic@0 583 m_editingCommand->finish();
lbajardsilogic@0 584 }
lbajardsilogic@0 585
lbajardsilogic@0 586 m_editingCommand = 0;
lbajardsilogic@0 587 m_editing = false;
lbajardsilogic@0 588 }
lbajardsilogic@0 589
lbajardsilogic@0 590 void
lbajardsilogic@0 591 TextLayer::editOpen(View *v, QMouseEvent *e)
lbajardsilogic@0 592 {
lbajardsilogic@0 593 std::cerr << "TextLayer::editOpen" << std::endl;
lbajardsilogic@0 594
lbajardsilogic@0 595 if (!m_model) return;
lbajardsilogic@0 596
lbajardsilogic@0 597 TextModel::PointList points = getLocalPoints(v, e->x(), e->y());
lbajardsilogic@0 598 if (points.empty()) return;
lbajardsilogic@0 599
lbajardsilogic@0 600 QString label = points.begin()->label;
lbajardsilogic@0 601
lbajardsilogic@0 602 bool ok = false;
lbajardsilogic@0 603 label = QInputDialog::getText(v, tr("Enter label"),
lbajardsilogic@0 604 tr("Please enter a new label:"),
lbajardsilogic@0 605 QLineEdit::Normal, label, &ok);
lbajardsilogic@0 606 if (ok && label != points.begin()->label) {
lbajardsilogic@0 607 TextModel::RelabelCommand *command =
lbajardsilogic@0 608 new TextModel::RelabelCommand(m_model, *points.begin(), label);
lbajardsilogic@0 609 CommandHistory::getInstance()->addCommand(command);
lbajardsilogic@0 610 }
lbajardsilogic@0 611 }
lbajardsilogic@0 612
lbajardsilogic@0 613 void
lbajardsilogic@0 614 TextLayer::moveSelection(Selection s, size_t newStartFrame)
lbajardsilogic@0 615 {
lbajardsilogic@0 616 if (!m_model) return;
lbajardsilogic@0 617
lbajardsilogic@0 618 TextModel::EditCommand *command =
lbajardsilogic@0 619 new TextModel::EditCommand(m_model, tr("Drag Selection"));
lbajardsilogic@0 620
lbajardsilogic@0 621 TextModel::PointList points =
lbajardsilogic@0 622 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 623
lbajardsilogic@0 624 for (TextModel::PointList::iterator i = points.begin();
lbajardsilogic@0 625 i != points.end(); ++i) {
lbajardsilogic@0 626
lbajardsilogic@0 627 if (s.contains(i->frame)) {
lbajardsilogic@0 628 TextModel::Point newPoint(*i);
lbajardsilogic@0 629 newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
lbajardsilogic@0 630 command->deletePoint(*i);
lbajardsilogic@0 631 command->addPoint(newPoint);
lbajardsilogic@0 632 }
lbajardsilogic@0 633 }
lbajardsilogic@0 634
lbajardsilogic@0 635 command->finish();
lbajardsilogic@0 636 }
lbajardsilogic@0 637
lbajardsilogic@0 638 void
lbajardsilogic@0 639 TextLayer::resizeSelection(Selection s, Selection newSize)
lbajardsilogic@0 640 {
lbajardsilogic@0 641 if (!m_model) return;
lbajardsilogic@0 642
lbajardsilogic@0 643 TextModel::EditCommand *command =
lbajardsilogic@0 644 new TextModel::EditCommand(m_model, tr("Resize Selection"));
lbajardsilogic@0 645
lbajardsilogic@0 646 TextModel::PointList points =
lbajardsilogic@0 647 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 648
lbajardsilogic@0 649 double ratio =
lbajardsilogic@0 650 double(newSize.getEndFrame() - newSize.getStartFrame()) /
lbajardsilogic@0 651 double(s.getEndFrame() - s.getStartFrame());
lbajardsilogic@0 652
lbajardsilogic@0 653 for (TextModel::PointList::iterator i = points.begin();
lbajardsilogic@0 654 i != points.end(); ++i) {
lbajardsilogic@0 655
lbajardsilogic@0 656 if (s.contains(i->frame)) {
lbajardsilogic@0 657
lbajardsilogic@0 658 double target = i->frame;
lbajardsilogic@0 659 target = newSize.getStartFrame() +
lbajardsilogic@0 660 double(target - s.getStartFrame()) * ratio;
lbajardsilogic@0 661
lbajardsilogic@0 662 TextModel::Point newPoint(*i);
lbajardsilogic@0 663 newPoint.frame = lrint(target);
lbajardsilogic@0 664 command->deletePoint(*i);
lbajardsilogic@0 665 command->addPoint(newPoint);
lbajardsilogic@0 666 }
lbajardsilogic@0 667 }
lbajardsilogic@0 668
lbajardsilogic@0 669 command->finish();
lbajardsilogic@0 670 }
lbajardsilogic@0 671
lbajardsilogic@0 672 void
lbajardsilogic@0 673 TextLayer::deleteSelection(Selection s)
lbajardsilogic@0 674 {
lbajardsilogic@0 675 if (!m_model) return;
lbajardsilogic@0 676
lbajardsilogic@0 677 TextModel::EditCommand *command =
lbajardsilogic@0 678 new TextModel::EditCommand(m_model, tr("Delete Selection"));
lbajardsilogic@0 679
lbajardsilogic@0 680 TextModel::PointList points =
lbajardsilogic@0 681 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 682
lbajardsilogic@0 683 for (TextModel::PointList::iterator i = points.begin();
lbajardsilogic@0 684 i != points.end(); ++i) {
lbajardsilogic@0 685 if (s.contains(i->frame)) command->deletePoint(*i);
lbajardsilogic@0 686 }
lbajardsilogic@0 687
lbajardsilogic@0 688 command->finish();
lbajardsilogic@0 689 }
lbajardsilogic@0 690
lbajardsilogic@0 691 void
lbajardsilogic@0 692 TextLayer::copy(Selection s, Clipboard &to)
lbajardsilogic@0 693 {
lbajardsilogic@0 694 if (!m_model) return;
lbajardsilogic@0 695
lbajardsilogic@0 696 TextModel::PointList points =
lbajardsilogic@0 697 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 698
lbajardsilogic@0 699 for (TextModel::PointList::iterator i = points.begin();
lbajardsilogic@0 700 i != points.end(); ++i) {
lbajardsilogic@0 701 if (s.contains(i->frame)) {
lbajardsilogic@0 702 Clipboard::Point point(i->frame, i->height, i->label);
lbajardsilogic@0 703 to.addPoint(point);
lbajardsilogic@0 704 }
lbajardsilogic@0 705 }
lbajardsilogic@0 706 }
lbajardsilogic@0 707
lbajardsilogic@0 708 bool
lbajardsilogic@0 709 TextLayer::paste(const Clipboard &from, int frameOffset, bool /* interactive */)
lbajardsilogic@0 710 {
lbajardsilogic@0 711 if (!m_model) return false;
lbajardsilogic@0 712
lbajardsilogic@0 713 const Clipboard::PointList &points = from.getPoints();
lbajardsilogic@0 714
lbajardsilogic@0 715 TextModel::EditCommand *command =
lbajardsilogic@0 716 new TextModel::EditCommand(m_model, tr("Paste"));
lbajardsilogic@0 717
lbajardsilogic@0 718 float valueMin = 0.0, valueMax = 1.0;
lbajardsilogic@0 719 for (Clipboard::PointList::const_iterator i = points.begin();
lbajardsilogic@0 720 i != points.end(); ++i) {
lbajardsilogic@0 721 if (i->haveValue()) {
lbajardsilogic@0 722 if (i->getValue() < valueMin) valueMin = i->getValue();
lbajardsilogic@0 723 if (i->getValue() > valueMax) valueMax = i->getValue();
lbajardsilogic@0 724 }
lbajardsilogic@0 725 }
lbajardsilogic@0 726 if (valueMax < valueMin + 1.0) valueMax = valueMin + 1.0;
lbajardsilogic@0 727
lbajardsilogic@0 728 for (Clipboard::PointList::const_iterator i = points.begin();
lbajardsilogic@0 729 i != points.end(); ++i) {
lbajardsilogic@0 730
lbajardsilogic@0 731 if (!i->haveFrame()) continue;
lbajardsilogic@0 732 size_t frame = 0;
lbajardsilogic@0 733 if (frameOffset > 0 || -frameOffset < i->getFrame()) {
lbajardsilogic@0 734 frame = i->getFrame() + frameOffset;
lbajardsilogic@0 735 }
lbajardsilogic@0 736 TextModel::Point newPoint(frame);
lbajardsilogic@0 737
lbajardsilogic@0 738 if (i->haveValue()) {
lbajardsilogic@0 739 newPoint.height = (i->getValue() - valueMin) / (valueMax - valueMin);
lbajardsilogic@0 740 } else {
lbajardsilogic@0 741 newPoint.height = 0.5;
lbajardsilogic@0 742 }
lbajardsilogic@0 743
lbajardsilogic@0 744 if (i->haveLabel()) {
lbajardsilogic@0 745 newPoint.label = i->getLabel();
lbajardsilogic@0 746 } else if (i->haveValue()) {
lbajardsilogic@0 747 newPoint.label = QString("%1").arg(i->getValue());
lbajardsilogic@0 748 } else {
lbajardsilogic@0 749 newPoint.label = tr("New Point");
lbajardsilogic@0 750 }
lbajardsilogic@0 751
lbajardsilogic@0 752 command->addPoint(newPoint);
lbajardsilogic@0 753 }
lbajardsilogic@0 754
lbajardsilogic@0 755 command->finish();
lbajardsilogic@0 756 return true;
lbajardsilogic@0 757 }
lbajardsilogic@0 758
lbajardsilogic@0 759 QString
lbajardsilogic@0 760 TextLayer::toXmlString(QString indent, QString extraAttributes) const
lbajardsilogic@0 761 {
lbajardsilogic@0 762 return Layer::toXmlString(indent, extraAttributes +
lbajardsilogic@0 763 QString(" colour=\"%1\"")
lbajardsilogic@0 764 .arg(encodeColour(m_colour)));
lbajardsilogic@0 765 }
lbajardsilogic@0 766
lbajardsilogic@18 767 QString
lbajardsilogic@18 768 TextLayer::toEasaierXmlString(QString indent, QString extraAttributes) const
lbajardsilogic@18 769 {
lbajardsilogic@18 770 return Layer::toEasaierXmlString(indent, extraAttributes +
lbajardsilogic@18 771 QString(" colour=\"%1\"")
lbajardsilogic@18 772 .arg(encodeColour(m_colour)));
lbajardsilogic@18 773 }
lbajardsilogic@18 774
lbajardsilogic@0 775 void
lbajardsilogic@0 776 TextLayer::setProperties(const QXmlAttributes &attributes)
lbajardsilogic@0 777 {
lbajardsilogic@0 778 QString colourSpec = attributes.value("colour");
lbajardsilogic@0 779 if (colourSpec != "") {
lbajardsilogic@0 780 QColor colour(colourSpec);
lbajardsilogic@0 781 if (colour.isValid()) {
lbajardsilogic@0 782 setBaseColour(QColor(colourSpec));
lbajardsilogic@0 783 }
lbajardsilogic@0 784 }
lbajardsilogic@0 785 }
lbajardsilogic@0 786