annotate layer/TextLayer.cpp @ 77:fd348f36c0d3

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