annotate layer/TextLayer.cpp @ 349:369a197737c7

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