Mercurial > hg > svgui
comparison layer/TextLayer.cpp @ 1459:42c87368287c
Merge from branch single-point
author | Chris Cannam |
---|---|
date | Fri, 17 May 2019 10:02:52 +0100 |
parents | e2b6a13a1f69 |
children | 696e569ff21b |
comparison
equal
deleted
inserted
replaced
1441:8d5bf4ab98ef | 1459:42c87368287c |
---|---|
106 { | 106 { |
107 QPoint discard; | 107 QPoint discard; |
108 return !v->shouldIlluminateLocalFeatures(this, discard); | 108 return !v->shouldIlluminateLocalFeatures(this, discard); |
109 } | 109 } |
110 | 110 |
111 | 111 EventVector |
112 TextModel::PointList | |
113 TextLayer::getLocalPoints(LayerGeometryProvider *v, int x, int y) const | 112 TextLayer::getLocalPoints(LayerGeometryProvider *v, int x, int y) const |
114 { | 113 { |
115 if (!m_model) return TextModel::PointList(); | 114 if (!m_model) return {}; |
116 | 115 |
117 sv_frame_t frame0 = v->getFrameForX(-150); | 116 int overlap = ViewManager::scalePixelSize(150); |
118 sv_frame_t frame1 = v->getFrameForX(v->getPaintWidth() + 150); | 117 |
119 | 118 sv_frame_t frame0 = v->getFrameForX(-overlap); |
120 TextModel::PointList points(m_model->getPoints(frame0, frame1)); | 119 sv_frame_t frame1 = v->getFrameForX(v->getPaintWidth() + overlap); |
121 | 120 |
122 TextModel::PointList rv; | 121 EventVector points(m_model->getEventsSpanning(frame0, frame1 - frame0)); |
122 | |
123 EventVector rv; | |
123 QFontMetrics metrics = QFontMetrics(QFont()); | 124 QFontMetrics metrics = QFontMetrics(QFont()); |
124 | 125 |
125 for (TextModel::PointList::iterator i = points.begin(); | 126 for (EventVector::iterator i = points.begin(); i != points.end(); ++i) { |
126 i != points.end(); ++i) { | 127 |
127 | 128 Event p(*i); |
128 const TextModel::Point &p(*i); | 129 |
129 | 130 int px = v->getXForFrame(p.getFrame()); |
130 int px = v->getXForFrame(p.frame); | 131 int py = getYForHeight(v, p.getValue()); |
131 int py = getYForHeight(v, p.height); | 132 |
132 | 133 QString label = p.getLabel(); |
133 QString label = p.label; | |
134 if (label == "") { | 134 if (label == "") { |
135 label = tr("<no text>"); | 135 label = tr("<no text>"); |
136 } | 136 } |
137 | 137 |
138 QRect rect = metrics.boundingRect | 138 QRect rect = metrics.boundingRect |
144 else py = v->getPaintHeight() - rect.height() - 1; | 144 else py = v->getPaintHeight() - rect.height() - 1; |
145 } | 145 } |
146 | 146 |
147 if (x >= px && x < px + rect.width() && | 147 if (x >= px && x < px + rect.width() && |
148 y >= py && y < py + rect.height()) { | 148 y >= py && y < py + rect.height()) { |
149 rv.insert(p); | 149 rv.push_back(p); |
150 } | 150 } |
151 } | 151 } |
152 | 152 |
153 return rv; | 153 return rv; |
154 } | 154 } |
155 | 155 |
156 bool | 156 bool |
157 TextLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, TextModel::Point &p) const | 157 TextLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, Event &p) const |
158 { | 158 { |
159 if (!m_model) return false; | 159 if (!m_model) return false; |
160 | 160 |
161 sv_frame_t a = v->getFrameForX(x - 120); | 161 sv_frame_t a = v->getFrameForX(x - ViewManager::scalePixelSize(120)); |
162 sv_frame_t b = v->getFrameForX(x + 10); | 162 sv_frame_t b = v->getFrameForX(x + ViewManager::scalePixelSize(10)); |
163 TextModel::PointList onPoints = m_model->getPoints(a, b); | 163 EventVector onPoints = m_model->getEventsWithin(a, b); |
164 if (onPoints.empty()) return false; | 164 if (onPoints.empty()) return false; |
165 | 165 |
166 double nearestDistance = -1; | 166 double nearestDistance = -1; |
167 | 167 |
168 for (TextModel::PointList::const_iterator i = onPoints.begin(); | 168 for (EventVector::const_iterator i = onPoints.begin(); |
169 i != onPoints.end(); ++i) { | 169 i != onPoints.end(); ++i) { |
170 | 170 |
171 double yd = getYForHeight(v, (*i).height) - y; | 171 double yd = getYForHeight(v, i->getValue()) - y; |
172 double xd = v->getXForFrame((*i).frame) - x; | 172 double xd = v->getXForFrame(i->getFrame()) - x; |
173 double distance = sqrt(yd*yd + xd*xd); | 173 double distance = sqrt(yd*yd + xd*xd); |
174 | 174 |
175 if (nearestDistance == -1 || distance < nearestDistance) { | 175 if (nearestDistance == -1 || distance < nearestDistance) { |
176 nearestDistance = distance; | 176 nearestDistance = distance; |
177 p = *i; | 177 p = *i; |
186 { | 186 { |
187 int x = pos.x(); | 187 int x = pos.x(); |
188 | 188 |
189 if (!m_model || !m_model->getSampleRate()) return ""; | 189 if (!m_model || !m_model->getSampleRate()) return ""; |
190 | 190 |
191 TextModel::PointList points = getLocalPoints(v, x, pos.y()); | 191 EventVector points = getLocalPoints(v, x, pos.y()); |
192 | 192 |
193 if (points.empty()) { | 193 if (points.empty()) { |
194 if (!m_model->isReady()) { | 194 if (!m_model->isReady()) { |
195 return tr("In progress"); | 195 return tr("In progress"); |
196 } else { | 196 } else { |
197 return ""; | 197 return ""; |
198 } | 198 } |
199 } | 199 } |
200 | 200 |
201 sv_frame_t useFrame = points.begin()->frame; | 201 sv_frame_t useFrame = points.begin()->getFrame(); |
202 | 202 |
203 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate()); | 203 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate()); |
204 | 204 |
205 QString text; | 205 QString text; |
206 | 206 |
207 if (points.begin()->label == "") { | 207 if (points.begin()->getLabel() == "") { |
208 text = QString(tr("Time:\t%1\nHeight:\t%2\nLabel:\t%3")) | 208 text = QString(tr("Time:\t%1\nHeight:\t%2\nLabel:\t%3")) |
209 .arg(rt.toText(true).c_str()) | 209 .arg(rt.toText(true).c_str()) |
210 .arg(points.begin()->height) | 210 .arg(points.begin()->getValue()) |
211 .arg(points.begin()->label); | 211 .arg(points.begin()->getLabel()); |
212 } | 212 } |
213 | 213 |
214 pos = QPoint(v->getXForFrame(useFrame), | 214 pos = QPoint(v->getXForFrame(useFrame), |
215 getYForHeight(v, points.begin()->height)); | 215 getYForHeight(v, points.begin()->getValue())); |
216 return text; | 216 return text; |
217 } | 217 } |
218 | 218 |
219 | 219 |
220 //!!! too much overlap with TimeValueLayer/TimeInstantLayer | 220 //!!! too much overlap with TimeValueLayer/TimeInstantLayer |
226 { | 226 { |
227 if (!m_model) { | 227 if (!m_model) { |
228 return Layer::snapToFeatureFrame(v, frame, resolution, snap); | 228 return Layer::snapToFeatureFrame(v, frame, resolution, snap); |
229 } | 229 } |
230 | 230 |
231 // SnapLeft / SnapRight: return frame of nearest feature in that | |
232 // direction no matter how far away | |
233 // | |
234 // SnapNeighbouring: return frame of feature that would be used in | |
235 // an editing operation, i.e. closest feature in either direction | |
236 // but only if it is "close enough" | |
237 | |
231 resolution = m_model->getResolution(); | 238 resolution = m_model->getResolution(); |
232 TextModel::PointList points; | |
233 | 239 |
234 if (snap == SnapNeighbouring) { | 240 if (snap == SnapNeighbouring) { |
235 | 241 EventVector points = getLocalPoints(v, v->getXForFrame(frame), -1); |
236 points = getLocalPoints(v, v->getXForFrame(frame), -1); | |
237 if (points.empty()) return false; | 242 if (points.empty()) return false; |
238 frame = points.begin()->frame; | 243 frame = points.begin()->getFrame(); |
239 return true; | 244 return true; |
240 } | 245 } |
241 | 246 |
242 points = m_model->getPoints(frame, frame); | 247 Event e; |
243 sv_frame_t snapped = frame; | 248 if (m_model->getNearestEventMatching |
244 bool found = false; | 249 (frame, |
245 | 250 [](Event) { return true; }, |
246 for (TextModel::PointList::const_iterator i = points.begin(); | 251 snap == SnapLeft ? EventSeries::Backward : EventSeries::Forward, |
247 i != points.end(); ++i) { | 252 e)) { |
248 | 253 frame = e.getFrame(); |
249 if (snap == SnapRight) { | 254 return true; |
250 | 255 } |
251 if (i->frame > frame) { | 256 |
252 snapped = i->frame; | 257 return false; |
253 found = true; | |
254 break; | |
255 } | |
256 | |
257 } else if (snap == SnapLeft) { | |
258 | |
259 if (i->frame <= frame) { | |
260 snapped = i->frame; | |
261 found = true; // don't break, as the next may be better | |
262 } else { | |
263 break; | |
264 } | |
265 | |
266 } else { // nearest | |
267 | |
268 TextModel::PointList::const_iterator j = i; | |
269 ++j; | |
270 | |
271 if (j == points.end()) { | |
272 | |
273 snapped = i->frame; | |
274 found = true; | |
275 break; | |
276 | |
277 } else if (j->frame >= frame) { | |
278 | |
279 if (j->frame - frame < frame - i->frame) { | |
280 snapped = j->frame; | |
281 } else { | |
282 snapped = i->frame; | |
283 } | |
284 found = true; | |
285 break; | |
286 } | |
287 } | |
288 } | |
289 | |
290 frame = snapped; | |
291 return found; | |
292 } | 258 } |
293 | 259 |
294 int | 260 int |
295 TextLayer::getYForHeight(LayerGeometryProvider *v, double height) const | 261 TextLayer::getYForHeight(LayerGeometryProvider *v, double height) const |
296 { | 262 { |
314 if (!sampleRate) return; | 280 if (!sampleRate) return; |
315 | 281 |
316 // Profiler profiler("TextLayer::paint", true); | 282 // Profiler profiler("TextLayer::paint", true); |
317 | 283 |
318 int x0 = rect.left(), x1 = rect.right(); | 284 int x0 = rect.left(), x1 = rect.right(); |
319 sv_frame_t frame0 = v->getFrameForX(x0); | 285 int overlap = ViewManager::scalePixelSize(150); |
320 sv_frame_t frame1 = v->getFrameForX(x1); | 286 sv_frame_t frame0 = v->getFrameForX(x0 - overlap); |
321 | 287 sv_frame_t frame1 = v->getFrameForX(x1 + overlap); |
322 TextModel::PointList points(m_model->getPoints(frame0, frame1)); | 288 |
289 EventVector points(m_model->getEventsWithin(frame0, frame1 - frame0, 2)); | |
323 if (points.empty()) return; | 290 if (points.empty()) return; |
324 | 291 |
325 QColor brushColour(getBaseQColor()); | 292 QColor brushColour(getBaseQColor()); |
326 | 293 |
327 int h, s, val; | 294 int h, s, val; |
333 | 300 |
334 // SVDEBUG << "TextLayer::paint: resolution is " | 301 // SVDEBUG << "TextLayer::paint: resolution is " |
335 // << m_model->getResolution() << " frames" << endl; | 302 // << m_model->getResolution() << " frames" << endl; |
336 | 303 |
337 QPoint localPos; | 304 QPoint localPos; |
338 TextModel::Point illuminatePoint(0); | 305 Event illuminatePoint(0); |
339 bool shouldIlluminate = false; | 306 bool shouldIlluminate = false; |
340 | 307 |
341 if (v->shouldIlluminateLocalFeatures(this, localPos)) { | 308 if (v->shouldIlluminateLocalFeatures(this, localPos)) { |
342 shouldIlluminate = getPointToDrag(v, localPos.x(), localPos.y(), | 309 shouldIlluminate = getPointToDrag(v, localPos.x(), localPos.y(), |
343 illuminatePoint); | 310 illuminatePoint); |
347 int boxMaxHeight = 200; | 314 int boxMaxHeight = 200; |
348 | 315 |
349 paint.save(); | 316 paint.save(); |
350 paint.setClipRect(rect.x(), 0, rect.width() + boxMaxWidth, v->getPaintHeight()); | 317 paint.setClipRect(rect.x(), 0, rect.width() + boxMaxWidth, v->getPaintHeight()); |
351 | 318 |
352 for (TextModel::PointList::const_iterator i = points.begin(); | 319 for (EventVector::const_iterator i = points.begin(); |
353 i != points.end(); ++i) { | 320 i != points.end(); ++i) { |
354 | 321 |
355 const TextModel::Point &p(*i); | 322 Event p(*i); |
356 | 323 |
357 int x = v->getXForFrame(p.frame); | 324 int x = v->getXForFrame(p.getFrame()); |
358 int y = getYForHeight(v, p.height); | 325 int y = getYForHeight(v, p.getValue()); |
359 | 326 |
360 if (!shouldIlluminate || | 327 if (!shouldIlluminate || illuminatePoint != p) { |
361 // "illuminatePoint != p" | |
362 TextModel::Point::Comparator()(illuminatePoint, p) || | |
363 TextModel::Point::Comparator()(p, illuminatePoint)) { | |
364 paint.setPen(penColour); | 328 paint.setPen(penColour); |
365 paint.setBrush(brushColour); | 329 paint.setBrush(brushColour); |
366 } else { | 330 } else { |
367 paint.setBrush(penColour); | 331 paint.setBrush(penColour); |
368 paint.setPen(v->getBackground()); | 332 paint.setPen(v->getBackground()); |
369 } | 333 } |
370 | 334 |
371 QString label = p.label; | 335 QString label = p.getLabel(); |
372 if (label == "") { | 336 if (label == "") { |
373 label = tr("<no text>"); | 337 label = tr("<no text>"); |
374 } | 338 } |
375 | 339 |
376 QRect boxRect = paint.fontMetrics().boundingRect | 340 QRect boxRect = paint.fontMetrics().boundingRect |
397 paint.setRenderHint(QPainter::Antialiasing, true); | 361 paint.setRenderHint(QPainter::Antialiasing, true); |
398 paint.drawText(textRect, | 362 paint.drawText(textRect, |
399 Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, | 363 Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, |
400 label); | 364 label); |
401 | 365 |
402 /// if (p.label != "") { | 366 /// if (p.getLabel() != "") { |
403 /// paint.drawText(x + 5, y - paint.fontMetrics().height() + paint.fontMetrics().ascent(), p.label); | 367 /// paint.drawText(x + 5, y - paint.fontMetrics().height() + paint.fontMetrics().ascent(), p.getLabel()); |
404 /// } | 368 /// } |
405 } | 369 } |
406 | 370 |
407 paint.restore(); | 371 paint.restore(); |
408 | 372 |
424 if (frame < 0) frame = 0; | 388 if (frame < 0) frame = 0; |
425 frame = frame / m_model->getResolution() * m_model->getResolution(); | 389 frame = frame / m_model->getResolution() * m_model->getResolution(); |
426 | 390 |
427 double height = getHeightForY(v, e->y()); | 391 double height = getHeightForY(v, e->y()); |
428 | 392 |
429 m_editingPoint = TextModel::Point(frame, float(height), ""); | 393 m_editingPoint = Event(frame, float(height), ""); |
430 m_originalPoint = m_editingPoint; | 394 m_originalPoint = m_editingPoint; |
431 | 395 |
432 if (m_editingCommand) finish(m_editingCommand); | 396 if (m_editingCommand) finish(m_editingCommand); |
433 m_editingCommand = new TextModel::EditCommand(m_model, "Add Label"); | 397 m_editingCommand = new ChangeEventsCommand(m_model, "Add Label"); |
434 m_editingCommand->addPoint(m_editingPoint); | 398 m_editingCommand->add(m_editingPoint); |
435 | 399 |
436 m_editing = true; | 400 m_editing = true; |
437 } | 401 } |
438 | 402 |
439 void | 403 void |
447 if (frame < 0) frame = 0; | 411 if (frame < 0) frame = 0; |
448 frame = frame / m_model->getResolution() * m_model->getResolution(); | 412 frame = frame / m_model->getResolution() * m_model->getResolution(); |
449 | 413 |
450 double height = getHeightForY(v, e->y()); | 414 double height = getHeightForY(v, e->y()); |
451 | 415 |
452 m_editingCommand->deletePoint(m_editingPoint); | 416 m_editingCommand->remove(m_editingPoint); |
453 m_editingPoint.frame = frame; | 417 m_editingPoint = m_editingPoint |
454 m_editingPoint.height = float(height); | 418 .withFrame(frame) |
455 m_editingCommand->addPoint(m_editingPoint); | 419 .withValue(float(height)); |
420 m_editingCommand->add(m_editingPoint); | |
456 } | 421 } |
457 | 422 |
458 void | 423 void |
459 TextLayer::drawEnd(LayerGeometryProvider *v, QMouseEvent *) | 424 TextLayer::drawEnd(LayerGeometryProvider *v, QMouseEvent *) |
460 { | 425 { |
464 bool ok = false; | 429 bool ok = false; |
465 QString label = QInputDialog::getText(v->getView(), tr("Enter label"), | 430 QString label = QInputDialog::getText(v->getView(), tr("Enter label"), |
466 tr("Please enter a new label:"), | 431 tr("Please enter a new label:"), |
467 QLineEdit::Normal, "", &ok); | 432 QLineEdit::Normal, "", &ok); |
468 | 433 |
434 m_editingCommand->remove(m_editingPoint); | |
435 | |
469 if (ok) { | 436 if (ok) { |
470 TextModel::RelabelCommand *command = | 437 m_editingPoint = m_editingPoint |
471 new TextModel::RelabelCommand(m_model, m_editingPoint, label); | 438 .withLabel(label); |
472 m_editingCommand->addCommand(command); | 439 m_editingCommand->add(m_editingPoint); |
473 } else { | |
474 m_editingCommand->deletePoint(m_editingPoint); | |
475 } | 440 } |
476 | 441 |
477 finish(m_editingCommand); | 442 finish(m_editingCommand); |
478 m_editingCommand = nullptr; | 443 m_editingCommand = nullptr; |
479 m_editing = false; | 444 m_editing = false; |
504 { | 469 { |
505 if (!m_model || !m_editing) return; | 470 if (!m_model || !m_editing) return; |
506 | 471 |
507 m_editing = false; | 472 m_editing = false; |
508 | 473 |
509 TextModel::Point p(0); | 474 Event p; |
510 if (!getPointToDrag(v, e->x(), e->y(), p)) return; | 475 if (!getPointToDrag(v, e->x(), e->y(), p)) return; |
511 if (p.frame != m_editingPoint.frame || p.height != m_editingPoint.height) return; | 476 if (p.getFrame() != m_editingPoint.getFrame() || |
512 | 477 p.getValue() != m_editingPoint.getValue()) return; |
513 m_editingCommand = new TextModel::EditCommand | 478 |
514 (m_model, tr("Erase Point")); | 479 m_editingCommand = new ChangeEventsCommand(m_model, tr("Erase Point")); |
515 | 480 m_editingCommand->remove(m_editingPoint); |
516 m_editingCommand->deletePoint(m_editingPoint); | |
517 | |
518 finish(m_editingCommand); | 481 finish(m_editingCommand); |
519 m_editingCommand = nullptr; | 482 m_editingCommand = nullptr; |
520 m_editing = false; | 483 m_editing = false; |
521 } | 484 } |
522 | 485 |
545 void | 508 void |
546 TextLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e) | 509 TextLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e) |
547 { | 510 { |
548 if (!m_model || !m_editing) return; | 511 if (!m_model || !m_editing) return; |
549 | 512 |
550 sv_frame_t frameDiff = v->getFrameForX(e->x()) - v->getFrameForX(m_editOrigin.x()); | 513 sv_frame_t frameDiff = |
551 double heightDiff = getHeightForY(v, e->y()) - getHeightForY(v, m_editOrigin.y()); | 514 v->getFrameForX(e->x()) - v->getFrameForX(m_editOrigin.x()); |
552 | 515 double heightDiff = |
553 sv_frame_t frame = m_originalPoint.frame + frameDiff; | 516 getHeightForY(v, e->y()) - getHeightForY(v, m_editOrigin.y()); |
554 double height = m_originalPoint.height + heightDiff; | 517 |
555 | 518 sv_frame_t frame = m_originalPoint.getFrame() + frameDiff; |
556 // sv_frame_t frame = v->getFrameForX(e->x()); | 519 double height = m_originalPoint.getValue() + heightDiff; |
520 | |
557 if (frame < 0) frame = 0; | 521 if (frame < 0) frame = 0; |
558 frame = (frame / m_model->getResolution()) * m_model->getResolution(); | 522 frame = (frame / m_model->getResolution()) * m_model->getResolution(); |
559 | 523 |
560 // double height = getHeightForY(v, e->y()); | |
561 | |
562 if (!m_editingCommand) { | 524 if (!m_editingCommand) { |
563 m_editingCommand = new TextModel::EditCommand(m_model, tr("Drag Label")); | 525 m_editingCommand = new ChangeEventsCommand(m_model, tr("Drag Label")); |
564 } | 526 } |
565 | 527 |
566 m_editingCommand->deletePoint(m_editingPoint); | 528 m_editingCommand->remove(m_editingPoint); |
567 m_editingPoint.frame = frame; | 529 m_editingPoint = m_editingPoint |
568 m_editingPoint.height = float(height); | 530 .withFrame(frame) |
569 m_editingCommand->addPoint(m_editingPoint); | 531 .withValue(float(height)); |
532 m_editingCommand->add(m_editingPoint); | |
570 } | 533 } |
571 | 534 |
572 void | 535 void |
573 TextLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) | 536 TextLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) |
574 { | 537 { |
577 | 540 |
578 if (m_editingCommand) { | 541 if (m_editingCommand) { |
579 | 542 |
580 QString newName = m_editingCommand->getName(); | 543 QString newName = m_editingCommand->getName(); |
581 | 544 |
582 if (m_editingPoint.frame != m_originalPoint.frame) { | 545 if (m_editingPoint.getFrame() != m_originalPoint.getFrame()) { |
583 if (m_editingPoint.height != m_originalPoint.height) { | 546 if (m_editingPoint.getValue() != m_originalPoint.getValue()) { |
584 newName = tr("Move Label"); | 547 newName = tr("Move Label"); |
585 } else { | 548 } else { |
586 newName = tr("Move Label Horizontally"); | 549 newName = tr("Move Label Horizontally"); |
587 } | 550 } |
588 } else { | 551 } else { |
600 bool | 563 bool |
601 TextLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) | 564 TextLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) |
602 { | 565 { |
603 if (!m_model) return false; | 566 if (!m_model) return false; |
604 | 567 |
605 TextModel::Point text(0); | 568 Event text; |
606 if (!getPointToDrag(v, e->x(), e->y(), text)) return false; | 569 if (!getPointToDrag(v, e->x(), e->y(), text)) return false; |
607 | 570 |
608 QString label = text.label; | 571 QString label = text.getLabel(); |
609 | 572 |
610 bool ok = false; | 573 bool ok = false; |
611 label = QInputDialog::getText(v->getView(), tr("Enter label"), | 574 label = QInputDialog::getText(v->getView(), tr("Enter label"), |
612 tr("Please enter a new label:"), | 575 tr("Please enter a new label:"), |
613 QLineEdit::Normal, label, &ok); | 576 QLineEdit::Normal, label, &ok); |
614 if (ok && label != text.label) { | 577 if (ok && label != text.getLabel()) { |
615 TextModel::RelabelCommand *command = | 578 ChangeEventsCommand *command = |
616 new TextModel::RelabelCommand(m_model, text, label); | 579 new ChangeEventsCommand(m_model, tr("Re-Label Point")); |
617 CommandHistory::getInstance()->addCommand(command); | 580 command->remove(text); |
581 command->add(text.withLabel(label)); | |
582 finish(command); | |
618 } | 583 } |
619 | 584 |
620 return true; | 585 return true; |
621 } | 586 } |
622 | 587 |
623 void | 588 void |
624 TextLayer::moveSelection(Selection s, sv_frame_t newStartFrame) | 589 TextLayer::moveSelection(Selection s, sv_frame_t newStartFrame) |
625 { | 590 { |
626 if (!m_model) return; | 591 if (!m_model) return; |
627 | 592 |
628 TextModel::EditCommand *command = | 593 ChangeEventsCommand *command = |
629 new TextModel::EditCommand(m_model, tr("Drag Selection")); | 594 new ChangeEventsCommand(m_model, tr("Drag Selection")); |
630 | 595 |
631 TextModel::PointList points = | 596 EventVector points = |
632 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | 597 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); |
633 | 598 |
634 for (TextModel::PointList::iterator i = points.begin(); | 599 for (Event p: points) { |
635 i != points.end(); ++i) { | 600 command->remove(p); |
636 | 601 Event moved = p.withFrame(p.getFrame() + |
637 if (s.contains(i->frame)) { | 602 newStartFrame - s.getStartFrame()); |
638 TextModel::Point newPoint(*i); | 603 command->add(moved); |
639 newPoint.frame = i->frame + newStartFrame - s.getStartFrame(); | |
640 command->deletePoint(*i); | |
641 command->addPoint(newPoint); | |
642 } | |
643 } | 604 } |
644 | 605 |
645 finish(command); | 606 finish(command); |
646 } | 607 } |
647 | 608 |
648 void | 609 void |
649 TextLayer::resizeSelection(Selection s, Selection newSize) | 610 TextLayer::resizeSelection(Selection s, Selection newSize) |
650 { | 611 { |
651 if (!m_model) return; | 612 if (!m_model) return; |
652 | 613 |
653 TextModel::EditCommand *command = | 614 ChangeEventsCommand *command = |
654 new TextModel::EditCommand(m_model, tr("Resize Selection")); | 615 new ChangeEventsCommand(m_model, tr("Resize Selection")); |
655 | 616 |
656 TextModel::PointList points = | 617 EventVector points = |
657 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | 618 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); |
658 | 619 |
659 double ratio = | 620 double ratio = double(newSize.getDuration()) / double(s.getDuration()); |
660 double(newSize.getEndFrame() - newSize.getStartFrame()) / | 621 double oldStart = double(s.getStartFrame()); |
661 double(s.getEndFrame() - s.getStartFrame()); | 622 double newStart = double(newSize.getStartFrame()); |
662 | 623 |
663 for (TextModel::PointList::iterator i = points.begin(); | 624 for (Event p: points) { |
664 i != points.end(); ++i) { | 625 |
665 | 626 double newFrame = (double(p.getFrame()) - oldStart) * ratio + newStart; |
666 if (s.contains(i->frame)) { | 627 |
667 | 628 Event newPoint = p |
668 double target = double(i->frame); | 629 .withFrame(lrint(newFrame)); |
669 target = double(newSize.getStartFrame()) + | 630 command->remove(p); |
670 target - double(s.getStartFrame()) * ratio; | 631 command->add(newPoint); |
671 | |
672 TextModel::Point newPoint(*i); | |
673 newPoint.frame = lrint(target); | |
674 command->deletePoint(*i); | |
675 command->addPoint(newPoint); | |
676 } | |
677 } | 632 } |
678 | 633 |
679 finish(command); | 634 finish(command); |
680 } | 635 } |
681 | 636 |
682 void | 637 void |
683 TextLayer::deleteSelection(Selection s) | 638 TextLayer::deleteSelection(Selection s) |
684 { | 639 { |
685 if (!m_model) return; | 640 if (!m_model) return; |
686 | 641 |
687 TextModel::EditCommand *command = | 642 ChangeEventsCommand *command = |
688 new TextModel::EditCommand(m_model, tr("Delete Selection")); | 643 new ChangeEventsCommand(m_model, tr("Delete Selection")); |
689 | 644 |
690 TextModel::PointList points = | 645 EventVector points = |
691 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | 646 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); |
692 | 647 |
693 for (TextModel::PointList::iterator i = points.begin(); | 648 for (Event p: points) { |
694 i != points.end(); ++i) { | 649 command->remove(p); |
695 if (s.contains(i->frame)) command->deletePoint(*i); | |
696 } | 650 } |
697 | 651 |
698 finish(command); | 652 finish(command); |
699 } | 653 } |
700 | 654 |
701 void | 655 void |
702 TextLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) | 656 TextLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) |
703 { | 657 { |
704 if (!m_model) return; | 658 if (!m_model) return; |
705 | 659 |
706 TextModel::PointList points = | 660 EventVector points = |
707 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | 661 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); |
708 | 662 |
709 for (TextModel::PointList::iterator i = points.begin(); | 663 for (Event p: points) { |
710 i != points.end(); ++i) { | 664 to.addPoint(p.withReferenceFrame(alignToReference(v, p.getFrame()))); |
711 if (s.contains(i->frame)) { | |
712 Clipboard::Point point(i->frame, i->height, i->label); | |
713 point.setReferenceFrame(alignToReference(v, i->frame)); | |
714 to.addPoint(point); | |
715 } | |
716 } | 665 } |
717 } | 666 } |
718 | 667 |
719 bool | 668 bool |
720 TextLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */) | 669 TextLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */) |
721 { | 670 { |
722 if (!m_model) return false; | 671 if (!m_model) return false; |
723 | 672 |
724 const Clipboard::PointList &points = from.getPoints(); | 673 const EventVector &points = from.getPoints(); |
725 | 674 |
726 bool realign = false; | 675 bool realign = false; |
727 | 676 |
728 if (clipboardHasDifferentAlignment(v, from)) { | 677 if (clipboardHasDifferentAlignment(v, from)) { |
729 | 678 |
740 if (button == QMessageBox::Yes) { | 689 if (button == QMessageBox::Yes) { |
741 realign = true; | 690 realign = true; |
742 } | 691 } |
743 } | 692 } |
744 | 693 |
745 TextModel::EditCommand *command = | 694 ChangeEventsCommand *command = |
746 new TextModel::EditCommand(m_model, tr("Paste")); | 695 new ChangeEventsCommand(m_model, tr("Paste")); |
747 | 696 |
748 double valueMin = 0.0, valueMax = 1.0; | 697 double valueMin = 0.0, valueMax = 1.0; |
749 for (Clipboard::PointList::const_iterator i = points.begin(); | 698 for (EventVector::const_iterator i = points.begin(); |
750 i != points.end(); ++i) { | 699 i != points.end(); ++i) { |
751 if (i->haveValue()) { | 700 if (i->hasValue()) { |
752 if (i->getValue() < valueMin) valueMin = i->getValue(); | 701 if (i->getValue() < valueMin) valueMin = i->getValue(); |
753 if (i->getValue() > valueMax) valueMax = i->getValue(); | 702 if (i->getValue() > valueMax) valueMax = i->getValue(); |
754 } | 703 } |
755 } | 704 } |
756 if (valueMax < valueMin + 1.0) valueMax = valueMin + 1.0; | 705 if (valueMax < valueMin + 1.0) valueMax = valueMin + 1.0; |
757 | 706 |
758 for (Clipboard::PointList::const_iterator i = points.begin(); | 707 for (EventVector::const_iterator i = points.begin(); |
759 i != points.end(); ++i) { | 708 i != points.end(); ++i) { |
760 | 709 |
761 if (!i->haveFrame()) continue; | |
762 sv_frame_t frame = 0; | 710 sv_frame_t frame = 0; |
763 | 711 |
764 if (!realign) { | 712 if (!realign) { |
765 | 713 |
766 frame = i->getFrame(); | 714 frame = i->getFrame(); |
767 | 715 |
768 } else { | 716 } else { |
769 | 717 |
770 if (i->haveReferenceFrame()) { | 718 if (i->hasReferenceFrame()) { |
771 frame = i->getReferenceFrame(); | 719 frame = i->getReferenceFrame(); |
772 frame = alignFromReference(v, frame); | 720 frame = alignFromReference(v, frame); |
773 } else { | 721 } else { |
774 frame = i->getFrame(); | 722 frame = i->getFrame(); |
775 } | 723 } |
776 } | 724 } |
777 | 725 |
778 TextModel::Point newPoint(frame); | 726 Event p = *i; |
779 | 727 Event newPoint = p; |
780 if (i->haveValue()) { | 728 if (p.hasValue()) { |
781 newPoint.height = float((i->getValue() - valueMin) / (valueMax - valueMin)); | 729 newPoint = newPoint.withValue(float((i->getValue() - valueMin) / |
730 (valueMax - valueMin))); | |
782 } else { | 731 } else { |
783 newPoint.height = 0.5f; | 732 newPoint = newPoint.withValue(0.5f); |
784 } | 733 } |
785 | 734 |
786 if (i->haveLabel()) { | 735 if (!p.hasLabel()) { |
787 newPoint.label = i->getLabel(); | 736 if (p.hasValue()) { |
788 } else if (i->haveValue()) { | 737 newPoint = newPoint.withLabel(QString("%1").arg(p.getValue())); |
789 newPoint.label = QString("%1").arg(i->getValue()); | 738 } else { |
790 } else { | 739 newPoint = newPoint.withLabel(tr("New Point")); |
791 newPoint.label = tr("New Point"); | 740 } |
792 } | 741 } |
793 | 742 |
794 command->addPoint(newPoint); | 743 command->add(newPoint); |
795 } | 744 } |
796 | 745 |
797 finish(command); | 746 finish(command); |
798 return true; | 747 return true; |
799 } | 748 } |