annotate layer/TextLayer.cpp @ 299:5c59c433b358

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