annotate layer/TextLayer.cpp @ 317:e251c3599ea8

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