annotate layer/TextLayer.cpp @ 101:0f36cdf407a6 sv1-v0.9rc1

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