annotate layer/TextLayer.cpp @ 333:e74b56f07c73

* Some work on correct alignment when moving panes during playback * Overhaul alignment for playback frame values (view manager now always refers to reference-timeline values, only the play source deals in playback model timeline values) * When making a selection, ensure the selection regions shown in other panes (and used for playback constraints if appropriate) are aligned correctly. This may be the coolest feature ever implemented in any program ever.
author Chris Cannam
date Thu, 22 Nov 2007 14:17:19 +0000
parents 984c1975f1ff
children 2f83b6e3b8ca 64e84e5efb76
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@44 451 TextLayer::editStart(View *v, QMouseEvent *e)
Chris@35 452 {
Chris@36 453 // std::cerr << "TextLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@35 454
Chris@35 455 if (!m_model) return;
Chris@35 456
Chris@44 457 TextModel::PointList points = getLocalPoints(v, e->x(), e->y());
Chris@35 458 if (points.empty()) return;
Chris@35 459
Chris@36 460 m_editOrigin = e->pos();
Chris@35 461 m_editingPoint = *points.begin();
Chris@35 462 m_originalPoint = m_editingPoint;
Chris@35 463
Chris@35 464 if (m_editingCommand) {
Chris@35 465 m_editingCommand->finish();
Chris@35 466 m_editingCommand = 0;
Chris@35 467 }
Chris@35 468
Chris@35 469 m_editing = true;
Chris@35 470 }
Chris@35 471
Chris@35 472 void
Chris@44 473 TextLayer::editDrag(View *v, QMouseEvent *e)
Chris@35 474 {
Chris@35 475 if (!m_model || !m_editing) return;
Chris@35 476
Chris@44 477 long frameDiff = v->getFrameForX(e->x()) - v->getFrameForX(m_editOrigin.x());
Chris@44 478 float heightDiff = getHeightForY(v, e->y()) - getHeightForY(v, m_editOrigin.y());
Chris@36 479
Chris@36 480 long frame = m_originalPoint.frame + frameDiff;
Chris@36 481 float height = m_originalPoint.height + heightDiff;
Chris@36 482
Chris@44 483 // long frame = v->getFrameForX(e->x());
Chris@35 484 if (frame < 0) frame = 0;
Chris@36 485 frame = (frame / m_model->getResolution()) * m_model->getResolution();
Chris@35 486
Chris@44 487 // float height = getHeightForY(v, e->y());
Chris@35 488
Chris@35 489 if (!m_editingCommand) {
Chris@35 490 m_editingCommand = new TextModel::EditCommand(m_model, tr("Drag Label"));
Chris@35 491 }
Chris@35 492
Chris@35 493 m_editingCommand->deletePoint(m_editingPoint);
Chris@35 494 m_editingPoint.frame = frame;
Chris@35 495 m_editingPoint.height = height;
Chris@35 496 m_editingCommand->addPoint(m_editingPoint);
Chris@35 497 }
Chris@35 498
Chris@35 499 void
Chris@248 500 TextLayer::editEnd(View *, QMouseEvent *)
Chris@35 501 {
Chris@36 502 // std::cerr << "TextLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@35 503 if (!m_model || !m_editing) return;
Chris@35 504
Chris@35 505 if (m_editingCommand) {
Chris@35 506
Chris@35 507 QString newName = m_editingCommand->getName();
Chris@35 508
Chris@35 509 if (m_editingPoint.frame != m_originalPoint.frame) {
Chris@35 510 if (m_editingPoint.height != m_originalPoint.height) {
Chris@35 511 newName = tr("Move Label");
Chris@35 512 } else {
Chris@36 513 newName = tr("Move Label Horizontally");
Chris@35 514 }
Chris@35 515 } else {
Chris@36 516 newName = tr("Move Label Vertically");
Chris@35 517 }
Chris@35 518
Chris@35 519 m_editingCommand->setName(newName);
Chris@35 520 m_editingCommand->finish();
Chris@35 521 }
Chris@35 522
Chris@35 523 m_editingCommand = 0;
Chris@35 524 m_editing = false;
Chris@35 525 }
Chris@35 526
Chris@255 527 bool
Chris@44 528 TextLayer::editOpen(View *v, QMouseEvent *e)
Chris@36 529 {
Chris@255 530 if (!m_model) return false;
Chris@36 531
Chris@44 532 TextModel::PointList points = getLocalPoints(v, e->x(), e->y());
Chris@255 533 if (points.empty()) return false;
Chris@36 534
Chris@36 535 QString label = points.begin()->label;
Chris@36 536
Chris@36 537 bool ok = false;
Chris@44 538 label = QInputDialog::getText(v, tr("Enter label"),
Chris@36 539 tr("Please enter a new label:"),
Chris@36 540 QLineEdit::Normal, label, &ok);
Chris@36 541 if (ok && label != points.begin()->label) {
Chris@36 542 TextModel::RelabelCommand *command =
Chris@36 543 new TextModel::RelabelCommand(m_model, *points.begin(), label);
Chris@99 544 CommandHistory::getInstance()->addCommand(command);
Chris@36 545 }
Chris@255 546
Chris@255 547 return true;
Chris@36 548 }
Chris@36 549
Chris@43 550 void
Chris@43 551 TextLayer::moveSelection(Selection s, size_t newStartFrame)
Chris@43 552 {
Chris@99 553 if (!m_model) return;
Chris@99 554
Chris@43 555 TextModel::EditCommand *command =
Chris@43 556 new TextModel::EditCommand(m_model, tr("Drag Selection"));
Chris@43 557
Chris@43 558 TextModel::PointList points =
Chris@43 559 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@43 560
Chris@43 561 for (TextModel::PointList::iterator i = points.begin();
Chris@43 562 i != points.end(); ++i) {
Chris@43 563
Chris@43 564 if (s.contains(i->frame)) {
Chris@43 565 TextModel::Point newPoint(*i);
Chris@43 566 newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
Chris@43 567 command->deletePoint(*i);
Chris@43 568 command->addPoint(newPoint);
Chris@43 569 }
Chris@43 570 }
Chris@43 571
Chris@43 572 command->finish();
Chris@43 573 }
Chris@43 574
Chris@43 575 void
Chris@43 576 TextLayer::resizeSelection(Selection s, Selection newSize)
Chris@43 577 {
Chris@99 578 if (!m_model) return;
Chris@99 579
Chris@43 580 TextModel::EditCommand *command =
Chris@43 581 new TextModel::EditCommand(m_model, tr("Resize Selection"));
Chris@43 582
Chris@43 583 TextModel::PointList points =
Chris@43 584 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@43 585
Chris@43 586 double ratio =
Chris@43 587 double(newSize.getEndFrame() - newSize.getStartFrame()) /
Chris@43 588 double(s.getEndFrame() - s.getStartFrame());
Chris@43 589
Chris@43 590 for (TextModel::PointList::iterator i = points.begin();
Chris@43 591 i != points.end(); ++i) {
Chris@43 592
Chris@43 593 if (s.contains(i->frame)) {
Chris@43 594
Chris@43 595 double target = i->frame;
Chris@43 596 target = newSize.getStartFrame() +
Chris@43 597 double(target - s.getStartFrame()) * ratio;
Chris@43 598
Chris@43 599 TextModel::Point newPoint(*i);
Chris@43 600 newPoint.frame = lrint(target);
Chris@43 601 command->deletePoint(*i);
Chris@43 602 command->addPoint(newPoint);
Chris@43 603 }
Chris@43 604 }
Chris@43 605
Chris@43 606 command->finish();
Chris@43 607 }
Chris@43 608
Chris@76 609 void
Chris@76 610 TextLayer::deleteSelection(Selection s)
Chris@76 611 {
Chris@99 612 if (!m_model) return;
Chris@99 613
Chris@76 614 TextModel::EditCommand *command =
Chris@76 615 new TextModel::EditCommand(m_model, tr("Delete Selection"));
Chris@76 616
Chris@76 617 TextModel::PointList points =
Chris@76 618 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@76 619
Chris@76 620 for (TextModel::PointList::iterator i = points.begin();
Chris@76 621 i != points.end(); ++i) {
Chris@76 622 if (s.contains(i->frame)) command->deletePoint(*i);
Chris@76 623 }
Chris@76 624
Chris@76 625 command->finish();
Chris@76 626 }
Chris@76 627
Chris@76 628 void
Chris@76 629 TextLayer::copy(Selection s, Clipboard &to)
Chris@76 630 {
Chris@99 631 if (!m_model) return;
Chris@99 632
Chris@76 633 TextModel::PointList points =
Chris@76 634 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@76 635
Chris@76 636 for (TextModel::PointList::iterator i = points.begin();
Chris@76 637 i != points.end(); ++i) {
Chris@76 638 if (s.contains(i->frame)) {
Chris@76 639 Clipboard::Point point(i->frame, i->height, i->label);
Chris@76 640 to.addPoint(point);
Chris@76 641 }
Chris@76 642 }
Chris@76 643 }
Chris@76 644
Chris@125 645 bool
Chris@248 646 TextLayer::paste(const Clipboard &from, int frameOffset, bool /* interactive */)
Chris@76 647 {
Chris@125 648 if (!m_model) return false;
Chris@99 649
Chris@76 650 const Clipboard::PointList &points = from.getPoints();
Chris@76 651
Chris@76 652 TextModel::EditCommand *command =
Chris@76 653 new TextModel::EditCommand(m_model, tr("Paste"));
Chris@76 654
Chris@125 655 float valueMin = 0.0, valueMax = 1.0;
Chris@125 656 for (Clipboard::PointList::const_iterator i = points.begin();
Chris@125 657 i != points.end(); ++i) {
Chris@125 658 if (i->haveValue()) {
Chris@125 659 if (i->getValue() < valueMin) valueMin = i->getValue();
Chris@125 660 if (i->getValue() > valueMax) valueMax = i->getValue();
Chris@125 661 }
Chris@125 662 }
Chris@125 663 if (valueMax < valueMin + 1.0) valueMax = valueMin + 1.0;
Chris@125 664
Chris@76 665 for (Clipboard::PointList::const_iterator i = points.begin();
Chris@76 666 i != points.end(); ++i) {
Chris@76 667
Chris@76 668 if (!i->haveFrame()) continue;
Chris@76 669 size_t frame = 0;
Chris@76 670 if (frameOffset > 0 || -frameOffset < i->getFrame()) {
Chris@76 671 frame = i->getFrame() + frameOffset;
Chris@76 672 }
Chris@76 673 TextModel::Point newPoint(frame);
Chris@125 674
Chris@125 675 if (i->haveValue()) {
Chris@125 676 newPoint.height = (i->getValue() - valueMin) / (valueMax - valueMin);
Chris@125 677 } else {
Chris@125 678 newPoint.height = 0.5;
Chris@125 679 }
Chris@125 680
Chris@125 681 if (i->haveLabel()) {
Chris@125 682 newPoint.label = i->getLabel();
Chris@125 683 } else if (i->haveValue()) {
Chris@125 684 newPoint.label = QString("%1").arg(i->getValue());
Chris@125 685 } else {
Chris@125 686 newPoint.label = tr("New Point");
Chris@125 687 }
Chris@76 688
Chris@76 689 command->addPoint(newPoint);
Chris@76 690 }
Chris@76 691
Chris@76 692 command->finish();
Chris@125 693 return true;
Chris@76 694 }
Chris@76 695
Chris@287 696 int
Chris@287 697 TextLayer::getDefaultColourHint(bool darkbg, bool &impose)
Chris@287 698 {
Chris@287 699 impose = false;
Chris@287 700 return ColourDatabase::getInstance()->getColourIndex
Chris@287 701 (QString(darkbg ? "Bright Orange" : "Orange"));
Chris@287 702 }
Chris@287 703
Chris@316 704 void
Chris@316 705 TextLayer::toXml(QTextStream &stream,
Chris@316 706 QString indent, QString extraAttributes) const
Chris@35 707 {
Chris@316 708 SingleColourLayer::toXml(stream, indent, extraAttributes);
Chris@35 709 }
Chris@35 710
Chris@35 711 void
Chris@35 712 TextLayer::setProperties(const QXmlAttributes &attributes)
Chris@35 713 {
Chris@287 714 SingleColourLayer::setProperties(attributes);
Chris@35 715 }
Chris@35 716