annotate layer/TextLayer.cpp @ 312:6de6f78b13a1

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